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