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_privcred = smb_cred_create_privs(cr, privileges); 235 user->u_audit_sid = audit_sid; 236 237 if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) { 238 if (!smb_idpool_constructor(&user->u_tid_pool)) { 239 smb_llist_constructor(&user->u_tree_list, 240 sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd)); 241 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 242 crhold(user->u_cred); 243 if (user->u_privcred) 244 crhold(user->u_privcred); 245 user->u_state = SMB_USER_STATE_LOGGED_IN; 246 user->u_magic = SMB_USER_MAGIC; 247 smb_llist_enter(&session->s_user_list, RW_WRITER); 248 smb_llist_insert_tail(&session->s_user_list, user); 249 smb_llist_exit(&session->s_user_list); 250 atomic_inc_32(&session->s_server->sv_open_users); 251 return (user); 252 } 253 smb_idpool_free(&session->s_uid_pool, user->u_uid); 254 } 255 kmem_free(user->u_name, (size_t)user->u_name_len); 256 kmem_free(user->u_domain, (size_t)user->u_domain_len); 257 kmem_cache_free(session->s_server->si_cache_user, user); 258 return (NULL); 259 } 260 261 /* 262 * Create a new user based on an existing user, used to support 263 * additional SessionSetupX requests for a user on a session. 264 * 265 * Assumes the caller has a reference on the original user from 266 * a user_lookup_by_x call. 267 */ 268 smb_user_t * 269 smb_user_dup( 270 smb_user_t *orig_user) 271 { 272 smb_user_t *user; 273 274 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 275 ASSERT(orig_user->u_refcnt); 276 277 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 278 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 279 orig_user->u_privileges, orig_user->u_audit_sid); 280 281 if (user) 282 smb_user_nonauth_logon(orig_user->u_audit_sid); 283 284 return (user); 285 } 286 287 /* 288 * smb_user_logoff 289 * 290 * 291 */ 292 void 293 smb_user_logoff( 294 smb_user_t *user) 295 { 296 ASSERT(user->u_magic == SMB_USER_MAGIC); 297 298 mutex_enter(&user->u_mutex); 299 ASSERT(user->u_refcnt); 300 switch (user->u_state) { 301 case SMB_USER_STATE_LOGGED_IN: { 302 /* 303 * The user is moved into a state indicating that the log off 304 * process has started. 305 */ 306 user->u_state = SMB_USER_STATE_LOGGING_OFF; 307 mutex_exit(&user->u_mutex); 308 atomic_dec_32(&user->u_server->sv_open_users); 309 /* 310 * All the trees hanging off of this user are disconnected. 311 */ 312 smb_user_disconnect_trees(user); 313 smb_user_auth_logoff(user->u_audit_sid); 314 mutex_enter(&user->u_mutex); 315 user->u_state = SMB_USER_STATE_LOGGED_OFF; 316 break; 317 } 318 case SMB_USER_STATE_LOGGED_OFF: 319 case SMB_USER_STATE_LOGGING_OFF: 320 break; 321 322 default: 323 ASSERT(0); 324 break; 325 } 326 mutex_exit(&user->u_mutex); 327 } 328 329 /* 330 * smb_user_logoff_all 331 * 332 * 333 */ 334 void 335 smb_user_logoff_all( 336 smb_session_t *session) 337 { 338 smb_user_t *user; 339 340 ASSERT(session); 341 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 342 343 smb_llist_enter(&session->s_user_list, RW_READER); 344 user = smb_llist_head(&session->s_user_list); 345 while (user) { 346 ASSERT(user->u_magic == SMB_USER_MAGIC); 347 ASSERT(user->u_session == session); 348 mutex_enter(&user->u_mutex); 349 switch (user->u_state) { 350 case SMB_USER_STATE_LOGGED_IN: 351 /* The user is still logged in. */ 352 user->u_refcnt++; 353 mutex_exit(&user->u_mutex); 354 smb_llist_exit(&session->s_user_list); 355 smb_user_logoff(user); 356 smb_user_release(user); 357 smb_llist_enter(&session->s_user_list, RW_READER); 358 user = smb_llist_head(&session->s_user_list); 359 break; 360 case SMB_USER_STATE_LOGGING_OFF: 361 case SMB_USER_STATE_LOGGED_OFF: 362 /* 363 * The user is logged off or logging off. 364 */ 365 mutex_exit(&user->u_mutex); 366 user = smb_llist_next(&session->s_user_list, user); 367 break; 368 default: 369 ASSERT(0); 370 mutex_exit(&user->u_mutex); 371 user = smb_llist_next(&session->s_user_list, user); 372 break; 373 } 374 } 375 smb_llist_exit(&session->s_user_list); 376 } 377 378 /* 379 * smb_user_release 380 * 381 * 382 */ 383 void 384 smb_user_release( 385 smb_user_t *user) 386 { 387 ASSERT(user->u_magic == SMB_USER_MAGIC); 388 389 mutex_enter(&user->u_mutex); 390 ASSERT(user->u_refcnt); 391 user->u_refcnt--; 392 switch (user->u_state) { 393 case SMB_USER_STATE_LOGGED_OFF: 394 if (user->u_refcnt == 0) { 395 mutex_exit(&user->u_mutex); 396 smb_user_delete(user); 397 return; 398 } 399 break; 400 401 case SMB_USER_STATE_LOGGED_IN: 402 case SMB_USER_STATE_LOGGING_OFF: 403 break; 404 405 default: 406 ASSERT(0); 407 break; 408 } 409 mutex_exit(&user->u_mutex); 410 } 411 412 /* 413 * smb_user_lookup_by_uid 414 * 415 * Find the appropriate user for this request. The request credentials 416 * set here may be overridden by the tree credentials. In domain mode, 417 * the user and tree credentials should be the same. In share mode, the 418 * tree credentials (defined in the share definition) should override 419 * the user credentials. 420 */ 421 smb_user_t * 422 smb_user_lookup_by_uid( 423 smb_session_t *session, 424 uint16_t uid) 425 { 426 smb_user_t *user; 427 428 ASSERT(session); 429 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 430 431 smb_llist_enter(&session->s_user_list, RW_READER); 432 user = smb_llist_head(&session->s_user_list); 433 while (user) { 434 ASSERT(user->u_magic == SMB_USER_MAGIC); 435 ASSERT(user->u_session == session); 436 if (user->u_uid == uid) { 437 mutex_enter(&user->u_mutex); 438 switch (user->u_state) { 439 440 case SMB_USER_STATE_LOGGED_IN: 441 /* The user exists and is still logged in. */ 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_state 472 * 473 * This function returns the first user in the logged in state. If the user 474 * provided is NULL the search starts from the beginning of the list passed 475 * in. It a user is provided the search starts just after that user. 476 */ 477 smb_user_t * 478 smb_user_lookup_by_state( 479 smb_session_t *session, 480 smb_user_t *user) 481 { 482 smb_llist_t *lst; 483 smb_user_t *next; 484 485 ASSERT(session); 486 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 487 488 lst = &session->s_user_list; 489 490 smb_llist_enter(lst, RW_READER); 491 if (user) { 492 ASSERT(user); 493 ASSERT(user->u_magic == SMB_USER_MAGIC); 494 ASSERT(user->u_refcnt); 495 next = smb_llist_next(lst, user); 496 } else { 497 next = smb_llist_head(lst); 498 } 499 while (next) { 500 ASSERT(next->u_magic == SMB_USER_MAGIC); 501 ASSERT(next->u_session == session); 502 mutex_enter(&next->u_mutex); 503 if (next->u_state == SMB_USER_STATE_LOGGED_IN) { 504 next->u_refcnt++; 505 mutex_exit(&next->u_mutex); 506 break; 507 } else { 508 ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) || 509 (next->u_state == SMB_USER_STATE_LOGGED_OFF)); 510 mutex_exit(&next->u_mutex); 511 next = smb_llist_next(lst, next); 512 } 513 } 514 smb_llist_exit(lst); 515 516 return (next); 517 } 518 519 /* 520 * Find a tree by tree-id. 521 */ 522 smb_tree_t * 523 smb_user_lookup_tree( 524 smb_user_t *user, 525 uint16_t tid) 526 527 { 528 smb_tree_t *tree; 529 530 ASSERT(user); 531 ASSERT(user->u_magic == SMB_USER_MAGIC); 532 533 smb_llist_enter(&user->u_tree_list, RW_READER); 534 tree = smb_llist_head(&user->u_tree_list); 535 536 while (tree) { 537 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 538 ASSERT(tree->t_user == user); 539 540 if (tree->t_tid == tid) { 541 if (smb_tree_hold(tree)) { 542 smb_llist_exit(&user->u_tree_list); 543 return (tree); 544 } else { 545 smb_llist_exit(&user->u_tree_list); 546 return (NULL); 547 } 548 } 549 550 tree = smb_llist_next(&user->u_tree_list, tree); 551 } 552 553 smb_llist_exit(&user->u_tree_list); 554 return (NULL); 555 } 556 557 /* 558 * Find the first connected tree that matches the specified sharename. 559 * If the specified tree is NULL the search starts from the beginning of 560 * the user's tree list. If a tree is provided the search starts just 561 * after that tree. 562 */ 563 smb_tree_t * 564 smb_user_lookup_share( 565 smb_user_t *user, 566 const char *sharename, 567 smb_tree_t *tree) 568 { 569 ASSERT(user); 570 ASSERT(user->u_magic == SMB_USER_MAGIC); 571 ASSERT(sharename); 572 573 smb_llist_enter(&user->u_tree_list, RW_READER); 574 575 if (tree) { 576 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 577 ASSERT(tree->t_user == user); 578 tree = smb_llist_next(&user->u_tree_list, tree); 579 } else { 580 tree = smb_llist_head(&user->u_tree_list); 581 } 582 583 while (tree) { 584 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 585 ASSERT(tree->t_user == user); 586 if (utf8_strcasecmp(tree->t_sharename, sharename) == 0) { 587 if (smb_tree_hold(tree)) { 588 smb_llist_exit(&user->u_tree_list); 589 return (tree); 590 } 591 } 592 tree = smb_llist_next(&user->u_tree_list, tree); 593 } 594 595 smb_llist_exit(&user->u_tree_list); 596 return (NULL); 597 } 598 599 /* 600 * Find the first connected tree that matches the specified volume name. 601 * If the specified tree is NULL the search starts from the beginning of 602 * the user's tree list. If a tree is provided the search starts just 603 * after that tree. 604 */ 605 smb_tree_t * 606 smb_user_lookup_volume( 607 smb_user_t *user, 608 const char *name, 609 smb_tree_t *tree) 610 { 611 ASSERT(user); 612 ASSERT(user->u_magic == SMB_USER_MAGIC); 613 ASSERT(name); 614 615 smb_llist_enter(&user->u_tree_list, RW_READER); 616 617 if (tree) { 618 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 619 ASSERT(tree->t_user == user); 620 tree = smb_llist_next(&user->u_tree_list, tree); 621 } else { 622 tree = smb_llist_head(&user->u_tree_list); 623 } 624 625 while (tree) { 626 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 627 ASSERT(tree->t_user == user); 628 629 if (utf8_strcasecmp(tree->t_volume, name) == 0) { 630 if (smb_tree_hold(tree)) { 631 smb_llist_exit(&user->u_tree_list); 632 return (tree); 633 } 634 } 635 636 tree = smb_llist_next(&user->u_tree_list, tree); 637 } 638 639 smb_llist_exit(&user->u_tree_list); 640 return (NULL); 641 } 642 643 /* 644 * Disconnect all trees that match the specified client process-id. 645 */ 646 void 647 smb_user_close_pid( 648 smb_user_t *user, 649 uint16_t pid) 650 { 651 smb_tree_t *tree; 652 653 ASSERT(user); 654 ASSERT(user->u_magic == SMB_USER_MAGIC); 655 656 tree = smb_user_get_tree(&user->u_tree_list, NULL); 657 while (tree) { 658 smb_tree_t *next; 659 ASSERT(tree->t_user == user); 660 smb_tree_close_pid(tree, pid); 661 next = smb_user_get_tree(&user->u_tree_list, tree); 662 smb_tree_release(tree); 663 tree = next; 664 } 665 } 666 667 /* 668 * Disconnect all trees that this user has connected. 669 */ 670 void 671 smb_user_disconnect_trees( 672 smb_user_t *user) 673 { 674 smb_tree_t *tree; 675 676 ASSERT(user); 677 ASSERT(user->u_magic == SMB_USER_MAGIC); 678 679 tree = smb_user_get_tree(&user->u_tree_list, NULL); 680 while (tree) { 681 ASSERT(tree->t_user == user); 682 smb_tree_disconnect(tree); 683 smb_tree_release(tree); 684 tree = smb_user_get_tree(&user->u_tree_list, NULL); 685 } 686 } 687 688 /* 689 * Disconnect all trees that match the specified share name. 690 */ 691 void 692 smb_user_disconnect_share( 693 smb_user_t *user, 694 const char *sharename) 695 { 696 smb_tree_t *tree; 697 smb_tree_t *next; 698 699 ASSERT(user); 700 ASSERT(user->u_magic == SMB_USER_MAGIC); 701 ASSERT(user->u_refcnt); 702 703 tree = smb_user_lookup_share(user, sharename, NULL); 704 while (tree) { 705 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 706 smb_session_cancel_requests(user->u_session, tree, NULL); 707 smb_tree_disconnect(tree); 708 next = smb_user_lookup_share(user, sharename, tree); 709 smb_tree_release(tree); 710 tree = next; 711 } 712 } 713 714 /* 715 * Determine whether or not the user is an administrator. 716 * Members of the administrators group have administrative rights. 717 */ 718 boolean_t 719 smb_user_is_admin( 720 smb_user_t *user) 721 { 722 cred_t *u_cred; 723 724 ASSERT(user); 725 u_cred = user->u_cred; 726 ASSERT(u_cred); 727 728 if (smb_admins_sid == NULL) 729 return (B_FALSE); 730 731 if (smb_cred_is_member(u_cred, smb_admins_sid)) 732 return (B_TRUE); 733 734 return (B_FALSE); 735 } 736 737 /* *************************** Static Functions ***************************** */ 738 739 /* 740 * smb_user_delete 741 */ 742 static void 743 smb_user_delete( 744 smb_user_t *user) 745 { 746 smb_session_t *session; 747 748 ASSERT(user); 749 ASSERT(user->u_magic == SMB_USER_MAGIC); 750 ASSERT(user->u_refcnt == 0); 751 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 752 753 session = user->u_session; 754 /* 755 * Let's remove the user from the list of users of the session. This 756 * has to be done before any resources associated with the user are 757 * deleted. 758 */ 759 smb_llist_enter(&session->s_user_list, RW_WRITER); 760 smb_llist_remove(&session->s_user_list, user); 761 smb_llist_exit(&session->s_user_list); 762 763 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 764 mutex_destroy(&user->u_mutex); 765 smb_llist_destructor(&user->u_tree_list); 766 smb_idpool_destructor(&user->u_tid_pool); 767 smb_idpool_free(&session->s_uid_pool, user->u_uid); 768 crfree(user->u_cred); 769 if (user->u_privcred) 770 crfree(user->u_privcred); 771 kmem_free(user->u_name, (size_t)user->u_name_len); 772 kmem_free(user->u_domain, (size_t)user->u_domain_len); 773 kmem_cache_free(user->u_server->si_cache_user, user); 774 } 775 776 /* 777 * Get the next connected tree in the list. A reference is taken on 778 * the tree, which can be released later with smb_tree_release(). 779 * 780 * If the specified tree is NULL the search starts from the beginning of 781 * the tree list. If a tree is provided the search starts just after 782 * that tree. 783 * 784 * Returns NULL if there are no connected trees in the list. 785 */ 786 static smb_tree_t * 787 smb_user_get_tree( 788 smb_llist_t *tree_list, 789 smb_tree_t *tree) 790 { 791 ASSERT(tree_list); 792 793 smb_llist_enter(tree_list, RW_READER); 794 795 if (tree) { 796 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 797 tree = smb_llist_next(tree_list, tree); 798 } else { 799 tree = smb_llist_head(tree_list); 800 } 801 802 while (tree) { 803 if (smb_tree_hold(tree)) 804 break; 805 806 tree = smb_llist_next(tree_list, tree); 807 } 808 809 smb_llist_exit(tree_list); 810 return (tree); 811 } 812 813 cred_t * 814 smb_user_getcred(smb_user_t *user) 815 { 816 return (user->u_cred); 817 } 818 819 cred_t * 820 smb_user_getprivcred(smb_user_t *user) 821 { 822 return ((user->u_privcred)? user->u_privcred : user->u_cred); 823 } 824