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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 #include <sys/atomic.h> 25 #include <sys/strsubr.h> 26 #include <sys/synch.h> 27 #include <sys/types.h> 28 #include <sys/socketvar.h> 29 #include <sys/sdt.h> 30 #include <smbsrv/netbios.h> 31 #include <smbsrv/smb_kproto.h> 32 #include <smbsrv/string.h> 33 #include <inet/tcp.h> 34 35 static volatile uint64_t smb_kids; 36 37 uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT; 38 39 static void smb_session_cancel(smb_session_t *); 40 static int smb_session_message(smb_session_t *); 41 static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *, 42 uint8_t *, size_t); 43 static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *); 44 static void smb_session_logoff(smb_session_t *); 45 static void smb_request_init_command_mbuf(smb_request_t *sr); 46 void dump_smb_inaddr(smb_inaddr_t *ipaddr); 47 48 void 49 smb_session_timers(smb_session_list_t *se) 50 { 51 smb_session_t *session; 52 53 rw_enter(&se->se_lock, RW_READER); 54 session = list_head(&se->se_act.lst); 55 while (session) { 56 /* 57 * Walk through the table and decrement each keep_alive 58 * timer that has not timed out yet. (keepalive > 0) 59 */ 60 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 61 if (session->keep_alive && 62 (session->keep_alive != (uint32_t)-1)) 63 session->keep_alive--; 64 session = list_next(&se->se_act.lst, session); 65 } 66 rw_exit(&se->se_lock); 67 } 68 69 void 70 smb_session_correct_keep_alive_values( 71 smb_session_list_t *se, 72 uint32_t new_keep_alive) 73 { 74 smb_session_t *sn; 75 76 if (new_keep_alive == smb_keep_alive) 77 return; 78 /* 79 * keep alive == 0 means do not drop connection if it's idle 80 */ 81 smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1; 82 83 /* 84 * Walk through the table and set each session to the new keep_alive 85 * value if they have not already timed out. Block clock interrupts. 86 */ 87 rw_enter(&se->se_lock, RW_READER); 88 sn = list_head(&se->se_rdy.lst); 89 while (sn) { 90 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 91 sn->keep_alive = new_keep_alive; 92 sn = list_next(&se->se_rdy.lst, sn); 93 } 94 sn = list_head(&se->se_act.lst); 95 while (sn) { 96 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 97 if (sn->keep_alive) 98 sn->keep_alive = new_keep_alive; 99 sn = list_next(&se->se_act.lst, sn); 100 } 101 rw_exit(&se->se_lock); 102 } 103 104 /* 105 * smb_reconnection_check 106 * 107 * This function is called when a client indicates its current connection 108 * should be the only one it has with the server, as indicated by VC=0 in 109 * a SessionSetupX request. We go through the session list and destroy any 110 * stale connections for that client. 111 * 112 * Clients don't associate IP addresses and servers. So a client may make 113 * independent connections (i.e. with VC=0) to a server with multiple 114 * IP addresses. So, when checking for a reconnection, we need to include 115 * the local IP address, to which the client is connecting, when checking 116 * for stale sessions. 117 * 118 * Also check the server's NetBIOS name to support simultaneous access by 119 * multiple clients behind a NAT server. This will only work for SMB over 120 * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because 121 * there is no NetBIOS name. See also Knowledge Base article Q301673. 122 */ 123 void 124 smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess) 125 { 126 smb_session_t *sn; 127 128 rw_enter(&se->se_lock, RW_READER); 129 sn = list_head(&se->se_act.lst); 130 while (sn) { 131 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 132 if ((sn != sess) && 133 smb_inet_equal(&sn->ipaddr, &sess->ipaddr) && 134 smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr) && 135 (strcasecmp(sn->workstation, sess->workstation) == 0) && 136 (sn->opentime <= sess->opentime) && 137 (sn->s_kid < sess->s_kid)) { 138 tsignal(sn->s_thread, SIGUSR1); 139 } 140 sn = list_next(&se->se_act.lst, sn); 141 } 142 rw_exit(&se->se_lock); 143 } 144 145 /* 146 * Send a session message - supports SMB-over-NBT and SMB-over-TCP. 147 * 148 * The mbuf chain is copied into a contiguous buffer so that the whole 149 * message is submitted to smb_sosend as a single request. This should 150 * help Ethereal/Wireshark delineate the packets correctly even though 151 * TCP_NODELAY has been set on the socket. 152 * 153 * If an mbuf chain is provided, it will be freed and set to NULL here. 154 */ 155 int 156 smb_session_send(smb_session_t *session, uint8_t type, mbuf_chain_t *mbc) 157 { 158 smb_txreq_t *txr; 159 smb_xprt_t hdr; 160 int rc; 161 162 switch (session->s_state) { 163 case SMB_SESSION_STATE_DISCONNECTED: 164 case SMB_SESSION_STATE_TERMINATED: 165 if ((mbc != NULL) && (mbc->chain != NULL)) { 166 m_freem(mbc->chain); 167 mbc->chain = NULL; 168 mbc->flags = 0; 169 } 170 return (ENOTCONN); 171 default: 172 break; 173 } 174 175 txr = smb_net_txr_alloc(); 176 177 if ((mbc != NULL) && (mbc->chain != NULL)) { 178 rc = mbc_moveout(mbc, (caddr_t)&txr->tr_buf[NETBIOS_HDR_SZ], 179 sizeof (txr->tr_buf) - NETBIOS_HDR_SZ, &txr->tr_len); 180 if (rc != 0) { 181 smb_net_txr_free(txr); 182 return (rc); 183 } 184 } 185 186 hdr.xh_type = type; 187 hdr.xh_length = (uint32_t)txr->tr_len; 188 189 rc = smb_session_xprt_puthdr(session, &hdr, txr->tr_buf, 190 NETBIOS_HDR_SZ); 191 192 if (rc != 0) { 193 smb_net_txr_free(txr); 194 return (rc); 195 } 196 txr->tr_len += NETBIOS_HDR_SZ; 197 smb_server_add_txb(session->s_server, (int64_t)txr->tr_len); 198 return (smb_net_txr_send(session->sock, &session->s_txlst, txr)); 199 } 200 201 /* 202 * Read, process and respond to a NetBIOS session request. 203 * 204 * A NetBIOS session must be established for SMB-over-NetBIOS. Validate 205 * the calling and called name format and save the client NetBIOS name, 206 * which is used when a NetBIOS session is established to check for and 207 * cleanup leftover state from a previous session. 208 * 209 * Session requests are not valid for SMB-over-TCP, which is unfortunate 210 * because without the client name leftover state cannot be cleaned up 211 * if the client is behind a NAT server. 212 */ 213 static int 214 smb_session_request(struct smb_session *session) 215 { 216 int rc; 217 char *calling_name; 218 char *called_name; 219 char client_name[NETBIOS_NAME_SZ]; 220 struct mbuf_chain mbc; 221 char *names = NULL; 222 smb_wchar_t *wbuf = NULL; 223 smb_xprt_t hdr; 224 char *p; 225 int rc1, rc2; 226 227 session->keep_alive = smb_keep_alive; 228 229 if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0) 230 return (rc); 231 232 DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session, 233 smb_xprt_t *, &hdr); 234 235 if ((hdr.xh_type != SESSION_REQUEST) || 236 (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) { 237 DTRACE_PROBE1(receive__session__req__failed, 238 struct session *, session); 239 return (EINVAL); 240 } 241 242 names = kmem_alloc(hdr.xh_length, KM_SLEEP); 243 244 if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) { 245 kmem_free(names, hdr.xh_length); 246 DTRACE_PROBE1(receive__session__req__failed, 247 struct session *, session); 248 return (rc); 249 } 250 251 DTRACE_PROBE3(receive__session__req__data, struct session *, session, 252 char *, names, uint32_t, hdr.xh_length); 253 254 called_name = &names[0]; 255 calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2]; 256 257 rc1 = netbios_name_isvalid(called_name, 0); 258 rc2 = netbios_name_isvalid(calling_name, client_name); 259 260 if (rc1 == 0 || rc2 == 0) { 261 262 DTRACE_PROBE3(receive__invalid__session__req, 263 struct session *, session, char *, names, 264 uint32_t, hdr.xh_length); 265 266 kmem_free(names, hdr.xh_length); 267 MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH); 268 (void) smb_mbc_encodef(&mbc, "b", 269 DATAGRAM_INVALID_SOURCE_NAME_FORMAT); 270 (void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE, 271 &mbc); 272 return (EINVAL); 273 } 274 275 DTRACE_PROBE3(receive__session__req__calling__decoded, 276 struct session *, session, 277 char *, calling_name, char *, client_name); 278 279 /* 280 * The client NetBIOS name is in oem codepage format. 281 * We need to convert it to unicode and store it in 282 * multi-byte format. We also need to strip off any 283 * spaces added as part of the NetBIOS name encoding. 284 */ 285 wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP); 286 (void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850); 287 (void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST); 288 kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t))); 289 290 if ((p = strchr(session->workstation, ' ')) != 0) 291 *p = '\0'; 292 293 kmem_free(names, hdr.xh_length); 294 return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL)); 295 } 296 297 /* 298 * Read 4-byte header from the session socket and build an in-memory 299 * session transport header. See smb_xprt_t definition for header 300 * format information. 301 * 302 * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The 303 * first byte of the four-byte header must be 0 and the next three 304 * bytes contain the length of the remaining data. 305 */ 306 int 307 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr) 308 { 309 int rc; 310 unsigned char buf[NETBIOS_HDR_SZ]; 311 312 if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0) 313 return (rc); 314 315 switch (session->s_local_port) { 316 case IPPORT_NETBIOS_SSN: 317 ret_hdr->xh_type = buf[0]; 318 ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) | 319 ((uint32_t)buf[2] << 8) | 320 ((uint32_t)buf[3]); 321 break; 322 323 case IPPORT_SMB: 324 ret_hdr->xh_type = buf[0]; 325 326 if (ret_hdr->xh_type != 0) { 327 cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type); 328 dump_smb_inaddr(&session->ipaddr); 329 return (EPROTO); 330 } 331 332 ret_hdr->xh_length = ((uint32_t)buf[1] << 16) | 333 ((uint32_t)buf[2] << 8) | 334 ((uint32_t)buf[3]); 335 break; 336 337 default: 338 cmn_err(CE_WARN, "invalid port %u", session->s_local_port); 339 dump_smb_inaddr(&session->ipaddr); 340 return (EPROTO); 341 } 342 343 return (0); 344 } 345 346 /* 347 * Encode a transport session packet header into a 4-byte buffer. 348 * See smb_xprt_t definition for header format information. 349 */ 350 static int 351 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr, 352 uint8_t *buf, size_t buflen) 353 { 354 if (session == NULL || hdr == NULL || 355 buf == NULL || buflen < NETBIOS_HDR_SZ) { 356 return (-1); 357 } 358 359 switch (session->s_local_port) { 360 case IPPORT_NETBIOS_SSN: 361 buf[0] = hdr->xh_type; 362 buf[1] = ((hdr->xh_length >> 16) & 1); 363 buf[2] = (hdr->xh_length >> 8) & 0xff; 364 buf[3] = hdr->xh_length & 0xff; 365 break; 366 367 case IPPORT_SMB: 368 buf[0] = hdr->xh_type; 369 buf[1] = (hdr->xh_length >> 16) & 0xff; 370 buf[2] = (hdr->xh_length >> 8) & 0xff; 371 buf[3] = hdr->xh_length & 0xff; 372 break; 373 374 default: 375 cmn_err(CE_WARN, "invalid port %u", session->s_local_port); 376 dump_smb_inaddr(&session->ipaddr); 377 return (-1); 378 } 379 380 return (0); 381 } 382 383 static void 384 smb_request_init_command_mbuf(smb_request_t *sr) 385 { 386 MGET(sr->command.chain, 0, MT_DATA); 387 388 /* 389 * Setup mbuf, mimic MCLGET but use the complete packet buffer. 390 */ 391 sr->command.chain->m_ext.ext_buf = sr->sr_request_buf; 392 sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf; 393 sr->command.chain->m_len = sr->sr_req_length; 394 sr->command.chain->m_flags |= M_EXT; 395 sr->command.chain->m_ext.ext_size = sr->sr_req_length; 396 sr->command.chain->m_ext.ext_ref = &mclrefnoop; 397 398 /* 399 * Initialize the rest of the mbuf_chain fields 400 */ 401 sr->command.flags = 0; 402 sr->command.shadow_of = 0; 403 sr->command.max_bytes = sr->sr_req_length; 404 sr->command.chain_offset = 0; 405 } 406 407 /* 408 * smb_request_cancel 409 * 410 * Handle a cancel for a request properly depending on the current request 411 * state. 412 */ 413 void 414 smb_request_cancel(smb_request_t *sr) 415 { 416 mutex_enter(&sr->sr_mutex); 417 switch (sr->sr_state) { 418 419 case SMB_REQ_STATE_SUBMITTED: 420 case SMB_REQ_STATE_ACTIVE: 421 case SMB_REQ_STATE_CLEANED_UP: 422 sr->sr_state = SMB_REQ_STATE_CANCELED; 423 break; 424 425 case SMB_REQ_STATE_WAITING_LOCK: 426 /* 427 * This request is waiting on a lock. Wakeup everything 428 * waiting on the lock so that the relevant thread regains 429 * control and notices that is has been canceled. The 430 * other lock request threads waiting on this lock will go 431 * back to sleep when they discover they are still blocked. 432 */ 433 sr->sr_state = SMB_REQ_STATE_CANCELED; 434 435 ASSERT(sr->sr_awaiting != NULL); 436 mutex_enter(&sr->sr_awaiting->l_mutex); 437 cv_broadcast(&sr->sr_awaiting->l_cv); 438 mutex_exit(&sr->sr_awaiting->l_mutex); 439 break; 440 441 case SMB_REQ_STATE_WAITING_EVENT: 442 case SMB_REQ_STATE_EVENT_OCCURRED: 443 /* 444 * Cancellations for these states are handled by the 445 * notify-change code 446 */ 447 break; 448 449 case SMB_REQ_STATE_COMPLETED: 450 case SMB_REQ_STATE_CANCELED: 451 /* 452 * No action required for these states since the request 453 * is completing. 454 */ 455 break; 456 /* 457 * Cases included: 458 * SMB_REQ_STATE_FREE: 459 * SMB_REQ_STATE_INITIALIZING: 460 */ 461 default: 462 SMB_PANIC(); 463 } 464 mutex_exit(&sr->sr_mutex); 465 } 466 467 /* 468 * This is the entry point for processing SMB messages over NetBIOS or 469 * SMB-over-TCP. 470 * 471 * NetBIOS connections require a session request to establish a session 472 * on which to send session messages. 473 * 474 * Session requests are not valid on SMB-over-TCP. We don't need to do 475 * anything here as session requests will be treated as an error when 476 * handling session messages. 477 */ 478 int 479 smb_session_daemon(smb_session_list_t *se) 480 { 481 int rc = 0; 482 smb_session_t *session; 483 484 session = smb_session_list_activate_head(se); 485 if (session == NULL) 486 return (EINVAL); 487 488 if (session->s_local_port == IPPORT_NETBIOS_SSN) { 489 rc = smb_session_request(session); 490 if (rc) { 491 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 492 session->s_state = SMB_SESSION_STATE_DISCONNECTED; 493 smb_rwx_rwexit(&session->s_lock); 494 smb_session_list_terminate(se, session); 495 return (rc); 496 } 497 } 498 499 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 500 session->s_state = SMB_SESSION_STATE_ESTABLISHED; 501 smb_rwx_rwexit(&session->s_lock); 502 503 rc = smb_session_message(session); 504 505 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 506 session->s_state = SMB_SESSION_STATE_DISCONNECTED; 507 smb_rwx_rwexit(&session->s_lock); 508 509 smb_soshutdown(session->sock); 510 511 DTRACE_PROBE2(session__drop, struct session *, session, int, rc); 512 513 smb_session_cancel(session); 514 515 /* 516 * At this point everything related to the session should have been 517 * cleaned up and we expect that nothing will attempt to use the 518 * socket. 519 */ 520 smb_session_list_terminate(se, session); 521 522 return (rc); 523 } 524 525 /* 526 * Read and process SMB requests. 527 * 528 * Returns: 529 * 0 Success 530 * 1 Unable to read transport header 531 * 2 Invalid transport header type 532 * 3 Invalid SMB length (too small) 533 * 4 Unable to read SMB header 534 * 5 Invalid SMB header (bad magic number) 535 * 6 Unable to read SMB data 536 * 2x Write raw failed 537 */ 538 static int 539 smb_session_message(smb_session_t *session) 540 { 541 smb_server_t *sv; 542 smb_request_t *sr = NULL; 543 smb_xprt_t hdr; 544 uint8_t *req_buf; 545 uint32_t resid; 546 int rc; 547 548 sv = session->s_server; 549 550 for (;;) { 551 552 rc = smb_session_xprt_gethdr(session, &hdr); 553 if (rc) 554 return (rc); 555 556 DTRACE_PROBE2(session__receive__xprthdr, session_t *, session, 557 smb_xprt_t *, &hdr); 558 559 if (hdr.xh_type != SESSION_MESSAGE) { 560 /* 561 * Anything other than SESSION_MESSAGE or 562 * SESSION_KEEP_ALIVE is an error. A SESSION_REQUEST 563 * may indicate a new session request but we need to 564 * close this session and we can treat it as an error 565 * here. 566 */ 567 if (hdr.xh_type == SESSION_KEEP_ALIVE) { 568 session->keep_alive = smb_keep_alive; 569 continue; 570 } 571 return (EPROTO); 572 } 573 574 if (hdr.xh_length < SMB_HEADER_LEN) 575 return (EPROTO); 576 577 session->keep_alive = smb_keep_alive; 578 /* 579 * Allocate a request context, read the SMB header and validate 580 * it. The sr includes a buffer large enough to hold the SMB 581 * request payload. If the header looks valid, read any 582 * remaining data. 583 */ 584 sr = smb_request_alloc(session, hdr.xh_length); 585 586 req_buf = (uint8_t *)sr->sr_request_buf; 587 resid = hdr.xh_length; 588 589 rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN); 590 if (rc) { 591 smb_request_free(sr); 592 return (rc); 593 } 594 595 if (SMB_PROTOCOL_MAGIC_INVALID(sr)) { 596 smb_request_free(sr); 597 return (EPROTO); 598 } 599 600 if (resid > SMB_HEADER_LEN) { 601 req_buf += SMB_HEADER_LEN; 602 resid -= SMB_HEADER_LEN; 603 604 rc = smb_sorecv(session->sock, req_buf, resid); 605 if (rc) { 606 smb_request_free(sr); 607 return (rc); 608 } 609 } 610 smb_server_add_rxb(sv, 611 (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ)); 612 /* 613 * Initialize command MBC to represent the received data. 614 */ 615 smb_request_init_command_mbuf(sr); 616 617 DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr); 618 619 /* 620 * If this is a raw write, hand off the request. The handler 621 * will retrieve the remaining raw data and process the request. 622 */ 623 if (SMB_IS_WRITERAW(sr)) { 624 rc = smb_handle_write_raw(session, sr); 625 if (rc == 0) 626 continue; 627 return (rc); 628 } 629 if (sr->session->signing.flags & SMB_SIGNING_ENABLED) { 630 if (SMB_IS_NT_CANCEL(sr)) { 631 sr->session->signing.seqnum++; 632 sr->sr_seqnum = sr->session->signing.seqnum + 1; 633 sr->reply_seqnum = 0; 634 } else { 635 sr->session->signing.seqnum += 2; 636 sr->sr_seqnum = sr->session->signing.seqnum; 637 sr->reply_seqnum = sr->sr_seqnum + 1; 638 } 639 } 640 sr->sr_time_submitted = gethrtime(); 641 sr->sr_state = SMB_REQ_STATE_SUBMITTED; 642 smb_srqueue_waitq_enter(session->s_srqueue); 643 (void) taskq_dispatch(session->s_server->sv_thread_pool, 644 smb_session_worker, sr, TQ_SLEEP); 645 } 646 } 647 648 /* 649 * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB. 650 */ 651 smb_session_t * 652 smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv, 653 int family) 654 { 655 struct sockaddr_in sin; 656 socklen_t slen; 657 struct sockaddr_in6 sin6; 658 smb_session_t *session; 659 int64_t now; 660 661 session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP); 662 bzero(session, sizeof (smb_session_t)); 663 664 if (smb_idpool_constructor(&session->s_uid_pool)) { 665 kmem_cache_free(sv->si_cache_session, session); 666 return (NULL); 667 } 668 669 now = ddi_get_lbolt64(); 670 671 session->s_kid = SMB_NEW_KID(); 672 session->s_state = SMB_SESSION_STATE_INITIALIZED; 673 session->native_os = NATIVE_OS_UNKNOWN; 674 session->opentime = now; 675 session->keep_alive = smb_keep_alive; 676 session->activity_timestamp = now; 677 678 smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t), 679 offsetof(smb_request_t, sr_session_lnd)); 680 681 smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t), 682 offsetof(smb_user_t, u_lnd)); 683 684 smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t), 685 offsetof(smb_xa_t, xa_lnd)); 686 687 list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t), 688 offsetof(mbuf_chain_t, mbc_lnd)); 689 690 smb_net_txl_constructor(&session->s_txlst); 691 692 smb_rwx_init(&session->s_lock); 693 694 if (new_so != NULL) { 695 if (family == AF_INET) { 696 slen = sizeof (sin); 697 (void) ksocket_getsockname(new_so, 698 (struct sockaddr *)&sin, &slen, CRED()); 699 bcopy(&sin.sin_addr, 700 &session->local_ipaddr.au_addr.au_ipv4, 701 sizeof (in_addr_t)); 702 slen = sizeof (sin); 703 (void) ksocket_getpeername(new_so, 704 (struct sockaddr *)&sin, &slen, CRED()); 705 bcopy(&sin.sin_addr, 706 &session->ipaddr.au_addr.au_ipv4, 707 sizeof (in_addr_t)); 708 } else { 709 slen = sizeof (sin6); 710 (void) ksocket_getsockname(new_so, 711 (struct sockaddr *)&sin6, &slen, CRED()); 712 bcopy(&sin6.sin6_addr, 713 &session->local_ipaddr.au_addr.au_ipv6, 714 sizeof (in6_addr_t)); 715 slen = sizeof (sin6); 716 (void) ksocket_getpeername(new_so, 717 (struct sockaddr *)&sin6, &slen, CRED()); 718 bcopy(&sin6.sin6_addr, 719 &session->ipaddr.au_addr.au_ipv6, 720 sizeof (in6_addr_t)); 721 } 722 session->ipaddr.a_family = family; 723 session->local_ipaddr.a_family = family; 724 session->s_local_port = port; 725 session->sock = new_so; 726 if (port == IPPORT_NETBIOS_SSN) 727 smb_server_inc_nbt_sess(sv); 728 else 729 smb_server_inc_tcp_sess(sv); 730 } 731 session->s_server = sv; 732 smb_server_get_cfg(sv, &session->s_cfg); 733 session->s_srqueue = &sv->sv_srqueue; 734 735 session->s_cache_request = sv->si_cache_request; 736 session->s_cache = sv->si_cache_session; 737 session->s_magic = SMB_SESSION_MAGIC; 738 return (session); 739 } 740 741 void 742 smb_session_delete(smb_session_t *session) 743 { 744 mbuf_chain_t *mbc; 745 746 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 747 748 session->s_magic = 0; 749 750 if (session->s_local_port == IPPORT_NETBIOS_SSN) 751 smb_server_dec_nbt_sess(session->s_server); 752 else 753 smb_server_dec_tcp_sess(session->s_server); 754 755 smb_rwx_destroy(&session->s_lock); 756 smb_net_txl_destructor(&session->s_txlst); 757 758 while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) { 759 SMB_MBC_VALID(mbc); 760 list_remove(&session->s_oplock_brkreqs, mbc); 761 smb_mbc_free(mbc); 762 } 763 list_destroy(&session->s_oplock_brkreqs); 764 765 smb_slist_destructor(&session->s_req_list); 766 smb_llist_destructor(&session->s_user_list); 767 smb_llist_destructor(&session->s_xa_list); 768 769 ASSERT(session->s_tree_cnt == 0); 770 ASSERT(session->s_file_cnt == 0); 771 ASSERT(session->s_dir_cnt == 0); 772 773 smb_idpool_destructor(&session->s_uid_pool); 774 kmem_cache_free(session->s_cache, session); 775 } 776 777 static void 778 smb_session_cancel(smb_session_t *session) 779 { 780 smb_xa_t *xa, *nextxa; 781 782 /* All the request currently being treated must be canceled. */ 783 smb_session_cancel_requests(session, NULL, NULL); 784 785 /* 786 * We wait for the completion of all the requests associated with 787 * this session. 788 */ 789 smb_slist_wait_for_empty(&session->s_req_list); 790 791 /* 792 * At this point the reference count of the users, trees, files, 793 * directories should be zero. It should be possible to destroy them 794 * without any problem. 795 */ 796 xa = smb_llist_head(&session->s_xa_list); 797 while (xa) { 798 nextxa = smb_llist_next(&session->s_xa_list, xa); 799 smb_xa_close(xa); 800 xa = nextxa; 801 } 802 803 smb_session_logoff(session); 804 } 805 806 /* 807 * Cancel requests. If a non-null tree is specified, only requests specific 808 * to that tree will be cancelled. If a non-null sr is specified, that sr 809 * will be not be cancelled - this would typically be the caller's sr. 810 */ 811 void 812 smb_session_cancel_requests( 813 smb_session_t *session, 814 smb_tree_t *tree, 815 smb_request_t *exclude_sr) 816 { 817 smb_request_t *sr; 818 819 smb_process_session_notify_change_queue(session, tree); 820 821 smb_slist_enter(&session->s_req_list); 822 sr = smb_slist_head(&session->s_req_list); 823 824 while (sr) { 825 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 826 if ((sr != exclude_sr) && 827 (tree == NULL || sr->tid_tree == tree)) 828 smb_request_cancel(sr); 829 830 sr = smb_slist_next(&session->s_req_list, sr); 831 } 832 833 smb_slist_exit(&session->s_req_list); 834 } 835 836 void 837 smb_session_worker(void *arg) 838 { 839 smb_request_t *sr; 840 smb_srqueue_t *srq; 841 842 sr = (smb_request_t *)arg; 843 SMB_REQ_VALID(sr); 844 845 srq = sr->session->s_srqueue; 846 smb_srqueue_waitq_to_runq(srq); 847 sr->sr_worker = curthread; 848 mutex_enter(&sr->sr_mutex); 849 sr->sr_time_active = gethrtime(); 850 switch (sr->sr_state) { 851 case SMB_REQ_STATE_SUBMITTED: 852 mutex_exit(&sr->sr_mutex); 853 if (smb_dispatch_request(sr)) { 854 mutex_enter(&sr->sr_mutex); 855 sr->sr_state = SMB_REQ_STATE_COMPLETED; 856 mutex_exit(&sr->sr_mutex); 857 smb_request_free(sr); 858 } 859 break; 860 861 default: 862 ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED); 863 sr->sr_state = SMB_REQ_STATE_COMPLETED; 864 mutex_exit(&sr->sr_mutex); 865 smb_request_free(sr); 866 break; 867 } 868 smb_srqueue_runq_exit(srq); 869 } 870 871 void 872 smb_session_list_constructor(smb_session_list_t *se) 873 { 874 bzero(se, sizeof (*se)); 875 rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL); 876 list_create(&se->se_rdy.lst, sizeof (smb_session_t), 877 offsetof(smb_session_t, s_lnd)); 878 list_create(&se->se_act.lst, sizeof (smb_session_t), 879 offsetof(smb_session_t, s_lnd)); 880 } 881 882 void 883 smb_session_list_destructor(smb_session_list_t *se) 884 { 885 list_destroy(&se->se_rdy.lst); 886 list_destroy(&se->se_act.lst); 887 rw_destroy(&se->se_lock); 888 } 889 890 void 891 smb_session_list_append(smb_session_list_t *se, smb_session_t *session) 892 { 893 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 894 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 895 896 rw_enter(&se->se_lock, RW_WRITER); 897 list_insert_tail(&se->se_rdy.lst, session); 898 se->se_rdy.count++; 899 se->se_wrop++; 900 rw_exit(&se->se_lock); 901 } 902 903 void 904 smb_session_list_delete_tail(smb_session_list_t *se) 905 { 906 smb_session_t *session; 907 908 rw_enter(&se->se_lock, RW_WRITER); 909 session = list_tail(&se->se_rdy.lst); 910 if (session) { 911 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 912 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 913 list_remove(&se->se_rdy.lst, session); 914 ASSERT(se->se_rdy.count); 915 se->se_rdy.count--; 916 rw_exit(&se->se_lock); 917 smb_session_delete(session); 918 return; 919 } 920 rw_exit(&se->se_lock); 921 } 922 923 smb_session_t * 924 smb_session_list_activate_head(smb_session_list_t *se) 925 { 926 smb_session_t *session; 927 928 rw_enter(&se->se_lock, RW_WRITER); 929 session = list_head(&se->se_rdy.lst); 930 if (session) { 931 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 932 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 933 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 934 session->s_thread = curthread; 935 session->s_ktdid = session->s_thread->t_did; 936 smb_rwx_rwexit(&session->s_lock); 937 list_remove(&se->se_rdy.lst, session); 938 se->se_rdy.count--; 939 list_insert_tail(&se->se_act.lst, session); 940 se->se_act.count++; 941 se->se_wrop++; 942 } 943 rw_exit(&se->se_lock); 944 return (session); 945 } 946 947 void 948 smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session) 949 { 950 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 951 952 rw_enter(&se->se_lock, RW_WRITER); 953 954 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 955 ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED); 956 session->s_state = SMB_SESSION_STATE_TERMINATED; 957 smb_sodestroy(session->sock); 958 session->sock = NULL; 959 smb_rwx_rwexit(&session->s_lock); 960 961 list_remove(&se->se_act.lst, session); 962 se->se_act.count--; 963 se->se_wrop++; 964 965 ASSERT(session->s_thread == curthread); 966 967 rw_exit(&se->se_lock); 968 969 smb_session_delete(session); 970 } 971 972 /* 973 * smb_session_list_signal 974 * 975 * This function signals all the session threads. The intent is to terminate 976 * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete 977 * immediately. 978 * 979 * This function must only be called by the threads listening and accepting 980 * connections. They must pass in their respective session list. 981 */ 982 void 983 smb_session_list_signal(smb_session_list_t *se) 984 { 985 smb_session_t *session; 986 987 rw_enter(&se->se_lock, RW_WRITER); 988 while (session = list_head(&se->se_rdy.lst)) { 989 990 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 991 992 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 993 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 994 session->s_state = SMB_SESSION_STATE_TERMINATED; 995 smb_sodestroy(session->sock); 996 session->sock = NULL; 997 smb_rwx_rwexit(&session->s_lock); 998 999 list_remove(&se->se_rdy.lst, session); 1000 se->se_rdy.count--; 1001 se->se_wrop++; 1002 1003 rw_exit(&se->se_lock); 1004 smb_session_delete(session); 1005 rw_enter(&se->se_lock, RW_WRITER); 1006 } 1007 rw_downgrade(&se->se_lock); 1008 1009 session = list_head(&se->se_act.lst); 1010 while (session) { 1011 1012 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1013 tsignal(session->s_thread, SIGUSR1); 1014 session = list_next(&se->se_act.lst, session); 1015 } 1016 rw_exit(&se->se_lock); 1017 } 1018 1019 /* 1020 * smb_session_lookup_user 1021 */ 1022 static smb_user_t * 1023 smb_session_lookup_user(smb_session_t *session, char *domain, char *name) 1024 { 1025 smb_user_t *user; 1026 smb_llist_t *ulist; 1027 1028 ulist = &session->s_user_list; 1029 smb_llist_enter(ulist, RW_READER); 1030 user = smb_llist_head(ulist); 1031 while (user) { 1032 ASSERT(user->u_magic == SMB_USER_MAGIC); 1033 if (!smb_strcasecmp(user->u_name, name, 0) && 1034 !smb_strcasecmp(user->u_domain, domain, 0)) { 1035 if (smb_user_hold(user)) 1036 break; 1037 } 1038 user = smb_llist_next(ulist, user); 1039 } 1040 smb_llist_exit(ulist); 1041 1042 return (user); 1043 } 1044 1045 /* 1046 * If a user attempts to log in subsequently from the specified session, 1047 * duplicates the existing SMB user instance such that all SMB user 1048 * instances that corresponds to the same user on the given session 1049 * reference the same user's cred. 1050 * 1051 * Returns NULL if the given user hasn't yet logged in from this 1052 * specified session. Otherwise, returns a user instance that corresponds 1053 * to this subsequent login. 1054 */ 1055 smb_user_t * 1056 smb_session_dup_user(smb_session_t *session, char *domain, char *account_name) 1057 { 1058 smb_user_t *orig_user = NULL; 1059 smb_user_t *user = NULL; 1060 1061 orig_user = smb_session_lookup_user(session, domain, 1062 account_name); 1063 1064 if (orig_user) { 1065 user = smb_user_dup(orig_user); 1066 smb_user_release(orig_user); 1067 } 1068 1069 return (user); 1070 } 1071 1072 /* 1073 * Find a user on the specified session by SMB UID. 1074 */ 1075 smb_user_t * 1076 smb_session_lookup_uid(smb_session_t *session, uint16_t uid) 1077 { 1078 smb_user_t *user; 1079 smb_llist_t *user_list; 1080 1081 SMB_SESSION_VALID(session); 1082 1083 user_list = &session->s_user_list; 1084 smb_llist_enter(user_list, RW_READER); 1085 1086 user = smb_llist_head(user_list); 1087 while (user) { 1088 SMB_USER_VALID(user); 1089 ASSERT(user->u_session == session); 1090 1091 if (user->u_uid == uid) { 1092 if (!smb_user_hold(user)) 1093 break; 1094 1095 smb_llist_exit(user_list); 1096 return (user); 1097 } 1098 1099 user = smb_llist_next(user_list, user); 1100 } 1101 1102 smb_llist_exit(user_list); 1103 return (NULL); 1104 } 1105 1106 void 1107 smb_session_post_user(smb_session_t *session, smb_user_t *user) 1108 { 1109 SMB_USER_VALID(user); 1110 ASSERT(user->u_refcnt == 0); 1111 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 1112 ASSERT(user->u_session == session); 1113 1114 smb_llist_post(&session->s_user_list, user, smb_user_delete); 1115 } 1116 1117 /* 1118 * Logoff all users associated with the specified session. 1119 */ 1120 static void 1121 smb_session_logoff(smb_session_t *session) 1122 { 1123 smb_user_t *user; 1124 1125 SMB_SESSION_VALID(session); 1126 1127 smb_llist_enter(&session->s_user_list, RW_READER); 1128 1129 user = smb_llist_head(&session->s_user_list); 1130 while (user) { 1131 SMB_USER_VALID(user); 1132 ASSERT(user->u_session == session); 1133 1134 if (smb_user_hold(user)) { 1135 smb_user_logoff(user); 1136 smb_user_release(user); 1137 } 1138 1139 user = smb_llist_next(&session->s_user_list, user); 1140 } 1141 1142 smb_llist_exit(&session->s_user_list); 1143 } 1144 1145 /* 1146 * Disconnect any trees associated with the specified share. 1147 * Iterate through the users on this session and tell each user 1148 * to disconnect from the share. 1149 */ 1150 void 1151 smb_session_disconnect_share(smb_session_t *session, const char *sharename) 1152 { 1153 smb_user_t *user; 1154 1155 SMB_SESSION_VALID(session); 1156 1157 smb_llist_enter(&session->s_user_list, RW_READER); 1158 1159 user = smb_llist_head(&session->s_user_list); 1160 while (user) { 1161 SMB_USER_VALID(user); 1162 ASSERT(user->u_session == session); 1163 1164 if (smb_user_hold(user)) { 1165 smb_user_disconnect_share(user, sharename); 1166 smb_user_release(user); 1167 } 1168 1169 user = smb_llist_next(&session->s_user_list, user); 1170 } 1171 1172 smb_llist_exit(&session->s_user_list); 1173 } 1174 1175 /* 1176 * Copy the session workstation/client name to buf. If the workstation 1177 * is an empty string (which it will be on TCP connections), use the 1178 * client IP address. 1179 */ 1180 void 1181 smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen) 1182 { 1183 char ipbuf[INET6_ADDRSTRLEN]; 1184 smb_inaddr_t *ipaddr; 1185 1186 ASSERT(sn); 1187 ASSERT(buf); 1188 ASSERT(buflen); 1189 1190 *buf = '\0'; 1191 1192 if (sn->workstation[0] != '\0') { 1193 (void) strlcpy(buf, sn->workstation, buflen); 1194 return; 1195 } 1196 1197 ipaddr = &sn->ipaddr; 1198 if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family))) 1199 (void) strlcpy(buf, ipbuf, buflen); 1200 } 1201 1202 /* 1203 * Check whether or not the specified client name is the client of this 1204 * session. The name may be in UNC format (\\CLIENT). 1205 * 1206 * A workstation/client name is setup on NBT connections as part of the 1207 * NetBIOS session request but that isn't available on TCP connections. 1208 * If the session doesn't have a client name we typically return the 1209 * client IP address as the workstation name on MSRPC requests. So we 1210 * check for the IP address here in addition to the workstation name. 1211 */ 1212 boolean_t 1213 smb_session_isclient(smb_session_t *sn, const char *client) 1214 { 1215 char buf[INET6_ADDRSTRLEN]; 1216 smb_inaddr_t *ipaddr; 1217 1218 client += strspn(client, "\\"); 1219 1220 if (smb_strcasecmp(client, sn->workstation, 0) == 0) 1221 return (B_TRUE); 1222 1223 ipaddr = &sn->ipaddr; 1224 if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL) 1225 return (B_FALSE); 1226 1227 if (smb_strcasecmp(client, buf, 0) == 0) 1228 return (B_TRUE); 1229 1230 return (B_FALSE); 1231 } 1232 1233 /* 1234 * smb_request_alloc 1235 * 1236 * Allocate an smb_request_t structure from the kmem_cache. Partially 1237 * initialize the found/new request. 1238 * 1239 * Returns pointer to a request 1240 */ 1241 smb_request_t * 1242 smb_request_alloc(smb_session_t *session, int req_length) 1243 { 1244 smb_request_t *sr; 1245 1246 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1247 1248 sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP); 1249 1250 /* 1251 * Future: Use constructor to pre-initialize some fields. For now 1252 * there are so many fields that it is easiest just to zero the 1253 * whole thing and start over. 1254 */ 1255 bzero(sr, sizeof (smb_request_t)); 1256 1257 mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL); 1258 smb_srm_init(sr); 1259 sr->session = session; 1260 sr->sr_server = session->s_server; 1261 sr->sr_gmtoff = session->s_server->si_gmtoff; 1262 sr->sr_cache = session->s_server->si_cache_request; 1263 sr->sr_cfg = &session->s_cfg; 1264 sr->command.max_bytes = req_length; 1265 sr->reply.max_bytes = smb_maxbufsize; 1266 sr->sr_req_length = req_length; 1267 if (req_length) 1268 sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP); 1269 sr->sr_magic = SMB_REQ_MAGIC; 1270 sr->sr_state = SMB_REQ_STATE_INITIALIZING; 1271 smb_slist_insert_tail(&session->s_req_list, sr); 1272 return (sr); 1273 } 1274 1275 /* 1276 * smb_request_free 1277 * 1278 * release the memories which have been allocated for a smb request. 1279 */ 1280 void 1281 smb_request_free(smb_request_t *sr) 1282 { 1283 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1284 ASSERT(sr->session); 1285 ASSERT(sr->r_xa == NULL); 1286 1287 if (sr->fid_ofile != NULL) 1288 smb_ofile_release(sr->fid_ofile); 1289 1290 if (sr->tid_tree != NULL) 1291 smb_tree_release(sr->tid_tree); 1292 1293 if (sr->uid_user != NULL) 1294 smb_user_release(sr->uid_user); 1295 1296 smb_slist_remove(&sr->session->s_req_list, sr); 1297 1298 sr->session = NULL; 1299 1300 smb_srm_fini(sr); 1301 1302 if (sr->sr_request_buf) 1303 kmem_free(sr->sr_request_buf, sr->sr_req_length); 1304 if (sr->command.chain) 1305 m_freem(sr->command.chain); 1306 if (sr->reply.chain) 1307 m_freem(sr->reply.chain); 1308 if (sr->raw_data.chain) 1309 m_freem(sr->raw_data.chain); 1310 1311 sr->sr_magic = 0; 1312 mutex_destroy(&sr->sr_mutex); 1313 kmem_cache_free(sr->sr_cache, sr); 1314 } 1315 1316 void 1317 dump_smb_inaddr(smb_inaddr_t *ipaddr) 1318 { 1319 char ipstr[INET6_ADDRSTRLEN]; 1320 1321 if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family))) 1322 cmn_err(CE_WARN, "error ipstr=%s", ipstr); 1323 else 1324 cmn_err(CE_WARN, "error converting ip address"); 1325 } 1326 1327 boolean_t 1328 smb_session_oplocks_enable(smb_session_t *session) 1329 { 1330 SMB_SESSION_VALID(session); 1331 if (session->s_cfg.skc_oplock_enable == 0) 1332 return (B_FALSE); 1333 else 1334 return (B_TRUE); 1335 } 1336 1337 /* 1338 * smb_session_breaking_oplock 1339 * 1340 * This MUST be a cross-session call, i.e. the caller must be in a different 1341 * context than the one passed. The mutex of the SMB node requiring an oplock 1342 * break MUST be dropped before calling this function. This last requirement is 1343 * due to a potential deadlock that can occur when trying to enter the lock of 1344 * the session passed in. 1345 */ 1346 void 1347 smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of) 1348 { 1349 mbuf_chain_t *mbc; 1350 1351 SMB_SESSION_VALID(session); 1352 1353 mbc = smb_mbc_alloc(MLEN); 1354 1355 (void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.", 1356 SMB_COM_LOCKING_ANDX, 1357 SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)), 1358 0xFFFF, 0, 0xFFFF, 8, 0xFF, 1359 SMB_OFILE_GET_FID(of), 1360 LOCKING_ANDX_OPLOCK_RELEASE); 1361 1362 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 1363 switch (session->s_state) { 1364 case SMB_SESSION_STATE_NEGOTIATED: 1365 case SMB_SESSION_STATE_OPLOCK_BREAKING: 1366 session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING; 1367 (void) smb_session_send(session, 0, mbc); 1368 smb_mbc_free(mbc); 1369 break; 1370 1371 case SMB_SESSION_STATE_READ_RAW_ACTIVE: 1372 list_insert_tail(&session->s_oplock_brkreqs, mbc); 1373 break; 1374 1375 case SMB_SESSION_STATE_DISCONNECTED: 1376 case SMB_SESSION_STATE_TERMINATED: 1377 smb_mbc_free(mbc); 1378 break; 1379 1380 default: 1381 SMB_PANIC(); 1382 } 1383 smb_rwx_rwexit(&session->s_lock); 1384 } 1385