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