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