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 2007 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 #include <sys/atomic.h> 29 #include <sys/strsubr.h> 30 #include <sys/synch.h> 31 #include <sys/types.h> 32 #include <sys/socketvar.h> 33 #include <sys/sdt.h> 34 #include <smbsrv/netbios.h> 35 #include <smbsrv/smb_incl.h> 36 #include <smbsrv/smb_i18n.h> 37 38 extern int smb_maxbufsize; 39 40 extern unsigned int smb_nt_tcp_rcvbuf; 41 42 uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT; 43 uint32_t smb_send_retries = 0; 44 uint32_t smb_receive_retries = 0; 45 46 static int smb_session_message(smb_session_t *); 47 static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *, 48 uint8_t *, size_t); 49 50 void smb_request_init_command_mbuf(smb_request_t *sr); 51 static void smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void); 52 53 54 void 55 smb_timers(smb_thread_t *thread, void *si_void) 56 { 57 smb_info_t *si = si_void; 58 smb_session_t *sn; 59 60 ASSERT(si != NULL); 61 62 while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) { 63 /* 64 * Walk through the table and decrement each keep_alive 65 * timer that has not timed out yet. (keepalive > 0) 66 */ 67 smb_svcstate_lock_read(&si->si_svc_sm_ctx); 68 69 sn = NULL; 70 while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, 71 sn)) != NULL) { 72 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 73 if (sn->keep_alive && (sn->keep_alive != (uint32_t)-1)) 74 sn->keep_alive--; 75 } 76 smb_svcstate_unlock(&smb_info.si_svc_sm_ctx); 77 78 } 79 } 80 81 /* 82 * smb_reconnection_check 83 * 84 * This function is called when a client indicates its current connection 85 * should be the only one it has with the server, as indicated by VC=0 in 86 * a SessionSetupX request. We go through the session list and destroy any 87 * stale connections for that client. 88 * 89 * Clients don't associate IP addresses and servers. So a client may make 90 * independent connections (i.e. with VC=0) to a server with multiple 91 * IP addresses. So, when checking for a reconnection, we need to include 92 * the local IP address, to which the client is connecting, when checking 93 * for stale sessions. 94 * 95 * Also check the server's NetBIOS name to support simultaneous access by 96 * multiple clients behind a NAT server. This will only work for SMB over 97 * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because 98 * there is no NetBIOS name. See also Knowledge Base article Q301673. 99 */ 100 void 101 smb_reconnection_check(struct smb_session *session) 102 { 103 smb_info_t *si = &smb_info; 104 smb_session_t *sn; 105 106 smb_svcstate_lock_read(&si->si_svc_sm_ctx); 107 108 sn = NULL; 109 while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn)) 110 != NULL) { 111 112 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 113 if ((sn != session) && 114 (sn->ipaddr == session->ipaddr) && 115 (sn->local_ipaddr == session->local_ipaddr) && 116 (strcasecmp(sn->workstation, session->workstation) == 0) && 117 (sn->opentime <= session->opentime) && 118 (sn->s_kid < session->s_kid)) { 119 smb_thread_stop(&sn->s_thread); 120 } 121 } 122 123 smb_svcstate_unlock(&smb_info.si_svc_sm_ctx); 124 } 125 126 127 void 128 smb_correct_keep_alive_values(uint32_t new_keep_alive) 129 { 130 smb_info_t *si = &smb_info; 131 smb_session_t *sn; 132 133 if (new_keep_alive == smb_keep_alive) 134 return; 135 /* 136 * keep alive == 0 means do not drop connection if it's idle 137 */ 138 smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1; 139 140 /* 141 * Walk through the table and set each session to the new keep_alive 142 * value if they have not already timed out. Block clock interrupts. 143 */ 144 smb_svcstate_lock_read(&si->si_svc_sm_ctx); 145 146 sn = NULL; 147 while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn)) 148 != NULL) { 149 if (sn->keep_alive) 150 sn->keep_alive = new_keep_alive; 151 } 152 153 smb_svcstate_unlock(&smb_info.si_svc_sm_ctx); 154 } 155 156 /* 157 * Send a session message - supports SMB-over-NBT and SMB-over-TCP. 158 * 159 * The mbuf chain is copied into a contiguous buffer so that the whole 160 * message is submitted to smb_sosend as a single request. This should 161 * help Ethereal/Wireshark delineate the packets correctly even though 162 * TCP_NODELAY has been set on the socket. 163 * 164 * If an mbuf chain is provided, it will be freed and set to NULL here. 165 */ 166 int 167 smb_session_send(smb_session_t *session, uint8_t type, struct mbuf_chain *mbc) 168 { 169 struct mbuf *m = 0; 170 uint8_t *buf; 171 smb_xprt_t hdr; 172 int count = 0; 173 int rc; 174 175 switch (session->s_state) { 176 case SMB_SESSION_STATE_DISCONNECTED: 177 case SMB_SESSION_STATE_TERMINATED: 178 if ((mbc != NULL) && (mbc->chain != NULL)) { 179 m_freem(mbc->chain); 180 mbc->chain = NULL; 181 mbc->flags = 0; 182 } 183 return (ENOTCONN); 184 default: 185 break; 186 } 187 188 buf = kmem_alloc(NETBIOS_REQ_MAX_SIZE, KM_SLEEP); 189 190 if ((mbc != NULL) && (mbc->chain != NULL)) { 191 count = NETBIOS_HDR_SZ; /* Account for the NBT header. */ 192 m = mbc->chain; 193 194 while (m) { 195 if ((count + m->m_len) > NETBIOS_REQ_MAX_SIZE) { 196 kmem_free(buf, NETBIOS_REQ_MAX_SIZE); 197 m_freem(mbc->chain); 198 mbc->chain = NULL; 199 mbc->flags = 0; 200 return (EMSGSIZE); 201 } 202 bcopy(m->m_data, buf + count, m->m_len); 203 count += m->m_len; 204 m = m->m_next; 205 } 206 207 m_freem(mbc->chain); 208 mbc->chain = NULL; 209 mbc->flags = 0; 210 count -= NETBIOS_HDR_SZ; 211 } 212 213 hdr.xh_type = type; 214 hdr.xh_length = count; 215 216 rc = smb_session_xprt_puthdr(session, &hdr, buf, NETBIOS_HDR_SZ); 217 if (rc == 0) { 218 count += NETBIOS_HDR_SZ; 219 rc = smb_sosend(session->sock, buf, count); 220 } 221 222 kmem_free(buf, NETBIOS_REQ_MAX_SIZE); 223 return (rc); 224 } 225 226 /* 227 * Read, process and respond to a NetBIOS session request. 228 * 229 * A NetBIOS session must be established for SMB-over-NetBIOS. Validate 230 * the calling and called name format and save the client NetBIOS name, 231 * which is used when a NetBIOS session is established to check for and 232 * cleanup leftover state from a previous session. 233 * 234 * Session requests are not valid for SMB-over-TCP, which is unfortunate 235 * because without the client name leftover state cannot be cleaned up 236 * if the client is behind a NAT server. 237 */ 238 static int 239 smb_session_request(struct smb_session *session) 240 { 241 int rc; 242 char *calling_name; 243 char *called_name; 244 char client_name[NETBIOS_NAME_SZ]; 245 struct mbuf_chain mbc; 246 char *names = NULL; 247 mts_wchar_t *wbuf = NULL; 248 smb_xprt_t hdr; 249 char *p; 250 unsigned int cpid = oem_get_smb_cpid(); 251 int rc1, rc2; 252 253 session->keep_alive = smb_keep_alive; 254 255 if (smb_session_xprt_gethdr(session, &hdr) != 0) 256 return (EINVAL); 257 258 DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session, 259 smb_xprt_t *, &hdr); 260 261 if ((hdr.xh_type != SESSION_REQUEST) || 262 (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) { 263 DTRACE_PROBE1(receive__session__req__failed, 264 struct session *, session); 265 return (EINVAL); 266 } 267 268 names = kmem_alloc(hdr.xh_length, KM_SLEEP); 269 270 if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) { 271 kmem_free(names, hdr.xh_length); 272 DTRACE_PROBE1(receive__session__req__failed, 273 struct session *, session); 274 return (rc); 275 } 276 277 DTRACE_PROBE3(receive__session__req__data, struct session *, session, 278 char *, names, uint32_t, hdr.xh_length); 279 280 called_name = &names[0]; 281 calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2]; 282 283 rc1 = netbios_name_isvalid(called_name, 0); 284 rc2 = netbios_name_isvalid(calling_name, client_name); 285 286 if (rc1 == 0 || rc2 == 0) { 287 288 DTRACE_PROBE3(receive__invalid__session__req, 289 struct session *, session, char *, names, 290 uint32_t, hdr.xh_length); 291 292 kmem_free(names, hdr.xh_length); 293 MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH); 294 (void) smb_encode_mbc(&mbc, "b", 295 DATAGRAM_INVALID_SOURCE_NAME_FORMAT); 296 (void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE, 297 &mbc); 298 return (EINVAL); 299 } 300 301 DTRACE_PROBE3(receive__session__req__calling__decoded, 302 struct session *, session, 303 char *, calling_name, char *, client_name); 304 305 /* 306 * The client NetBIOS name is in oem codepage format. 307 * We need to convert it to unicode and store it in 308 * multi-byte format. We also need to strip off any 309 * spaces added as part of the NetBIOS name encoding. 310 */ 311 wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (mts_wchar_t)), KM_SLEEP); 312 (void) oemstounicodes(wbuf, client_name, SMB_PI_MAX_HOST, cpid); 313 (void) mts_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST); 314 kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (mts_wchar_t))); 315 316 if ((p = strchr(session->workstation, ' ')) != 0) 317 *p = '\0'; 318 319 kmem_free(names, hdr.xh_length); 320 return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL)); 321 } 322 323 /* 324 * Read 4-byte header from the session socket and build an in-memory 325 * session transport header. See smb_xprt_t definition for header 326 * format information. 327 * 328 * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The 329 * first byte of the four-byte header must be 0 and the next three 330 * bytes contain the length of the remaining data. 331 */ 332 int 333 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr) 334 { 335 unsigned char buf[NETBIOS_HDR_SZ]; 336 337 if (smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ) != 0) 338 return (-1); 339 340 switch (session->s_local_port) { 341 case SSN_SRVC_TCP_PORT: 342 ret_hdr->xh_type = buf[0]; 343 ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) | 344 ((uint32_t)buf[2] << 8) | 345 ((uint32_t)buf[3]); 346 break; 347 348 case SMB_SRVC_TCP_PORT: 349 ret_hdr->xh_type = buf[0]; 350 351 if (ret_hdr->xh_type != 0) { 352 cmn_err(CE_WARN, "0x%08x: invalid type (%u)", 353 session->ipaddr, ret_hdr->xh_type); 354 return (-1); 355 } 356 357 ret_hdr->xh_length = ((uint32_t)buf[1] << 16) | 358 ((uint32_t)buf[2] << 8) | 359 ((uint32_t)buf[3]); 360 break; 361 362 default: 363 cmn_err(CE_WARN, "0x%08x: invalid port %u", 364 session->ipaddr, session->s_local_port); 365 return (-1); 366 } 367 368 return (0); 369 } 370 371 /* 372 * Encode a transport session packet header into a 4-byte buffer. 373 * See smb_xprt_t definition for header format information. 374 */ 375 static int 376 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr, 377 uint8_t *buf, size_t buflen) 378 { 379 if (session == NULL || hdr == NULL || 380 buf == NULL || buflen < NETBIOS_HDR_SZ) { 381 return (-1); 382 } 383 384 switch (session->s_local_port) { 385 case SSN_SRVC_TCP_PORT: 386 buf[0] = hdr->xh_type; 387 buf[1] = ((hdr->xh_length >> 16) & 1); 388 buf[2] = (hdr->xh_length >> 8) & 0xff; 389 buf[3] = hdr->xh_length & 0xff; 390 break; 391 392 case SMB_SRVC_TCP_PORT: 393 buf[0] = hdr->xh_type; 394 buf[1] = (hdr->xh_length >> 16) & 0xff; 395 buf[2] = (hdr->xh_length >> 8) & 0xff; 396 buf[3] = hdr->xh_length & 0xff; 397 break; 398 399 default: 400 cmn_err(CE_WARN, "0x%08x: invalid port (%u)", 401 session->ipaddr, session->s_local_port); 402 return (-1); 403 } 404 405 return (0); 406 } 407 408 /* 409 * smb_request_alloc 410 * 411 * Allocate an smb_request_t structure from the kmem_cache. Partially 412 * initialize the found/new request. 413 * 414 * Returns pointer to a request 415 */ 416 smb_request_t * 417 smb_request_alloc(struct smb_session *session, int req_length) 418 { 419 struct smb_request *sr; 420 421 sr = kmem_cache_alloc(smb_info.si_cache_request, KM_SLEEP); 422 423 /* 424 * Future: Use constructor to pre-initialize some fields. For now 425 * there are so many fields that it is easiest just to zero the 426 * whole thing and start over. 427 */ 428 bzero(sr, sizeof (smb_request_t)); 429 430 mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL); 431 sr->session = session; 432 sr->request_storage.forw = &sr->request_storage; 433 sr->request_storage.back = &sr->request_storage; 434 sr->command.max_bytes = req_length; 435 sr->reply.max_bytes = smb_maxbufsize; 436 sr->sr_req_length = req_length; 437 sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP); 438 sr->sr_magic = SMB_REQ_MAGIC; 439 sr->sr_state = SMB_REQ_STATE_INITIALIZING; 440 smb_slist_insert_tail(&session->s_req_list, sr); 441 return (sr); 442 } 443 444 void 445 smb_request_init_command_mbuf(smb_request_t *sr) 446 { 447 MGET(sr->command.chain, 0, MT_DATA); 448 449 /* 450 * Setup mbuf, mimic MCLGET but use the complete packet buffer. 451 */ 452 sr->command.chain->m_ext.ext_buf = sr->sr_request_buf; 453 sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf; 454 sr->command.chain->m_len = sr->sr_req_length; 455 sr->command.chain->m_flags |= M_EXT; 456 sr->command.chain->m_ext.ext_size = sr->sr_req_length; 457 sr->command.chain->m_ext.ext_ref = &mclrefnoop; 458 459 /* 460 * Initialize the rest of the mbuf_chain fields 461 */ 462 sr->command.flags = 0; 463 sr->command.shadow_of = 0; 464 sr->command.max_bytes = sr->sr_req_length; 465 sr->command.chain_offset = 0; 466 } 467 468 /* 469 * smb_request_cancel 470 * 471 * Handle a cancel for a request properly depending on the current request 472 * state. 473 */ 474 void 475 smb_request_cancel(smb_request_t *sr) 476 { 477 mutex_enter(&sr->sr_mutex); 478 switch (sr->sr_state) { 479 480 case SMB_REQ_STATE_SUBMITTED: 481 case SMB_REQ_STATE_ACTIVE: 482 case SMB_REQ_STATE_CLEANED_UP: 483 sr->sr_state = SMB_REQ_STATE_CANCELED; 484 break; 485 486 case SMB_REQ_STATE_WAITING_LOCK: 487 /* 488 * This request is waiting on a lock. Wakeup everything 489 * waiting on the lock so that the relevant thread regains 490 * control and notices that is has been canceled. The 491 * other lock request threads waiting on this lock will go 492 * back to sleep when they discover they are still blocked. 493 */ 494 sr->sr_state = SMB_REQ_STATE_CANCELED; 495 496 ASSERT(sr->sr_awaiting != NULL); 497 mutex_enter(&sr->sr_awaiting->l_mutex); 498 cv_broadcast(&sr->sr_awaiting->l_cv); 499 mutex_exit(&sr->sr_awaiting->l_mutex); 500 501 break; 502 503 case SMB_REQ_STATE_WAITING_EVENT: 504 case SMB_REQ_STATE_EVENT_OCCURRED: 505 /* 506 * Cancellations for these states are handled by the 507 * notify-change code 508 */ 509 break; 510 511 case SMB_REQ_STATE_COMPLETED: 512 case SMB_REQ_STATE_CANCELED: 513 /* 514 * No action required for these states since the request 515 * is completing. 516 */ 517 break; 518 /* 519 * Cases included: 520 * SMB_REQ_STATE_FREE: 521 * SMB_REQ_STATE_INITIALIZING: 522 */ 523 default: 524 ASSERT(0); 525 break; 526 } 527 mutex_exit(&sr->sr_mutex); 528 } 529 530 /* 531 * smb_request_free 532 * 533 * release the memories which have been allocated for a smb request. 534 */ 535 void 536 smb_request_free(smb_request_t *sr) 537 { 538 ASSERT(sr->session); 539 540 ASSERT(sr->fid_ofile == NULL); 541 ASSERT(sr->sid_odir == NULL); 542 ASSERT(sr->tid_tree == NULL); 543 ASSERT(sr->uid_user == NULL); 544 ASSERT(sr->r_xa == NULL); 545 546 smb_slist_remove(&sr->session->s_req_list, sr); 547 548 sr->session = 0; 549 550 /* Release any temp storage */ 551 smbsr_free_malloc_list(&sr->request_storage); 552 553 if (sr->sr_request_buf) 554 kmem_free(sr->sr_request_buf, sr->sr_req_length); 555 if (sr->command.chain) 556 m_freem(sr->command.chain); 557 if (sr->reply.chain) 558 m_freem(sr->reply.chain); 559 if (sr->raw_data.chain) 560 m_freem(sr->raw_data.chain); 561 562 sr->sr_magic = (uint32_t)~SMB_REQ_MAGIC; 563 mutex_destroy(&sr->sr_mutex); 564 kmem_cache_free(smb_info.si_cache_request, sr); 565 } 566 567 /*ARGSUSED*/ 568 void 569 smb_wakeup_session_daemon(smb_thread_t *thread, void *session_void) 570 { 571 struct smb_session *session = session_void; 572 573 ASSERT(session); 574 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 575 576 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 577 switch (session->s_state) { 578 case SMB_SESSION_STATE_TERMINATED: 579 case SMB_SESSION_STATE_DISCONNECTED: 580 break; 581 default: 582 smb_soshutdown(session->sock); 583 break; 584 } 585 smb_rwx_rwexit(&session->s_lock); 586 } 587 588 /* 589 * This is the entry point for processing SMB messages over NetBIOS or 590 * SMB-over-TCP. 591 * 592 * NetBIOS connections require a session request to establish a session 593 * on which to send session messages. 594 * 595 * Session requests are not valid on SMB-over-TCP. We don't need to do 596 * anything here as session requests will be treated as an error when 597 * handling session messages. 598 */ 599 /*ARGSUSED*/ 600 void 601 smb_session_daemon(smb_thread_t *thread, void *session_void) 602 { 603 struct smb_session *session = session_void; 604 int rc = 0; 605 606 ASSERT(session != NULL); 607 608 if (session->s_local_port == SSN_SRVC_TCP_PORT) 609 rc = smb_session_request(session); 610 611 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 612 613 if ((rc == 0) || (session->s_local_port == SMB_SRVC_TCP_PORT)) 614 session->s_state = SMB_SESSION_STATE_ESTABLISHED; 615 else 616 session->s_state = SMB_SESSION_STATE_DISCONNECTED; 617 618 while (session->s_state != SMB_SESSION_STATE_DISCONNECTED) { 619 smb_rwx_rwexit(&session->s_lock); 620 621 rc = smb_session_message(session); 622 623 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 624 625 if (rc != 0) 626 break; 627 } 628 629 smb_soshutdown(session->sock); 630 session->s_state = SMB_SESSION_STATE_DISCONNECTED; 631 smb_rwx_rwexit(&session->s_lock); 632 633 DTRACE_PROBE2(session__drop, struct session *, session, int, rc); 634 635 smb_session_cancel(session); 636 637 /* 638 * At this point everything related to the session should have been 639 * cleaned up and we expect that nothing will attempt to use the 640 * socket. 641 */ 642 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 643 session->s_state = SMB_SESSION_STATE_TERMINATED; 644 smb_sodestroy(session->sock); 645 session->sock = NULL; 646 smb_rwx_rwexit(&session->s_lock); 647 648 /* 649 * Notify SMB service state machine so it can cleanup the session 650 */ 651 smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session); 652 } 653 654 /* 655 * Read and process SMB requests. 656 * 657 * Returns: 658 * 0 Success 659 * 1 Unable to read transport header 660 * 2 Invalid transport header type 661 * 3 Invalid SMB length (too small) 662 * 4 Unable to read SMB header 663 * 5 Invalid SMB header (bad magic number) 664 * 6 Unable to read SMB data 665 * 2x Write raw failed 666 */ 667 static int 668 smb_session_message(smb_session_t *session) 669 { 670 struct smb_request *sr = NULL; 671 smb_xprt_t hdr; 672 uint8_t *req_buf; 673 uint32_t resid; 674 int rc; 675 676 if (smb_session_xprt_gethdr(session, &hdr) != 0) 677 return (1); 678 679 DTRACE_PROBE2(session__receive__xprthdr, struct session *, session, 680 smb_xprt_t *, &hdr); 681 682 if (hdr.xh_type != SESSION_MESSAGE) { 683 /* 684 * Anything other than SESSION_MESSAGE or SESSION_KEEP_ALIVE 685 * is an error. A SESSION_REQUEST may indicate a new session 686 * request but we need to close this session and we can treat 687 * it as an error here. 688 */ 689 if (hdr.xh_type == SESSION_KEEP_ALIVE) { 690 session->keep_alive = smb_keep_alive; 691 return (0); 692 } 693 694 return (2); 695 } 696 697 if (hdr.xh_length < SMB_HEADER_LEN) 698 return (3); 699 700 session->keep_alive = smb_keep_alive; 701 702 /* 703 * Allocate a request context, read the SMB header and validate it. 704 * The sr includes a buffer large enough to hold the SMB request 705 * payload. If the header looks valid, read any remaining data. 706 */ 707 sr = smb_request_alloc(session, hdr.xh_length); 708 709 req_buf = (uint8_t *)sr->sr_request_buf; 710 resid = hdr.xh_length; 711 712 if (smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN) != 0) { 713 smb_request_free(sr); 714 return (4); 715 } 716 717 if (SMB_PROTOCOL_MAGIC_INVALID(sr)) { 718 smb_request_free(sr); 719 return (5); 720 } 721 722 if (resid > SMB_HEADER_LEN) { 723 req_buf += SMB_HEADER_LEN; 724 resid -= SMB_HEADER_LEN; 725 726 if (smb_sorecv(session->sock, req_buf, resid) != 0) { 727 smb_request_free(sr); 728 return (6); 729 } 730 } 731 732 /* 733 * Initialize command MBC to represent the received data. 734 */ 735 smb_request_init_command_mbuf(sr); 736 737 DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr); 738 739 /* 740 * If this is a raw write, hand off the request. The handler 741 * will retrieve the remaining raw data and process the request. 742 */ 743 if (SMB_IS_WRITERAW(sr)) { 744 rc = smb_handle_write_raw(session, sr); 745 /* XXX smb_request_free(sr); ??? */ 746 return (rc); 747 } 748 749 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 750 (void) taskq_dispatch(smb_info.thread_pool, smb_session_worker, 751 sr, TQ_SLEEP); 752 return (0); 753 } 754 755 /* 756 * smb_session_wakeup_daemon 757 * 758 * When the smbsrv kernel module/driver gets unloaded, chances are the 759 * smb_nbt_daemon and smb_tcp_daemon threads are blocked in soaccept. 760 * We can't get control of the threads until they return from soaccept. 761 * This function will attempt to connect to the SMB service via 762 * "localhost" to wake up the threads. 763 */ 764 /*ARGSUSED*/ 765 static void 766 smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void) 767 { 768 struct sonode *so = so_void; 769 770 ASSERT(so != NULL); 771 772 mutex_enter(&so->so_lock); 773 so->so_error = EINTR; 774 cv_signal(&so->so_connind_cv); 775 mutex_exit(&so->so_lock); 776 } 777 778 /* 779 * SMB-over-NetBIOS service. 780 * 781 * Traditional SMB service over NetBIOS (port 139), which requires 782 * that a NetBIOS session be established. 783 */ 784 void 785 smb_nbt_daemon(smb_thread_t *thread, void *arg) 786 { 787 /* XXX Defaults for these values should come from smbd and SMF */ 788 uint32_t txbuf_size = 128*1024; 789 uint32_t on = 1; 790 struct smb_session *session; 791 struct sonode *l_so, *s_so; 792 struct sockaddr_in sin; 793 int error; 794 smb_info_t *si = arg; 795 796 ASSERT(si != NULL); 797 sin.sin_family = AF_INET; 798 sin.sin_port = htons(SSN_SRVC_TCP_PORT); 799 sin.sin_addr.s_addr = htonl(INADDR_ANY); 800 801 l_so = smb_socreate(AF_INET, SOCK_STREAM, 0); 802 if (l_so == NULL) { 803 cmn_err(CE_WARN, "NBT: socket create failed"); 804 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM); 805 return; 806 } 807 808 (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR, 809 (const void *)&on, sizeof (on)); 810 811 if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin), 812 0, 0)) != 0) { 813 cmn_err(CE_WARN, "NBT: bind failed"); 814 smb_soshutdown(l_so); 815 smb_sodestroy(l_so); 816 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 817 return; 818 } 819 if ((error = solisten(l_so, 20)) < 0) { 820 cmn_err(CE_WARN, "NBT: listen failed"); 821 smb_soshutdown(l_so); 822 smb_sodestroy(l_so); 823 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 824 return; 825 } 826 827 smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so); 828 si->si_connect_progress |= SMB_SI_NBT_CONNECTED; 829 smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL); 830 831 while (smb_thread_continue_nowait(thread)) { 832 DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so); 833 834 error = soaccept(l_so, 0, &s_so); 835 if (error) { 836 DTRACE_PROBE1(so__accept__error, int, error); 837 if (error == EINTR) { 838 continue; 839 } 840 841 break; 842 } 843 844 DTRACE_PROBE1(so__accept, struct sonode *, s_so); 845 846 (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY, 847 (const void *)&on, sizeof (on)); 848 (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE, 849 (const void *)&on, sizeof (on)); 850 (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF, 851 (const void *)&txbuf_size, sizeof (txbuf_size)); 852 853 /* 854 * Create a session for this connection and notify the SMB 855 * service state machine. The service state machine may 856 * start a session thread or reject the session depending 857 * on the current service state or number of connections. 858 */ 859 session = smb_session_create(s_so, SSN_SRVC_TCP_PORT); 860 smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE, 861 (uintptr_t)session); 862 863 } 864 865 smb_soshutdown(l_so); 866 smb_sodestroy(l_so); 867 si->si_connect_progress &= ~SMB_SI_NBT_CONNECTED; 868 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 869 } 870 871 /* 872 * SMB-over-TCP (or NetBIOS-less SMB) service. 873 * 874 * SMB service natively over TCP (port 445), i.e. no NetBIOS support. 875 */ 876 void 877 smb_tcp_daemon(smb_thread_t *thread, void *arg) 878 { 879 /* XXX Defaults for these values should come from smbd and SMF */ 880 uint32_t txbuf_size = 128*1024; 881 uint32_t on = 1; 882 struct smb_session *session; 883 struct sonode *l_so, *s_so; 884 struct sockaddr_in sin; 885 int error; 886 smb_info_t *si = arg; 887 888 ASSERT(si != NULL); 889 sin.sin_family = AF_INET; 890 sin.sin_port = htons(SMB_SRVC_TCP_PORT); 891 sin.sin_addr.s_addr = htonl(INADDR_ANY); 892 893 l_so = smb_socreate(AF_INET, SOCK_STREAM, 0); 894 if (l_so == NULL) { 895 cmn_err(CE_WARN, "TCP: socket create failed"); 896 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM); 897 return; 898 } 899 900 (void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR, 901 (const void *)&on, sizeof (on)); 902 903 if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin), 904 0, 0)) != 0) { 905 cmn_err(CE_WARN, "TCP: bind failed"); 906 smb_soshutdown(l_so); 907 smb_sodestroy(l_so); 908 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 909 return; 910 } 911 if ((error = solisten(l_so, 20)) < 0) { 912 cmn_err(CE_WARN, "TCP: listen failed"); 913 smb_soshutdown(l_so); 914 smb_sodestroy(l_so); 915 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 916 return; 917 } 918 919 smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so); 920 si->si_connect_progress |= SMB_SI_TCP_CONNECTED; 921 smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL); 922 923 while (smb_thread_continue_nowait(thread)) { 924 DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so); 925 926 error = soaccept(l_so, 0, &s_so); 927 if (error) { 928 DTRACE_PROBE1(so__accept__error, int, error); 929 if (error == EINTR) { 930 continue; 931 } 932 933 break; 934 } 935 936 DTRACE_PROBE1(so__accept, struct sonode *, s_so); 937 938 (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY, 939 (const void *)&on, sizeof (on)); 940 (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE, 941 (const void *)&on, sizeof (on)); 942 (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF, 943 (const void *)&txbuf_size, sizeof (txbuf_size)); 944 945 /* 946 * Create a session for this connection and notify the SMB 947 * service state machine. The service state machine may 948 * start a session thread or reject the session depending 949 * on the current service state or number of connections. 950 */ 951 session = smb_session_create(s_so, SMB_SRVC_TCP_PORT); 952 smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE, 953 (uintptr_t)session); 954 955 } 956 957 smb_soshutdown(l_so); 958 smb_sodestroy(l_so); 959 si->si_connect_progress &= ~SMB_SI_TCP_CONNECTED; 960 smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error); 961 } 962 963 /* 964 * smb_session_reject 965 * 966 * Build and send a NEGATIVE_SESSION_RESPONSE on the specified socket. 967 * The reason is written to the log. 968 */ 969 /*ARGSUSED*/ 970 void 971 smb_session_reject(smb_session_t *session, char *reason) 972 { 973 unsigned char reply[8]; 974 975 smb_rwx_rwenter(&session->s_lock, RW_READER); 976 if (session->sock != NULL) { 977 reply[0] = NEGATIVE_SESSION_RESPONSE; 978 reply[1] = 0; 979 reply[2] = 0; 980 reply[3] = 1; 981 reply[4] = SESSION_INSUFFICIENT_RESOURCES; 982 983 (void) smb_sosend(session->sock, reply, 5); 984 } 985 smb_rwx_rwexit(&session->s_lock); 986 } 987 988 /* 989 * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT. 990 */ 991 smb_session_t * 992 smb_session_create(struct sonode *new_so, uint16_t port) 993 { 994 uint32_t ipaddr; 995 uint32_t local_ipaddr; 996 struct sockaddr_in sin; 997 smb_session_t *session; 998 999 session = kmem_cache_alloc(smb_info.si_cache_session, KM_SLEEP); 1000 bzero(session, sizeof (smb_session_t)); 1001 1002 if (smb_idpool_constructor(&session->s_uid_pool)) { 1003 kmem_cache_free(smb_info.si_cache_session, session); 1004 return (NULL); 1005 } 1006 1007 session->s_kid = SMB_NEW_KID(); 1008 session->s_state = SMB_SESSION_STATE_DISCONNECTED; 1009 session->native_os = NATIVE_OS_UNKNOWN; 1010 session->opentime = lbolt64; 1011 session->keep_alive = smb_keep_alive; 1012 session->activity_timestamp = lbolt64; 1013 1014 smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t), 1015 offsetof(smb_request_t, sr_session_lnd)); 1016 1017 smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t), 1018 offsetof(smb_user_t, u_lnd)); 1019 1020 smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t), 1021 offsetof(smb_xa_t, xa_lnd)); 1022 1023 smb_thread_init(&session->s_thread, "smb_session", &smb_session_daemon, 1024 session, smb_wakeup_session_daemon, session); 1025 1026 smb_rwx_init(&session->s_lock); 1027 1028 bcopy(new_so->so_faddr_sa, &sin, new_so->so_faddr_len); 1029 ipaddr = sin.sin_addr.s_addr; 1030 1031 bcopy(new_so->so_laddr_sa, &sin, new_so->so_faddr_len); 1032 local_ipaddr = sin.sin_addr.s_addr; 1033 1034 session->s_local_port = port; 1035 session->ipaddr = ipaddr; 1036 session->local_ipaddr = local_ipaddr; 1037 session->sock = new_so; 1038 1039 session->s_magic = SMB_SESSION_MAGIC; 1040 return (session); 1041 } 1042 1043 void 1044 smb_session_delete(smb_session_t *session) 1045 { 1046 ASSERT(session); 1047 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1048 1049 session->s_magic = (uint32_t)~SMB_SESSION_MAGIC; 1050 1051 smb_rwx_destroy(&session->s_lock); 1052 smb_thread_destroy(&session->s_thread); 1053 smb_slist_destructor(&session->s_req_list); 1054 smb_llist_destructor(&session->s_user_list); 1055 smb_llist_destructor(&session->s_xa_list); 1056 1057 ASSERT(session->s_tree_cnt == 0); 1058 ASSERT(session->s_file_cnt == 0); 1059 ASSERT(session->s_dir_cnt == 0); 1060 1061 smb_idpool_destructor(&session->s_uid_pool); 1062 kmem_cache_free(smb_info.si_cache_session, session); 1063 } 1064 1065 void 1066 smb_session_cancel(smb_session_t *session) 1067 { 1068 smb_xa_t *xa, *nextxa; 1069 1070 /* All the request currently being treated must be canceled. */ 1071 smb_session_cancel_requests(session); 1072 1073 /* 1074 * We wait for the completion of all the requests associated with 1075 * this session. 1076 */ 1077 smb_slist_wait_for_empty(&session->s_req_list); 1078 1079 /* 1080 * At this point the reference count of the users, trees, files, 1081 * directories should be zero. It should be possible to destroy them 1082 * without any problem. 1083 */ 1084 xa = smb_llist_head(&session->s_xa_list); 1085 while (xa) { 1086 nextxa = smb_llist_next(&session->s_xa_list, xa); 1087 smb_xa_close(xa); 1088 xa = nextxa; 1089 } 1090 smb_user_logoff_all(session); 1091 } 1092 1093 void 1094 smb_session_cancel_requests( 1095 smb_session_t *session) 1096 { 1097 smb_request_t *sr; 1098 smb_request_t *tmp; 1099 1100 /* All the SMB requests on the notification queue are canceled. */ 1101 smb_process_session_notify_change_queue(session); 1102 1103 smb_slist_enter(&session->s_req_list); 1104 sr = smb_slist_head(&session->s_req_list); 1105 while (sr) { 1106 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1107 tmp = smb_slist_next(&session->s_req_list, sr); 1108 1109 smb_request_cancel(sr); 1110 1111 sr = tmp; 1112 } 1113 smb_slist_exit(&session->s_req_list); 1114 } 1115 1116 void 1117 smb_session_worker( 1118 void *arg) 1119 { 1120 smb_request_t *sr; 1121 1122 sr = (smb_request_t *)arg; 1123 1124 ASSERT(sr != NULL); 1125 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1126 1127 mutex_enter(&sr->sr_mutex); 1128 switch (sr->sr_state) { 1129 case SMB_REQ_STATE_SUBMITTED: 1130 mutex_exit(&sr->sr_mutex); 1131 if (smb_dispatch_request(sr) < 0) { 1132 smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER); 1133 if (sr->session->s_state != 1134 SMB_SESSION_STATE_DISCONNECTED) { 1135 smb_soshutdown(sr->session->sock); 1136 sr->session->s_state = 1137 SMB_SESSION_STATE_DISCONNECTED; 1138 } 1139 smb_rwx_rwexit(&sr->session->s_lock); 1140 } 1141 mutex_enter(&sr->sr_mutex); 1142 if (!sr->sr_keep) { 1143 sr->sr_state = SMB_REQ_STATE_COMPLETED; 1144 mutex_exit(&sr->sr_mutex); 1145 smb_request_free(sr); 1146 break; 1147 } 1148 mutex_exit(&sr->sr_mutex); 1149 break; 1150 1151 default: 1152 ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED); 1153 sr->sr_state = SMB_REQ_STATE_COMPLETED; 1154 mutex_exit(&sr->sr_mutex); 1155 smb_request_free(sr); 1156 break; 1157 } 1158 } 1159 1160 /* 1161 * smb_session_disconnect_share 1162 * 1163 * Disconnects the specified share. This function should be called after the 1164 * share passed in has been made unavailable by the "share manager". 1165 */ 1166 void 1167 smb_session_disconnect_share(char *sharename) 1168 { 1169 smb_session_t *session; 1170 1171 smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx); 1172 1173 session = NULL; 1174 while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, 1175 session)) != NULL) { 1176 1177 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1178 smb_rwx_rwenter(&session->s_lock, RW_READER); 1179 switch (session->s_state) { 1180 case SMB_SESSION_STATE_NEGOTIATED: 1181 case SMB_SESSION_STATE_OPLOCK_BREAKING: 1182 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: { 1183 smb_user_t *user; 1184 smb_user_t *next; 1185 1186 user = smb_user_lookup_by_state(session, NULL); 1187 while (user) { 1188 smb_user_disconnect_share(user, sharename); 1189 next = smb_user_lookup_by_state(session, user); 1190 smb_user_release(user); 1191 user = next; 1192 } 1193 break; 1194 1195 } 1196 default: 1197 break; 1198 } 1199 smb_rwx_rwexit(&session->s_lock); 1200 } 1201 smb_svcstate_unlock(&smb_info.si_svc_sm_ctx); 1202 } 1203 1204 /* 1205 * smb_session_disconnect_volume 1206 * 1207 * This function is called when a volume is deleted. We need to ensure 1208 * all trees with a reference to the volume are destroyed before we 1209 * discard the fs_online. Before destroying each tree, we notify any 1210 * in-progress requests and give them a chance to complete. 1211 * 1212 * NOTE: 1213 * We shouldn't be accepting any new connection on this volume while 1214 * we are in this function. 1215 */ 1216 void 1217 smb_session_disconnect_volume(fs_desc_t *fsd) 1218 { 1219 smb_session_t *session; 1220 1221 smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx); 1222 1223 session = NULL; 1224 while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx, 1225 session)) != NULL) { 1226 1227 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1228 smb_rwx_rwenter(&session->s_lock, RW_READER); 1229 switch (session->s_state) { 1230 case SMB_SESSION_STATE_NEGOTIATED: 1231 case SMB_SESSION_STATE_OPLOCK_BREAKING: 1232 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: { 1233 smb_user_t *user; 1234 smb_user_t *next; 1235 1236 user = smb_user_lookup_by_state(session, NULL); 1237 while (user) { 1238 smb_user_disconnect_volume(user, fsd); 1239 next = smb_user_lookup_by_state(session, user); 1240 smb_user_release(user); 1241 user = next; 1242 } 1243 break; 1244 1245 } 1246 default: 1247 break; 1248 } 1249 smb_rwx_rwexit(&session->s_lock); 1250 } 1251 smb_svcstate_unlock(&smb_info.si_svc_sm_ctx); 1252 } 1253