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