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