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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * NetBIOS support functions. NetBIOS is documented in the following 30 * RFC documents: 31 * 32 * RFC 1001: Protocol Standard for a NetBIOS Service on a TCP/UDP 33 * Transport: Concepts and Methods 34 * 35 * RFC 1002: Protocol Standard for a NetBIOS Service on a TCP/UDP 36 * Transport: Detailed Specifications 37 * 38 */ 39 40 #define BSD_BYTE_STRING_PROTOTYPES 41 42 #include <string.h> 43 #include <unistd.h> 44 #include <synch.h> 45 #include <sys/types.h> 46 #include <sys/uio.h> 47 #include <sys/time.h> 48 49 #include <stdio.h> 50 #include <pthread.h> 51 52 #define MAX_NETBIOS_NAME_SIZE 16 53 54 #define SESSION_MESSAGE 0x00 55 #define SESSION_REQUEST 0x81 56 #define POSITIVE_SESSION_RESPONSE 0x82 57 #define NEGATIVE_SESSION_RESPONSE 0x83 58 #define RETARGET_SESSION_RESPONSE 0x84 59 #define SESSION_KEEP_ALIVE 0x85 60 61 #define NB_READ_MSG_ERR_EOF 0 62 #define NB_READ_MSG_ERR -1 63 #define NB_READ_MSG_ERR_OVERFLOW -2 64 #define NB_READ_MSG_ERR_UNDERFLOW -3 65 #define NB_RCV_MSG_ERR_INVTYPE -4 66 67 /* 68 * Semaphore object used to serialize access through NetBIOS exchange. 69 */ 70 static mutex_t nb_mutex; 71 72 static int nb_write_msg(int fd, unsigned char *buf, unsigned count, int type); 73 static int nb_read_msg(int fd, unsigned char *buf, unsigned max_buf, 74 int *type, long timeout); 75 static int nb_read_itter(int fd, unsigned char *buf, unsigned cnt); 76 static int nb_first_level_name_encode(char *name, char *scope, 77 unsigned char *out, int max_out); 78 79 80 /* 81 * nb_lock 82 * 83 * Acquire semaphore for doing netbios operations 84 */ 85 void 86 nb_lock() 87 { 88 (void) mutex_lock(&nb_mutex); 89 } 90 91 /* 92 * nb_lock 93 * 94 * Release netbios semaphore. 95 */ 96 void 97 nb_unlock() 98 { 99 (void) mutex_unlock(&nb_mutex); 100 } 101 102 void 103 nb_close(int fd) 104 { 105 (void) mutex_lock(&nb_mutex); 106 if (fd > 0) { 107 (void) close(fd); 108 (void) printf("[%d] socket (%d) closed\n", pthread_self(), fd); 109 } 110 (void) mutex_unlock(&nb_mutex); 111 } 112 113 /* 114 * nb_keep_alive 115 * 116 * Send the NetBIOS keep alive message. No response is expected but we 117 * do need to ignore keep-alive messages in nb_exchange. The semaphore 118 * ensures compatibility/serialization with nb_exchange to allow us to 119 * call this function from a separate thread. 120 */ 121 int 122 nb_keep_alive(int fd) 123 { 124 int nothing; 125 int rc; 126 127 (void) mutex_lock(&nb_mutex); 128 129 rc = nb_write_msg(fd, (unsigned char *)¬hing, 0, SESSION_KEEP_ALIVE); 130 131 (void) mutex_unlock(&nb_mutex); 132 return (rc); 133 } 134 135 /* 136 * nb_send 137 * 138 * This is just a wrapper round the nb_write_msg. 139 */ 140 int 141 nb_send(int fd, unsigned char *send_buf, unsigned send_cnt) 142 { 143 int rc; 144 145 rc = nb_write_msg(fd, send_buf, send_cnt, SESSION_MESSAGE); 146 return (rc); 147 } 148 149 /* 150 * nb_rcv 151 * 152 * This is a wrapper round the nb_read_msg() so that if a 153 * keep-alive message is received, just discard it and go 154 * back to look for the real response. 155 */ 156 int 157 nb_rcv(int fd, unsigned char *recv_buf, unsigned recv_max, long timeout) 158 { 159 int rc; 160 int type; 161 162 do { 163 rc = nb_read_msg(fd, recv_buf, recv_max, &type, timeout); 164 if (rc < 0) 165 return (rc); 166 } while (type == SESSION_KEEP_ALIVE); 167 168 if (type != SESSION_MESSAGE) 169 return (NB_RCV_MSG_ERR_INVTYPE); 170 171 return (rc); 172 } 173 174 /* 175 * nb_exchange 176 * 177 * This is the NetBIOS workhorse function where we do the send/receive 178 * message exchange. A semaphore is used to serialize access because 179 * we may get swapped out between the send and receive operations and 180 * another thread could enter here and collect our response. If a 181 * keep-alive message is received, just discard it and go back to look 182 * for the real response. 183 * 184 * Note: With the addition of support for SMB over TCP, this function 185 * may be exchanging NetBIOS-less SMB data. 186 */ 187 int 188 nb_exchange(int fd, unsigned char *send_buf, unsigned send_cnt, 189 unsigned char *recv_buf, unsigned recv_max, long timeout) 190 { 191 int rc; 192 193 (void) mutex_lock(&nb_mutex); 194 195 rc = nb_send(fd, send_buf, send_cnt); 196 if (rc == send_cnt) 197 rc = nb_rcv(fd, recv_buf, recv_max, timeout); 198 199 (void) mutex_unlock(&nb_mutex); 200 return (rc); 201 } 202 203 /* 204 * nb_session_request 205 * 206 * We should never see descriptor 0 (stdin) or -1. 207 */ 208 int 209 nb_session_request(int fd, char *called_name, char *called_scope, 210 char *calling_name, char *calling_scope) 211 { 212 unsigned char sr_buf[200]; 213 int len; 214 int rc; 215 int type; 216 217 if (fd == 0 || fd == -1) 218 return (-1); 219 220 rc = nb_first_level_name_encode(called_name, called_scope, sr_buf, 100); 221 len = rc; 222 rc = nb_first_level_name_encode(calling_name, calling_scope, 223 sr_buf+len, 100); 224 len += rc; 225 226 (void) mutex_lock(&nb_mutex); 227 228 rc = nb_write_msg(fd, (unsigned char *)sr_buf, len, SESSION_REQUEST); 229 if (rc < 0) { 230 (void) mutex_unlock(&nb_mutex); 231 return (rc); 232 } 233 234 for (;;) { 235 rc = nb_read_msg(fd, (unsigned char *)sr_buf, 236 sizeof (sr_buf), &type, 0); 237 if (rc < 0) { 238 (void) mutex_unlock(&nb_mutex); 239 return (rc); 240 } 241 242 if ((rc == 0) && (type == -1)) { 243 (void) mutex_unlock(&nb_mutex); 244 return (-1); /* EOF */ 245 } 246 247 if (type == POSITIVE_SESSION_RESPONSE) { 248 (void) mutex_unlock(&nb_mutex); 249 return (0); 250 } 251 252 if (type == NEGATIVE_SESSION_RESPONSE) { 253 (void) mutex_unlock(&nb_mutex); 254 return (-1); 255 } 256 } 257 258 /* NOTREACHED */ 259 (void) mutex_unlock(&nb_mutex); 260 return (-1); 261 } 262 263 264 265 /* 266 * nb_write_msg 267 */ 268 static int 269 nb_write_msg(int fd, unsigned char *buf, unsigned count, int type) 270 { 271 struct iovec iov[2]; 272 unsigned char header[4]; 273 int rc; 274 275 if (fd == 0 || fd == -1) { 276 /* 277 * We should never see descriptor 0 (stdin). 278 */ 279 return (-1); 280 } 281 282 /* 283 * The NetBIOS message length is limited to 17 bits but 284 * we use this layer for SMB over both NetBIOS and TCP 285 * (NetBIOS-less SMB). When using SMB over TCP the length 286 * is 24 bits but we are ignoring that for now because we 287 * don't expect any messages larger than 64KB. 288 */ 289 header[0] = type; 290 header[1] = (count >> 16) & 1; 291 header[2] = count >> 8; 292 header[3] = count; 293 294 iov[0].iov_base = (caddr_t)header; 295 iov[0].iov_len = 4; 296 iov[1].iov_base = (caddr_t)buf; 297 iov[1].iov_len = count; 298 299 rc = writev(fd, iov, 2); 300 if (rc != 4 + count) { 301 return (-3); /* error */ 302 } 303 304 return (count); 305 } 306 307 308 /* 309 * nb_read_msg 310 * 311 * Added select to ensure that we don't block forever waiting for a 312 * message. 313 */ 314 static int 315 nb_read_msg(int fd, unsigned char *buf, unsigned max_buf, 316 int *type, long timeout) 317 { 318 unsigned char header[4]; 319 int length; 320 int rc; 321 fd_set readfds; 322 struct timeval tval; 323 324 *type = -1; 325 326 if (fd == 0 || fd == -1) { 327 /* 328 * We should never see descriptor 0 (stdin). 329 */ 330 return (NB_READ_MSG_ERR); 331 } 332 333 FD_ZERO(&readfds); 334 FD_SET(fd, &readfds); 335 tval.tv_sec = (timeout == 0) ? 45 : timeout; 336 tval.tv_usec = 0; 337 338 if ((rc = select(fd + 1, &readfds, 0, 0, &tval)) <= 0) { 339 return (NB_READ_MSG_ERR); 340 } 341 342 if ((rc = nb_read_itter(fd, header, 4)) < 0) 343 return (rc); /* error */ 344 345 if (rc != 4) 346 return (NB_READ_MSG_ERR_EOF); /* EOF */ 347 348 /* 349 * The NetBIOS message length is limited to 17 bits but 350 * we use this layer for SMB over both NetBIOS and TCP 351 * (NetBIOS-less SMB). When using SMB over TCP the length 352 * is 24 bits but we are ignoring that for now because we 353 * don't expect any messages larger than 64KB. 354 */ 355 *type = header[0]; 356 length = ((header[1]&1) << 16) + (header[2]<<8) + header[3]; 357 358 if (length > max_buf) 359 return (NB_READ_MSG_ERR_OVERFLOW); /* error overflow */ 360 361 if ((rc = nb_read_itter(fd, buf, length)) != length) 362 return (NB_READ_MSG_ERR_UNDERFLOW); /* error underflow */ 363 364 return (rc); 365 } 366 367 368 /* 369 * nb_read_itter 370 * 371 * We should never see descriptor 0 (stdin) or -1. 372 */ 373 static int 374 nb_read_itter(int fd, unsigned char *buf, unsigned cnt) 375 { 376 int ix; 377 int rc; 378 379 for (ix = 0; ix < cnt; ix += rc) { 380 if (fd == 0 || fd == -1) 381 return (-1); 382 383 if ((rc = read(fd, buf+ix, cnt-ix)) < 0) 384 return (rc); 385 386 if (rc == 0) 387 break; 388 } 389 390 return (ix); 391 } 392 393 394 /* 395 * nb_first_level_name_encode 396 */ 397 static int 398 nb_first_level_name_encode(char *name, char *scope, 399 unsigned char *out, int max_out) 400 { 401 unsigned char ch, len; 402 unsigned char *in; 403 unsigned char *lp; 404 unsigned char *op = out; 405 unsigned char *op_end = op + max_out; 406 407 in = (unsigned char *)name; 408 *op++ = 0x20; 409 for (len = 0; ((ch = *in) != 0) && len < MAX_NETBIOS_NAME_SIZE; 410 len++, in++) { 411 *op++ = 'A' + ((ch >> 4) & 0xF); 412 *op++ = 'A' + ((ch) & 0xF); 413 } 414 415 for (; len < MAX_NETBIOS_NAME_SIZE; len++) { 416 ch = ' '; 417 *op++ = 'A' + ((ch >> 4) & 0xF); 418 *op++ = 'A' + ((ch) & 0xF); 419 } 420 421 in = (unsigned char *)scope; 422 len = 0; 423 lp = op++; 424 for (; op < op_end; in++) { 425 ch = *in; 426 if (ch == 0) { 427 if ((*lp = len) != 0) 428 *op++ = 0; 429 break; 430 } 431 if (ch == '.') { 432 *lp = (op - lp) - 1; 433 lp = op++; 434 len = 0; 435 } else { 436 *op++ = ch; 437 len++; 438 } 439 } 440 441 return ((int)(op - out)); 442 } 443