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