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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * General Structures Layout 28 * ------------------------- 29 * 30 * This is a simplified diagram showing the relationship between most of the 31 * main structures. 32 * 33 * +-------------------+ 34 * | SMB_INFO | 35 * +-------------------+ 36 * | 37 * | 38 * v 39 * +-------------------+ +-------------------+ +-------------------+ 40 * | SESSION |<----->| SESSION |......| SESSION | 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | 43 * | 44 * v 45 * +-------------------+ +-------------------+ +-------------------+ 46 * | USER |<----->| USER |......| USER | 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | 49 * | 50 * v 51 * +-------------------+ +-------------------+ +-------------------+ 52 * | TREE |<----->| TREE |......| TREE | 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | | 55 * | | 56 * | v 57 * | +-------+ +-------+ +-------+ 58 * | | OFILE |<----->| OFILE |......| OFILE | 59 * | +-------+ +-------+ +-------+ 60 * | 61 * | 62 * v 63 * +-------+ +------+ +------+ 64 * | ODIR |<----->| ODIR |......| ODIR | 65 * +-------+ +------+ +------+ 66 * 67 * 68 * User State Machine 69 * ------------------ 70 * 71 * +-----------------------------+ T0 72 * | SMB_USER_STATE_LOGGED_IN |<----------- Creation/Allocation 73 * +-----------------------------+ 74 * | 75 * | T1 76 * | 77 * v 78 * +-----------------------------+ 79 * | SMB_USER_STATE_LOGGING_OFF | 80 * +-----------------------------+ 81 * | 82 * | T2 83 * | 84 * v 85 * +-----------------------------+ T3 86 * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free 87 * +-----------------------------+ 88 * 89 * SMB_USER_STATE_LOGGED_IN 90 * 91 * While in this state: 92 * - The user is queued in the list of users of his session. 93 * - References will be given out if the user is looked up. 94 * - The user can access files and pipes. 95 * 96 * SMB_USER_STATE_LOGGING_OFF 97 * 98 * While in this state: 99 * - The user is queued in the list of users of his session. 100 * - References will not be given out if the user is looked up. 101 * - The trees the user connected are being disconnected. 102 * - The resources associated with the user remain. 103 * 104 * SMB_USER_STATE_LOGGING_OFF 105 * 106 * While in this state: 107 * - The user is queued in the list of users of his session. 108 * - References will not be given out if the user is looked up. 109 * - The user has no more trees connected. 110 * - The resources associated with the user remain. 111 * 112 * Transition T0 113 * 114 * This transition occurs in smb_user_login(). A new user is created and 115 * added to the list of users of a session. 116 * 117 * Transition T1 118 * 119 * This transition occurs in smb_user_logoff(). 120 * 121 * Transition T2 122 * 123 * This transition occurs in smb_user_release(). The resources associated 124 * with the user are deleted as well as the user. For the transition to 125 * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the 126 * reference count be zero. 127 * 128 * Comments 129 * -------- 130 * 131 * The state machine of the user structures is controlled by 3 elements: 132 * - The list of users of the session he belongs to. 133 * - The mutex embedded in the structure itself. 134 * - The reference count. 135 * 136 * There's a mutex embedded in the user structure used to protect its fields 137 * and there's a lock embedded in the list of users of a session. To 138 * increment or to decrement the reference count the mutex must be entered. 139 * To insert the user into the list of users of the session and to remove 140 * the user from it, the lock must be entered in RW_WRITER mode. 141 * 142 * Rules of access to a user structure: 143 * 144 * 1) In order to avoid deadlocks, when both (mutex and lock of the session 145 * list) have to be entered, the lock must be entered first. 146 * 147 * 2) All actions applied to a user require a reference count. 148 * 149 * 3) There are 2 ways of getting a reference count. One is when the user 150 * logs in. The other when the user is looked up. This translates into 151 * 3 functions: smb_user_login(), smb_user_lookup_by_uid() and 152 * smb_user_lookup_by_credentials. 153 * 154 * It should be noted that the reference count of a user registers the 155 * number of references to the user in other structures (such as an smb 156 * request). The reference count is not incremented in these 2 instances: 157 * 158 * 1) The user is logged in. An user is anchored by his state. If there's 159 * no activity involving a user currently logged in, the reference 160 * count of that user is zero. 161 * 162 * 2) The user is queued in the list of users of the session. The fact of 163 * being queued in that list is NOT registered by incrementing the 164 * reference count. 165 */ 166 #include <smbsrv/smb_incl.h> 167 #include <smbsrv/smb_door_svc.h> 168 169 170 #define ADMINISTRATORS_SID "S-1-5-32-544" 171 172 static smb_sid_t *smb_admins_sid = NULL; 173 174 static void smb_user_delete(smb_user_t *user); 175 static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *); 176 177 int 178 smb_user_init(void) 179 { 180 if (smb_admins_sid != NULL) 181 return (0); 182 183 if ((smb_admins_sid = smb_sid_fromstr(ADMINISTRATORS_SID)) == NULL) 184 return (-1); 185 186 return (0); 187 } 188 189 void 190 smb_user_fini(void) 191 { 192 if (smb_admins_sid != NULL) { 193 smb_sid_free(smb_admins_sid); 194 smb_admins_sid = NULL; 195 } 196 } 197 198 /* 199 * smb_user_login 200 * 201 * 202 */ 203 smb_user_t * 204 smb_user_login( 205 smb_session_t *session, 206 cred_t *cr, 207 char *domain_name, 208 char *account_name, 209 uint32_t flags, 210 uint32_t privileges, 211 uint32_t audit_sid) 212 { 213 smb_user_t *user; 214 215 ASSERT(session); 216 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 217 ASSERT(cr); 218 ASSERT(account_name); 219 ASSERT(domain_name); 220 221 user = kmem_cache_alloc(session->s_server->si_cache_user, KM_SLEEP); 222 bzero(user, sizeof (smb_user_t)); 223 user->u_refcnt = 1; 224 user->u_session = session; 225 user->u_server = session->s_server; 226 user->u_logon_time = gethrestime_sec(); 227 user->u_flags = flags; 228 user->u_privileges = privileges; 229 user->u_name_len = strlen(account_name) + 1; 230 user->u_domain_len = strlen(domain_name) + 1; 231 user->u_name = smb_kstrdup(account_name, user->u_name_len); 232 user->u_domain = smb_kstrdup(domain_name, user->u_domain_len); 233 user->u_cred = cr; 234 user->u_audit_sid = audit_sid; 235 236 if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) { 237 if (!smb_idpool_constructor(&user->u_tid_pool)) { 238 smb_llist_constructor(&user->u_tree_list, 239 sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd)); 240 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 241 crhold(cr); 242 user->u_state = SMB_USER_STATE_LOGGED_IN; 243 user->u_magic = SMB_USER_MAGIC; 244 smb_llist_enter(&session->s_user_list, RW_WRITER); 245 smb_llist_insert_tail(&session->s_user_list, user); 246 smb_llist_exit(&session->s_user_list); 247 atomic_inc_32(&session->s_server->sv_open_users); 248 return (user); 249 } 250 smb_idpool_free(&session->s_uid_pool, user->u_uid); 251 } 252 kmem_free(user->u_name, (size_t)user->u_name_len); 253 kmem_free(user->u_domain, (size_t)user->u_domain_len); 254 kmem_cache_free(session->s_server->si_cache_user, user); 255 return (NULL); 256 } 257 258 /* 259 * Create a new user based on an existing user, used to support 260 * additional SessionSetupX requests for a user on a session. 261 * 262 * Assumes the caller has a reference on the original user from 263 * a user_lookup_by_x call. 264 */ 265 smb_user_t * 266 smb_user_dup( 267 smb_user_t *orig_user) 268 { 269 smb_user_t *user; 270 271 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 272 ASSERT(orig_user->u_refcnt); 273 274 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 275 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 276 orig_user->u_privileges, orig_user->u_audit_sid); 277 278 if (user) 279 smb_user_nonauth_logon(orig_user->u_audit_sid); 280 281 return (user); 282 } 283 284 /* 285 * smb_user_logoff 286 * 287 * 288 */ 289 void 290 smb_user_logoff( 291 smb_user_t *user) 292 { 293 ASSERT(user->u_magic == SMB_USER_MAGIC); 294 295 mutex_enter(&user->u_mutex); 296 ASSERT(user->u_refcnt); 297 switch (user->u_state) { 298 case SMB_USER_STATE_LOGGED_IN: { 299 /* 300 * The user is moved into a state indicating that the log off 301 * process has started. 302 */ 303 user->u_state = SMB_USER_STATE_LOGGING_OFF; 304 mutex_exit(&user->u_mutex); 305 atomic_dec_32(&user->u_server->sv_open_users); 306 /* 307 * All the trees hanging off of this user are disconnected. 308 */ 309 smb_user_disconnect_trees(user); 310 smb_user_auth_logoff(user->u_audit_sid); 311 mutex_enter(&user->u_mutex); 312 user->u_state = SMB_USER_STATE_LOGGED_OFF; 313 break; 314 } 315 case SMB_USER_STATE_LOGGED_OFF: 316 case SMB_USER_STATE_LOGGING_OFF: 317 break; 318 319 default: 320 ASSERT(0); 321 break; 322 } 323 mutex_exit(&user->u_mutex); 324 } 325 326 /* 327 * smb_user_logoff_all 328 * 329 * 330 */ 331 void 332 smb_user_logoff_all( 333 smb_session_t *session) 334 { 335 smb_user_t *user; 336 337 ASSERT(session); 338 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 339 340 smb_llist_enter(&session->s_user_list, RW_READER); 341 user = smb_llist_head(&session->s_user_list); 342 while (user) { 343 ASSERT(user->u_magic == SMB_USER_MAGIC); 344 ASSERT(user->u_session == session); 345 mutex_enter(&user->u_mutex); 346 switch (user->u_state) { 347 case SMB_USER_STATE_LOGGED_IN: 348 /* The user is still logged in. */ 349 user->u_refcnt++; 350 mutex_exit(&user->u_mutex); 351 smb_llist_exit(&session->s_user_list); 352 smb_user_logoff(user); 353 smb_user_release(user); 354 smb_llist_enter(&session->s_user_list, RW_READER); 355 user = smb_llist_head(&session->s_user_list); 356 break; 357 case SMB_USER_STATE_LOGGING_OFF: 358 case SMB_USER_STATE_LOGGED_OFF: 359 /* 360 * The user is logged off or logging off. 361 */ 362 mutex_exit(&user->u_mutex); 363 user = smb_llist_next(&session->s_user_list, user); 364 break; 365 default: 366 ASSERT(0); 367 mutex_exit(&user->u_mutex); 368 user = smb_llist_next(&session->s_user_list, user); 369 break; 370 } 371 } 372 smb_llist_exit(&session->s_user_list); 373 } 374 375 /* 376 * smb_user_release 377 * 378 * 379 */ 380 void 381 smb_user_release( 382 smb_user_t *user) 383 { 384 ASSERT(user->u_magic == SMB_USER_MAGIC); 385 386 mutex_enter(&user->u_mutex); 387 ASSERT(user->u_refcnt); 388 user->u_refcnt--; 389 switch (user->u_state) { 390 case SMB_USER_STATE_LOGGED_OFF: 391 if (user->u_refcnt == 0) { 392 mutex_exit(&user->u_mutex); 393 smb_user_delete(user); 394 return; 395 } 396 break; 397 398 case SMB_USER_STATE_LOGGED_IN: 399 case SMB_USER_STATE_LOGGING_OFF: 400 break; 401 402 default: 403 ASSERT(0); 404 break; 405 } 406 mutex_exit(&user->u_mutex); 407 } 408 409 /* 410 * smb_user_lookup_by_uid 411 * 412 * Find the appropriate user for this request. The request credentials 413 * set here may be overridden by the tree credentials. In domain mode, 414 * the user and tree credentials should be the same. In share mode, the 415 * tree credentials (defined in the share definition) should override 416 * the user credentials. 417 */ 418 smb_user_t * 419 smb_user_lookup_by_uid( 420 smb_session_t *session, 421 cred_t **cr, 422 uint16_t uid) 423 { 424 smb_user_t *user; 425 426 ASSERT(session); 427 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 428 ASSERT(cr); 429 430 smb_llist_enter(&session->s_user_list, RW_READER); 431 user = smb_llist_head(&session->s_user_list); 432 while (user) { 433 ASSERT(user->u_magic == SMB_USER_MAGIC); 434 ASSERT(user->u_session == session); 435 if (user->u_uid == uid) { 436 mutex_enter(&user->u_mutex); 437 switch (user->u_state) { 438 439 case SMB_USER_STATE_LOGGED_IN: 440 /* The user exists and is still logged in. */ 441 *cr = user->u_cred; 442 user->u_refcnt++; 443 mutex_exit(&user->u_mutex); 444 smb_llist_exit(&session->s_user_list); 445 return (user); 446 447 case SMB_USER_STATE_LOGGING_OFF: 448 case SMB_USER_STATE_LOGGED_OFF: 449 /* 450 * The user exists but has logged off or is in 451 * the process of logging off. 452 */ 453 mutex_exit(&user->u_mutex); 454 smb_llist_exit(&session->s_user_list); 455 return (NULL); 456 457 default: 458 ASSERT(0); 459 mutex_exit(&user->u_mutex); 460 smb_llist_exit(&session->s_user_list); 461 return (NULL); 462 } 463 } 464 user = smb_llist_next(&session->s_user_list, user); 465 } 466 smb_llist_exit(&session->s_user_list); 467 return (NULL); 468 } 469 470 /* 471 * smb_user_lookup_by_name 472 */ 473 smb_user_t * 474 smb_user_lookup_by_name(smb_session_t *session, char *domain, char *name) 475 { 476 smb_user_t *user; 477 smb_llist_t *ulist; 478 479 ulist = &session->s_user_list; 480 smb_llist_enter(ulist, RW_READER); 481 user = smb_llist_head(ulist); 482 while (user) { 483 ASSERT(user->u_magic == SMB_USER_MAGIC); 484 if (!utf8_strcasecmp(user->u_name, name) && 485 !utf8_strcasecmp(user->u_domain, domain)) { 486 mutex_enter(&user->u_mutex); 487 if (user->u_state == SMB_USER_STATE_LOGGED_IN) { 488 user->u_refcnt++; 489 mutex_exit(&user->u_mutex); 490 break; 491 } 492 mutex_exit(&user->u_mutex); 493 } 494 user = smb_llist_next(ulist, user); 495 } 496 smb_llist_exit(ulist); 497 498 return (user); 499 } 500 501 /* 502 * smb_user_lookup_by_state 503 * 504 * This function returns the first user in the logged in state. If the user 505 * provided is NULL the search starts from the beginning of the list passed 506 * in. It a user is provided the search starts just after that user. 507 */ 508 smb_user_t * 509 smb_user_lookup_by_state( 510 smb_session_t *session, 511 smb_user_t *user) 512 { 513 smb_llist_t *lst; 514 smb_user_t *next; 515 516 ASSERT(session); 517 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 518 519 lst = &session->s_user_list; 520 521 smb_llist_enter(lst, RW_READER); 522 if (user) { 523 ASSERT(user); 524 ASSERT(user->u_magic == SMB_USER_MAGIC); 525 ASSERT(user->u_refcnt); 526 next = smb_llist_next(lst, user); 527 } else { 528 next = smb_llist_head(lst); 529 } 530 while (next) { 531 ASSERT(next->u_magic == SMB_USER_MAGIC); 532 ASSERT(next->u_session == session); 533 mutex_enter(&next->u_mutex); 534 if (next->u_state == SMB_USER_STATE_LOGGED_IN) { 535 next->u_refcnt++; 536 mutex_exit(&next->u_mutex); 537 break; 538 } else { 539 ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) || 540 (next->u_state == SMB_USER_STATE_LOGGED_OFF)); 541 mutex_exit(&next->u_mutex); 542 next = smb_llist_next(lst, next); 543 } 544 } 545 smb_llist_exit(lst); 546 547 return (next); 548 } 549 550 /* 551 * Find a tree by tree-id. 552 */ 553 smb_tree_t * 554 smb_user_lookup_tree( 555 smb_user_t *user, 556 uint16_t tid) 557 558 { 559 smb_tree_t *tree; 560 561 ASSERT(user); 562 ASSERT(user->u_magic == SMB_USER_MAGIC); 563 564 smb_llist_enter(&user->u_tree_list, RW_READER); 565 tree = smb_llist_head(&user->u_tree_list); 566 567 while (tree) { 568 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 569 ASSERT(tree->t_user == user); 570 571 if (tree->t_tid == tid) { 572 if (smb_tree_hold(tree)) { 573 smb_llist_exit(&user->u_tree_list); 574 return (tree); 575 } else { 576 smb_llist_exit(&user->u_tree_list); 577 return (NULL); 578 } 579 } 580 581 tree = smb_llist_next(&user->u_tree_list, tree); 582 } 583 584 smb_llist_exit(&user->u_tree_list); 585 return (NULL); 586 } 587 588 /* 589 * Find the first connected tree that matches the specified sharename. 590 * If the specified tree is NULL the search starts from the beginning of 591 * the user's tree list. If a tree is provided the search starts just 592 * after that tree. 593 */ 594 smb_tree_t * 595 smb_user_lookup_share( 596 smb_user_t *user, 597 const char *sharename, 598 smb_tree_t *tree) 599 { 600 ASSERT(user); 601 ASSERT(user->u_magic == SMB_USER_MAGIC); 602 ASSERT(sharename); 603 604 smb_llist_enter(&user->u_tree_list, RW_READER); 605 606 if (tree) { 607 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 608 ASSERT(tree->t_user == user); 609 tree = smb_llist_next(&user->u_tree_list, tree); 610 } else { 611 tree = smb_llist_head(&user->u_tree_list); 612 } 613 614 while (tree) { 615 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 616 ASSERT(tree->t_user == user); 617 if (utf8_strcasecmp(tree->t_sharename, sharename) == 0) { 618 if (smb_tree_hold(tree)) { 619 smb_llist_exit(&user->u_tree_list); 620 return (tree); 621 } 622 } 623 tree = smb_llist_next(&user->u_tree_list, tree); 624 } 625 626 smb_llist_exit(&user->u_tree_list); 627 return (NULL); 628 } 629 630 /* 631 * Find the first connected tree that matches the specified volume name. 632 * If the specified tree is NULL the search starts from the beginning of 633 * the user's tree list. If a tree is provided the search starts just 634 * after that tree. 635 */ 636 smb_tree_t * 637 smb_user_lookup_volume( 638 smb_user_t *user, 639 const char *name, 640 smb_tree_t *tree) 641 { 642 ASSERT(user); 643 ASSERT(user->u_magic == SMB_USER_MAGIC); 644 ASSERT(name); 645 646 smb_llist_enter(&user->u_tree_list, RW_READER); 647 648 if (tree) { 649 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 650 ASSERT(tree->t_user == user); 651 tree = smb_llist_next(&user->u_tree_list, tree); 652 } else { 653 tree = smb_llist_head(&user->u_tree_list); 654 } 655 656 while (tree) { 657 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 658 ASSERT(tree->t_user == user); 659 660 if (utf8_strcasecmp(tree->t_volume, name) == 0) { 661 if (smb_tree_hold(tree)) { 662 smb_llist_exit(&user->u_tree_list); 663 return (tree); 664 } 665 } 666 667 tree = smb_llist_next(&user->u_tree_list, tree); 668 } 669 670 smb_llist_exit(&user->u_tree_list); 671 return (NULL); 672 } 673 674 /* 675 * Disconnect all trees that match the specified client process-id. 676 */ 677 void 678 smb_user_close_pid( 679 smb_user_t *user, 680 uint16_t pid) 681 { 682 smb_tree_t *tree; 683 684 ASSERT(user); 685 ASSERT(user->u_magic == SMB_USER_MAGIC); 686 687 tree = smb_user_get_tree(&user->u_tree_list, NULL); 688 while (tree) { 689 smb_tree_t *next; 690 ASSERT(tree->t_user == user); 691 smb_tree_close_pid(tree, pid); 692 next = smb_user_get_tree(&user->u_tree_list, tree); 693 smb_tree_release(tree); 694 tree = next; 695 } 696 } 697 698 /* 699 * Disconnect all trees that this user has connected. 700 */ 701 void 702 smb_user_disconnect_trees( 703 smb_user_t *user) 704 { 705 smb_tree_t *tree; 706 707 ASSERT(user); 708 ASSERT(user->u_magic == SMB_USER_MAGIC); 709 710 tree = smb_user_get_tree(&user->u_tree_list, NULL); 711 while (tree) { 712 ASSERT(tree->t_user == user); 713 smb_tree_disconnect(tree); 714 smb_tree_release(tree); 715 tree = smb_user_get_tree(&user->u_tree_list, NULL); 716 } 717 } 718 719 /* 720 * Disconnect all trees that match the specified share name. 721 */ 722 void 723 smb_user_disconnect_share( 724 smb_user_t *user, 725 const char *sharename) 726 { 727 smb_tree_t *tree; 728 smb_tree_t *next; 729 730 ASSERT(user); 731 ASSERT(user->u_magic == SMB_USER_MAGIC); 732 ASSERT(user->u_refcnt); 733 734 tree = smb_user_lookup_share(user, sharename, NULL); 735 while (tree) { 736 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 737 smb_session_cancel_requests(user->u_session, tree, NULL); 738 smb_tree_disconnect(tree); 739 next = smb_user_lookup_share(user, sharename, tree); 740 smb_tree_release(tree); 741 tree = next; 742 } 743 } 744 745 /* 746 * Determine whether or not the user is an administrator. 747 * Members of the administrators group have administrative rights. 748 */ 749 boolean_t 750 smb_user_is_admin( 751 smb_user_t *user) 752 { 753 cred_t *u_cred; 754 755 ASSERT(user); 756 u_cred = user->u_cred; 757 ASSERT(u_cred); 758 759 if (smb_admins_sid == NULL) 760 return (B_FALSE); 761 762 if (smb_cred_is_member(u_cred, smb_admins_sid)) 763 return (B_TRUE); 764 765 return (B_FALSE); 766 } 767 768 /* *************************** Static Functions ***************************** */ 769 770 /* 771 * smb_user_delete 772 */ 773 static void 774 smb_user_delete( 775 smb_user_t *user) 776 { 777 smb_session_t *session; 778 779 ASSERT(user); 780 ASSERT(user->u_magic == SMB_USER_MAGIC); 781 ASSERT(user->u_refcnt == 0); 782 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 783 784 session = user->u_session; 785 /* 786 * Let's remove the user from the list of users of the session. This 787 * has to be done before any resources associated with the user are 788 * deleted. 789 */ 790 smb_llist_enter(&session->s_user_list, RW_WRITER); 791 smb_llist_remove(&session->s_user_list, user); 792 smb_llist_exit(&session->s_user_list); 793 794 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 795 mutex_destroy(&user->u_mutex); 796 smb_llist_destructor(&user->u_tree_list); 797 smb_idpool_destructor(&user->u_tid_pool); 798 smb_idpool_free(&session->s_uid_pool, user->u_uid); 799 crfree(user->u_cred); 800 kmem_free(user->u_name, (size_t)user->u_name_len); 801 kmem_free(user->u_domain, (size_t)user->u_domain_len); 802 kmem_cache_free(user->u_server->si_cache_user, user); 803 } 804 805 /* 806 * Get the next connected tree in the list. A reference is taken on 807 * the tree, which can be released later with smb_tree_release(). 808 * 809 * If the specified tree is NULL the search starts from the beginning of 810 * the tree list. If a tree is provided the search starts just after 811 * that tree. 812 * 813 * Returns NULL if there are no connected trees in the list. 814 */ 815 static smb_tree_t * 816 smb_user_get_tree( 817 smb_llist_t *tree_list, 818 smb_tree_t *tree) 819 { 820 ASSERT(tree_list); 821 822 smb_llist_enter(tree_list, RW_READER); 823 824 if (tree) { 825 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 826 tree = smb_llist_next(tree_list, tree); 827 } else { 828 tree = smb_llist_head(tree_list); 829 } 830 831 while (tree) { 832 if (smb_tree_hold(tree)) 833 break; 834 835 tree = smb_llist_next(tree_list, tree); 836 } 837 838 smb_llist_exit(tree_list); 839 return (tree); 840 } 841