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