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