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