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