1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * NetBIOS session service functions
  28  */
  29 
  30 #include <errno.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <libintl.h>
  36 #include <xti.h>
  37 #include <assert.h>
  38 
  39 #include <sys/types.h>
  40 #include <sys/socket.h>
  41 #include <sys/poll.h>
  42 
  43 #include <netsmb/netbios.h>
  44 #include <netsmb/smb_lib.h>
  45 #include <netsmb/nb_lib.h>
  46 #include <netsmb/mchain.h>
  47 
  48 #include "private.h"
  49 #include "charsets.h"
  50 
  51 static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
  52 static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
  53 static int nb_ssn_pollin(struct smb_ctx *, int);
  54 
  55 /*
  56  * Send a data message.
  57  */
  58 int
  59 smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
  60 {
  61         return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
  62 }
  63 
  64 /*
  65  * Send a NetBIOS message, after
  66  * prepending the 4-byte header.
  67  */
  68 static int
  69 nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
  70             int mtype, int mlen)
  71 {
  72         mbuf_t *m;
  73         uint32_t hdr, hdrbuf;
  74         int err;
  75 
  76         m = mbp->mb_top;
  77         if (m == NULL)
  78                 return (EINVAL);
  79 
  80         /*
  81          * Prepend the NetBIOS header.
  82          * Our mbufs leave space for this.
  83          */
  84         hdr = (mtype << 24) | mlen;
  85         hdrbuf = htonl(hdr);
  86         m->m_data -= 4;
  87         m->m_len  += 4;
  88         bcopy(&hdrbuf, m->m_data, 4);
  89 
  90         /*
  91          * Get contiguous data (so TCP won't fragment)
  92          * Note: replaces mb_top.
  93          */
  94         err = m_lineup(mbp->mb_top, &mbp->mb_top);
  95         if (err)
  96                 return (err);
  97         m = mbp->mb_top;
  98 
  99         /*
 100          * Send it.
 101          */
 102         if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) {
 103                 if (t_errno == TSYSERR)
 104                         err = errno;
 105                 else
 106                         err = EPROTO;
 107                 DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
 108                 return (err);
 109         }
 110 
 111         return (0);
 112 }
 113 
 114 /*
 115  * Receive a data message.  Discard anything else.
 116  * Caller must deal with EAGAIN, EINTR.
 117  */
 118 int
 119 smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
 120 {
 121         int err, mtype, mlen;
 122         err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
 123         if (err)
 124                 return (err);
 125         if (mtype != NB_SSN_MESSAGE) {
 126                 DPRINT("discard type 0x%x", mtype);
 127                 mb_done(mbp);
 128                 return (EAGAIN);
 129         }
 130         if (mlen == 0) {
 131                 DPRINT("zero length");
 132                 mb_done(mbp);
 133                 return (EAGAIN);
 134         }
 135 
 136         return (0);
 137 }
 138 
 139 /*
 140  * Receive a NetBIOS message, any type.
 141  * Give caller type and length.
 142  */
 143 static int
 144 nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
 145             int *mtype, int *mlen)
 146 {
 147         char *buf;
 148         uint32_t hdr, hdrbuf;
 149         int cnt, len, err, moreflag;
 150         int fd = ctx->ct_tran_fd;
 151         int tmo = smb_recv_timeout * 1000;
 152 
 153         /*
 154          * Start by getting the header
 155          * (four bytes)
 156          */
 157         if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
 158                 DPRINT("pollin err %d", err);
 159                 return (err);
 160         }
 161         moreflag = 0;
 162         cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
 163         if (cnt < 0) {
 164                 err = get_xti_err(fd);
 165                 DPRINT("t_errno %d err %d", t_errno, err);
 166                 return (err);
 167         }
 168 
 169         if (cnt != sizeof (hdrbuf)) {
 170                 DPRINT("hdr cnt %d", cnt);
 171                 return (EPROTO);
 172         }
 173 
 174         /*
 175          * Decode the header, get the length.
 176          */
 177         hdr = ntohl(hdrbuf);
 178         *mtype = (hdr >> 24) & 0xff;
 179         *mlen = hdr & 0xffffff;
 180 
 181         if (mlen == 0)
 182                 return (0);
 183 
 184         /*
 185          * Get a message buffer, read the payload
 186          */
 187         if ((err = mb_init_sz(mb, *mlen)) != 0)
 188                 return (err);
 189         buf = mb->mb_top->m_data;
 190         len = *mlen;
 191         while (len > 0) {
 192                 if (!moreflag) {
 193                         if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
 194                                 DPRINT("pollin err %d", err);
 195                                 return (err);
 196                         }
 197                 }
 198 
 199                 moreflag = 0;
 200                 cnt = t_rcv(fd, buf, len, &moreflag);
 201                 if (cnt < 0) {
 202                         err = get_xti_err(fd);
 203                         DPRINT("t_errno %d err %d", t_errno, err);
 204                         return (err);
 205                 }
 206                 buf += cnt;
 207                 len -= cnt;
 208         }
 209         mb->mb_top->m_len = *mlen;
 210         mb->mb_count = *mlen;
 211 
 212         return (0);
 213 }
 214 
 215 int
 216 get_xti_err(int fd)
 217 {
 218         int look;
 219         if (t_errno == TSYSERR)
 220                 return (errno);
 221 
 222         if (t_errno == TLOOK) {
 223                 look = t_look(fd);
 224                 switch (look) {
 225                 case T_DISCONNECT:
 226                         (void) t_rcvdis(fd, NULL);
 227                         (void) t_snddis(fd, NULL);
 228                         return (ECONNRESET);
 229                 case T_ORDREL:
 230                         /* Received orderly release indication */
 231                         (void) t_rcvrel(fd);
 232                         /* Send orderly release indicator */
 233                         (void) t_sndrel(fd);
 234                         return (ECONNRESET);
 235                 }
 236         }
 237         return (EPROTO);
 238 }
 239 
 240 /*
 241  * Wait for data we can receive.
 242  * Timeout is mSec., as for poll(2)
 243  */
 244 static int
 245 nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
 246 {
 247         struct pollfd pfd[1];
 248         int cnt, err;
 249 
 250         pfd[0].fd = ctx->ct_tran_fd;
 251         pfd[0].events = POLLIN | POLLPRI;
 252         pfd[0].revents = 0;
 253         cnt = poll(pfd, 1, tmo);
 254         switch (cnt) {
 255         case 0:
 256                 err = ETIME;
 257                 break;
 258         case -1:
 259                 err = errno;
 260                 break;
 261         default:
 262                 err = 0;
 263                 break;
 264         }
 265         return (err);
 266 }
 267 
 268 /*
 269  * Send a NetBIOS session request and
 270  * wait for the response.
 271  */
 272 int
 273 nb_ssn_request(struct smb_ctx *ctx, char *srvname)
 274 {
 275         struct mbdata req, res;
 276         struct nb_name lcl, srv;
 277         int err, mtype, mlen;
 278         char *ucwks;
 279 
 280         bzero(&req, sizeof (req));
 281         bzero(&res, sizeof (res));
 282 
 283         if ((err = mb_init(&req)) != 0)
 284                 goto errout;
 285 
 286         ucwks = utf8_str_toupper(ctx->ct_locname);
 287         if (ucwks == NULL) {
 288                 err = ENOMEM;
 289                 goto errout;
 290         }
 291 
 292         /* Local NB name. */
 293         snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
 294         lcl.nn_type = NBT_WKSTA;
 295         lcl.nn_scope = ctx->ct_nb->nb_scope;
 296 
 297         /* Server NB name */
 298         snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
 299         srv.nn_type = NBT_SERVER;
 300         srv.nn_scope = ctx->ct_nb->nb_scope;
 301 
 302         /*
 303          * Build the request.  Header is prepended later.
 304          */
 305         if ((err = nb_name_encode(&req, &srv)) != 0)
 306                 goto errout;
 307         if ((err = nb_name_encode(&req, &lcl)) != 0)
 308                 goto errout;
 309 
 310         /*
 311          * Send it, wait for the reply.
 312          */
 313         err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
 314         if (err) {
 315                 DPRINT("send, err %d", err);
 316                 goto errout;
 317         }
 318         err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
 319         if (err) {
 320                 DPRINT("recv, err %d", err);
 321                 goto errout;
 322         }
 323 
 324         if (mtype != NB_SSN_POSRESP) {
 325                 DPRINT("recv, mtype 0x%x", mtype);
 326                 err = ECONNREFUSED;
 327                 goto errout;
 328         }
 329 
 330         return (0);
 331 
 332 errout:
 333         mb_done(&res);
 334         mb_done(&req);
 335         return (err);
 336 }