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(ksocket_t new_so, uint16_t port, smb_server_t *sv) 638 { 639 struct sockaddr_in sin; 640 socklen_t slen; 641 smb_session_t *session; 642 643 session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP); 644 bzero(session, sizeof (smb_session_t)); 645 646 if (smb_idpool_constructor(&session->s_uid_pool)) { 647 kmem_cache_free(sv->si_cache_session, session); 648 return (NULL); 649 } 650 651 session->s_kid = SMB_NEW_KID(); 652 session->s_state = SMB_SESSION_STATE_INITIALIZED; 653 session->native_os = NATIVE_OS_UNKNOWN; 654 session->opentime = lbolt64; 655 session->keep_alive = smb_keep_alive; 656 session->activity_timestamp = lbolt64; 657 658 smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t), 659 offsetof(smb_request_t, sr_session_lnd)); 660 661 smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t), 662 offsetof(smb_user_t, u_lnd)); 663 664 smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t), 665 offsetof(smb_xa_t, xa_lnd)); 666 667 smb_net_txl_constructor(&session->s_txlst); 668 669 smb_rwx_init(&session->s_lock); 670 671 if (new_so) { 672 slen = sizeof (sin); 673 674 (void) ksocket_getsockname(new_so, (struct sockaddr *)&sin, 675 &slen, CRED()); 676 session->local_ipaddr = sin.sin_addr.s_addr; 677 678 slen = sizeof (sin); 679 (void) ksocket_getpeername(new_so, (struct sockaddr *)&sin, 680 &slen, CRED()); 681 session->ipaddr = sin.sin_addr.s_addr; 682 683 session->s_local_port = port; 684 session->sock = new_so; 685 } 686 687 session->s_server = sv; 688 smb_server_get_cfg(sv, &session->s_cfg); 689 session->s_cache_request = sv->si_cache_request; 690 session->s_cache = sv->si_cache_session; 691 session->s_magic = SMB_SESSION_MAGIC; 692 return (session); 693 } 694 695 void 696 smb_session_delete(smb_session_t *session) 697 { 698 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 699 700 session->s_magic = (uint32_t)~SMB_SESSION_MAGIC; 701 702 smb_rwx_destroy(&session->s_lock); 703 smb_net_txl_destructor(&session->s_txlst); 704 smb_slist_destructor(&session->s_req_list); 705 smb_llist_destructor(&session->s_user_list); 706 smb_llist_destructor(&session->s_xa_list); 707 708 ASSERT(session->s_tree_cnt == 0); 709 ASSERT(session->s_file_cnt == 0); 710 ASSERT(session->s_dir_cnt == 0); 711 712 smb_idpool_destructor(&session->s_uid_pool); 713 kmem_cache_free(session->s_cache, session); 714 } 715 716 void 717 smb_session_cancel(smb_session_t *session) 718 { 719 smb_xa_t *xa, *nextxa; 720 721 /* All the request currently being treated must be canceled. */ 722 smb_session_cancel_requests(session, NULL, NULL); 723 724 /* 725 * We wait for the completion of all the requests associated with 726 * this session. 727 */ 728 smb_slist_wait_for_empty(&session->s_req_list); 729 730 /* 731 * At this point the reference count of the users, trees, files, 732 * directories should be zero. It should be possible to destroy them 733 * without any problem. 734 */ 735 xa = smb_llist_head(&session->s_xa_list); 736 while (xa) { 737 nextxa = smb_llist_next(&session->s_xa_list, xa); 738 smb_xa_close(xa); 739 xa = nextxa; 740 } 741 smb_user_logoff_all(session); 742 } 743 744 /* 745 * Cancel requests. If a non-null tree is specified, only requests specific 746 * to that tree will be cancelled. If a non-null sr is specified, that sr 747 * will be not be cancelled - this would typically be the caller's sr. 748 */ 749 void 750 smb_session_cancel_requests( 751 smb_session_t *session, 752 smb_tree_t *tree, 753 smb_request_t *exclude_sr) 754 { 755 smb_request_t *sr; 756 757 smb_process_session_notify_change_queue(session, tree); 758 759 smb_slist_enter(&session->s_req_list); 760 sr = smb_slist_head(&session->s_req_list); 761 762 while (sr) { 763 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 764 if ((sr != exclude_sr) && 765 (tree == NULL || sr->tid_tree == tree)) 766 smb_request_cancel(sr); 767 768 sr = smb_slist_next(&session->s_req_list, sr); 769 } 770 771 smb_slist_exit(&session->s_req_list); 772 } 773 774 void 775 smb_session_worker( 776 void *arg) 777 { 778 smb_request_t *sr; 779 780 sr = (smb_request_t *)arg; 781 782 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 783 784 785 mutex_enter(&sr->sr_mutex); 786 switch (sr->sr_state) { 787 case SMB_REQ_STATE_SUBMITTED: 788 mutex_exit(&sr->sr_mutex); 789 if (smb_dispatch_request(sr)) { 790 mutex_enter(&sr->sr_mutex); 791 sr->sr_state = SMB_REQ_STATE_COMPLETED; 792 mutex_exit(&sr->sr_mutex); 793 smb_request_free(sr); 794 } 795 break; 796 797 default: 798 ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED); 799 sr->sr_state = SMB_REQ_STATE_COMPLETED; 800 mutex_exit(&sr->sr_mutex); 801 smb_request_free(sr); 802 break; 803 } 804 } 805 806 /* 807 * smb_session_disconnect_share 808 * 809 * Disconnects the specified share. This function should be called after the 810 * share passed in has been made unavailable by the "share manager". 811 */ 812 void 813 smb_session_disconnect_share(smb_session_list_t *se, char *sharename) 814 { 815 smb_session_t *session; 816 817 rw_enter(&se->se_lock, RW_READER); 818 session = list_head(&se->se_act.lst); 819 while (session) { 820 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 821 smb_rwx_rwenter(&session->s_lock, RW_READER); 822 switch (session->s_state) { 823 case SMB_SESSION_STATE_NEGOTIATED: 824 case SMB_SESSION_STATE_OPLOCK_BREAKING: 825 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: { 826 smb_user_t *user; 827 smb_user_t *next; 828 829 user = smb_user_lookup_by_state(session, NULL); 830 while (user) { 831 smb_user_disconnect_share(user, sharename); 832 next = smb_user_lookup_by_state(session, user); 833 smb_user_release(user); 834 user = next; 835 } 836 break; 837 838 } 839 default: 840 break; 841 } 842 smb_rwx_rwexit(&session->s_lock); 843 session = list_next(&se->se_act.lst, session); 844 } 845 rw_exit(&se->se_lock); 846 } 847 848 void 849 smb_session_list_constructor(smb_session_list_t *se) 850 { 851 bzero(se, sizeof (*se)); 852 rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL); 853 list_create(&se->se_rdy.lst, sizeof (smb_session_t), 854 offsetof(smb_session_t, s_lnd)); 855 list_create(&se->se_act.lst, sizeof (smb_session_t), 856 offsetof(smb_session_t, s_lnd)); 857 } 858 859 void 860 smb_session_list_destructor(smb_session_list_t *se) 861 { 862 list_destroy(&se->se_rdy.lst); 863 list_destroy(&se->se_act.lst); 864 rw_destroy(&se->se_lock); 865 } 866 867 void 868 smb_session_list_append(smb_session_list_t *se, smb_session_t *session) 869 { 870 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 871 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 872 873 rw_enter(&se->se_lock, RW_WRITER); 874 list_insert_tail(&se->se_rdy.lst, session); 875 se->se_rdy.count++; 876 se->se_wrop++; 877 rw_exit(&se->se_lock); 878 } 879 880 void 881 smb_session_list_delete_tail(smb_session_list_t *se) 882 { 883 smb_session_t *session; 884 885 rw_enter(&se->se_lock, RW_WRITER); 886 session = list_tail(&se->se_rdy.lst); 887 if (session) { 888 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 889 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 890 list_remove(&se->se_rdy.lst, session); 891 ASSERT(se->se_rdy.count); 892 se->se_rdy.count--; 893 rw_exit(&se->se_lock); 894 smb_session_delete(session); 895 return; 896 } 897 rw_exit(&se->se_lock); 898 } 899 900 smb_session_t * 901 smb_session_list_activate_head(smb_session_list_t *se) 902 { 903 smb_session_t *session; 904 905 rw_enter(&se->se_lock, RW_WRITER); 906 session = list_head(&se->se_rdy.lst); 907 if (session) { 908 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 909 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 910 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 911 session->s_thread = curthread; 912 session->s_ktdid = session->s_thread->t_did; 913 smb_rwx_rwexit(&session->s_lock); 914 list_remove(&se->se_rdy.lst, session); 915 se->se_rdy.count--; 916 list_insert_tail(&se->se_act.lst, session); 917 se->se_act.count++; 918 se->se_wrop++; 919 } 920 rw_exit(&se->se_lock); 921 return (session); 922 } 923 924 void 925 smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session) 926 { 927 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 928 929 rw_enter(&se->se_lock, RW_WRITER); 930 931 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 932 ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED); 933 session->s_state = SMB_SESSION_STATE_TERMINATED; 934 smb_sodestroy(session->sock); 935 session->sock = NULL; 936 smb_rwx_rwexit(&session->s_lock); 937 938 list_remove(&se->se_act.lst, session); 939 se->se_act.count--; 940 se->se_wrop++; 941 942 ASSERT(session->s_thread == curthread); 943 944 rw_exit(&se->se_lock); 945 946 smb_session_delete(session); 947 } 948 949 /* 950 * smb_session_list_signal 951 * 952 * This function signals all the session threads. The intent is to terminate 953 * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete 954 * immediately. 955 * 956 * This function must only be called by the threads listening and accepting 957 * connections. They must pass in their respective session list. 958 */ 959 void 960 smb_session_list_signal(smb_session_list_t *se) 961 { 962 smb_session_t *session; 963 964 rw_enter(&se->se_lock, RW_WRITER); 965 while (session = list_head(&se->se_rdy.lst)) { 966 967 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 968 969 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 970 ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED); 971 session->s_state = SMB_SESSION_STATE_TERMINATED; 972 smb_sodestroy(session->sock); 973 session->sock = NULL; 974 smb_rwx_rwexit(&session->s_lock); 975 976 list_remove(&se->se_rdy.lst, session); 977 se->se_rdy.count--; 978 se->se_wrop++; 979 980 rw_exit(&se->se_lock); 981 smb_session_delete(session); 982 rw_enter(&se->se_lock, RW_WRITER); 983 } 984 rw_downgrade(&se->se_lock); 985 986 session = list_head(&se->se_act.lst); 987 while (session) { 988 989 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 990 tsignal(session->s_thread, SIGINT); 991 session = list_next(&se->se_act.lst, session); 992 } 993 rw_exit(&se->se_lock); 994 } 995 996 /* 997 * smb_session_lookup_user 998 */ 999 static smb_user_t * 1000 smb_session_lookup_user(smb_session_t *session, char *domain, char *name) 1001 { 1002 smb_user_t *user; 1003 smb_llist_t *ulist; 1004 1005 ulist = &session->s_user_list; 1006 smb_llist_enter(ulist, RW_READER); 1007 user = smb_llist_head(ulist); 1008 while (user) { 1009 ASSERT(user->u_magic == SMB_USER_MAGIC); 1010 if (!utf8_strcasecmp(user->u_name, name) && 1011 !utf8_strcasecmp(user->u_domain, domain)) { 1012 mutex_enter(&user->u_mutex); 1013 if (user->u_state == SMB_USER_STATE_LOGGED_IN) { 1014 user->u_refcnt++; 1015 mutex_exit(&user->u_mutex); 1016 break; 1017 } 1018 mutex_exit(&user->u_mutex); 1019 } 1020 user = smb_llist_next(ulist, user); 1021 } 1022 smb_llist_exit(ulist); 1023 1024 return (user); 1025 } 1026 1027 /* 1028 * If a user attempts to log in subsequently from the specified session, 1029 * duplicates the existing SMB user instance such that all SMB user 1030 * instances that corresponds to the same user on the given session 1031 * reference the same user's cred. 1032 * 1033 * Returns NULL if the given user hasn't yet logged in from this 1034 * specified session. Otherwise, returns a user instance that corresponds 1035 * to this subsequent login. 1036 */ 1037 smb_user_t * 1038 smb_session_dup_user(smb_session_t *session, char *domain, char *account_name) 1039 { 1040 smb_user_t *orig_user = NULL; 1041 smb_user_t *user = NULL; 1042 1043 orig_user = smb_session_lookup_user(session, domain, 1044 account_name); 1045 1046 if (orig_user) { 1047 user = smb_user_dup(orig_user); 1048 smb_user_release(orig_user); 1049 } 1050 1051 return (user); 1052 } 1053 1054 /* 1055 * smb_request_alloc 1056 * 1057 * Allocate an smb_request_t structure from the kmem_cache. Partially 1058 * initialize the found/new request. 1059 * 1060 * Returns pointer to a request 1061 */ 1062 smb_request_t * 1063 smb_request_alloc(smb_session_t *session, int req_length) 1064 { 1065 smb_request_t *sr; 1066 1067 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1068 1069 sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP); 1070 1071 /* 1072 * Future: Use constructor to pre-initialize some fields. For now 1073 * there are so many fields that it is easiest just to zero the 1074 * whole thing and start over. 1075 */ 1076 bzero(sr, sizeof (smb_request_t)); 1077 1078 mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL); 1079 sr->session = session; 1080 sr->sr_server = session->s_server; 1081 sr->sr_gmtoff = session->s_server->si_gmtoff; 1082 sr->sr_cache = session->s_server->si_cache_request; 1083 sr->sr_cfg = &session->s_cfg; 1084 sr->request_storage.forw = &sr->request_storage; 1085 sr->request_storage.back = &sr->request_storage; 1086 sr->command.max_bytes = req_length; 1087 sr->reply.max_bytes = smb_maxbufsize; 1088 sr->sr_req_length = req_length; 1089 if (req_length) 1090 sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP); 1091 sr->sr_magic = SMB_REQ_MAGIC; 1092 sr->sr_state = SMB_REQ_STATE_INITIALIZING; 1093 smb_slist_insert_tail(&session->s_req_list, sr); 1094 return (sr); 1095 } 1096 1097 /* 1098 * smb_request_free 1099 * 1100 * release the memories which have been allocated for a smb request. 1101 */ 1102 void 1103 smb_request_free(smb_request_t *sr) 1104 { 1105 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1106 ASSERT(sr->session); 1107 ASSERT(sr->fid_ofile == NULL); 1108 ASSERT(sr->sid_odir == NULL); 1109 ASSERT(sr->r_xa == NULL); 1110 1111 if (sr->tid_tree) 1112 smb_tree_release(sr->tid_tree); 1113 1114 if (sr->uid_user) 1115 smb_user_release(sr->uid_user); 1116 1117 smb_slist_remove(&sr->session->s_req_list, sr); 1118 1119 sr->session = NULL; 1120 1121 /* Release any temp storage */ 1122 smbsr_free_malloc_list(&sr->request_storage); 1123 1124 if (sr->sr_request_buf) 1125 kmem_free(sr->sr_request_buf, sr->sr_req_length); 1126 if (sr->command.chain) 1127 m_freem(sr->command.chain); 1128 if (sr->reply.chain) 1129 m_freem(sr->reply.chain); 1130 if (sr->raw_data.chain) 1131 m_freem(sr->raw_data.chain); 1132 1133 sr->sr_magic = 0; 1134 mutex_destroy(&sr->sr_mutex); 1135 kmem_cache_free(sr->sr_cache, sr); 1136 } 1137