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 } 337