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 2009 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_kproto.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 boolean_t smb_user_is_logged_in(smb_user_t *); 175 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); 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_strdup(account_name); 234 user->u_domain = smb_strdup(domain_name); 235 user->u_cred = cr; 236 user->u_privcred = smb_cred_create_privs(cr, privileges); 237 user->u_audit_sid = audit_sid; 238 239 if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) { 240 if (!smb_idpool_constructor(&user->u_tid_pool)) { 241 smb_llist_constructor(&user->u_tree_list, 242 sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd)); 243 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 244 crhold(user->u_cred); 245 if (user->u_privcred) 246 crhold(user->u_privcred); 247 user->u_state = SMB_USER_STATE_LOGGED_IN; 248 user->u_magic = SMB_USER_MAGIC; 249 smb_llist_enter(&session->s_user_list, RW_WRITER); 250 smb_llist_insert_tail(&session->s_user_list, user); 251 smb_llist_exit(&session->s_user_list); 252 atomic_inc_32(&session->s_server->sv_open_users); 253 return (user); 254 } 255 smb_idpool_free(&session->s_uid_pool, user->u_uid); 256 } 257 smb_mfree(user->u_name); 258 smb_mfree(user->u_domain); 259 kmem_cache_free(session->s_server->si_cache_user, user); 260 return (NULL); 261 } 262 263 /* 264 * Create a new user based on an existing user, used to support 265 * additional SessionSetupX requests for a user on a session. 266 * 267 * Assumes the caller has a reference on the original user from 268 * a user_lookup_by_x call. 269 */ 270 smb_user_t * 271 smb_user_dup( 272 smb_user_t *orig_user) 273 { 274 smb_user_t *user; 275 276 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 277 ASSERT(orig_user->u_refcnt); 278 279 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 280 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 281 orig_user->u_privileges, orig_user->u_audit_sid); 282 283 if (user) 284 smb_user_nonauth_logon(orig_user->u_audit_sid); 285 286 return (user); 287 } 288 289 /* 290 * smb_user_logoff 291 * 292 * Change the user state and disconnect trees. 293 * The user list must not be entered or modified here. 294 */ 295 void 296 smb_user_logoff( 297 smb_user_t *user) 298 { 299 ASSERT(user->u_magic == SMB_USER_MAGIC); 300 301 mutex_enter(&user->u_mutex); 302 ASSERT(user->u_refcnt); 303 switch (user->u_state) { 304 case SMB_USER_STATE_LOGGED_IN: { 305 /* 306 * The user is moved into a state indicating that the log off 307 * process has started. 308 */ 309 user->u_state = SMB_USER_STATE_LOGGING_OFF; 310 mutex_exit(&user->u_mutex); 311 atomic_dec_32(&user->u_server->sv_open_users); 312 /* 313 * All the trees hanging off of this user are disconnected. 314 */ 315 smb_user_disconnect_trees(user); 316 smb_user_auth_logoff(user->u_audit_sid); 317 mutex_enter(&user->u_mutex); 318 user->u_state = SMB_USER_STATE_LOGGED_OFF; 319 break; 320 } 321 case SMB_USER_STATE_LOGGED_OFF: 322 case SMB_USER_STATE_LOGGING_OFF: 323 break; 324 325 default: 326 ASSERT(0); 327 break; 328 } 329 mutex_exit(&user->u_mutex); 330 } 331 332 /* 333 * smb_user_logoff_all 334 * 335 * 336 */ 337 void 338 smb_user_logoff_all( 339 smb_session_t *session) 340 { 341 smb_user_t *user; 342 343 ASSERT(session); 344 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 345 346 smb_llist_enter(&session->s_user_list, RW_READER); 347 user = smb_llist_head(&session->s_user_list); 348 while (user) { 349 ASSERT(user->u_magic == SMB_USER_MAGIC); 350 ASSERT(user->u_session == session); 351 mutex_enter(&user->u_mutex); 352 switch (user->u_state) { 353 case SMB_USER_STATE_LOGGED_IN: 354 /* The user is still logged in. */ 355 user->u_refcnt++; 356 mutex_exit(&user->u_mutex); 357 smb_llist_exit(&session->s_user_list); 358 smb_user_logoff(user); 359 smb_user_release(user); 360 smb_llist_enter(&session->s_user_list, RW_READER); 361 user = smb_llist_head(&session->s_user_list); 362 break; 363 case SMB_USER_STATE_LOGGING_OFF: 364 case SMB_USER_STATE_LOGGED_OFF: 365 /* 366 * The user is logged off or logging off. 367 */ 368 mutex_exit(&user->u_mutex); 369 user = smb_llist_next(&session->s_user_list, user); 370 break; 371 default: 372 ASSERT(0); 373 mutex_exit(&user->u_mutex); 374 user = smb_llist_next(&session->s_user_list, user); 375 break; 376 } 377 } 378 smb_llist_exit(&session->s_user_list); 379 } 380 381 /* 382 * Take a reference on a user. 383 */ 384 boolean_t 385 smb_user_hold(smb_user_t *user) 386 { 387 ASSERT(user); 388 ASSERT(user->u_magic == SMB_USER_MAGIC); 389 390 mutex_enter(&user->u_mutex); 391 392 if (smb_user_is_logged_in(user)) { 393 user->u_refcnt++; 394 mutex_exit(&user->u_mutex); 395 return (B_TRUE); 396 } 397 398 mutex_exit(&user->u_mutex); 399 return (B_FALSE); 400 } 401 402 /* 403 * smb_user_release 404 * 405 * 406 */ 407 void 408 smb_user_release( 409 smb_user_t *user) 410 { 411 ASSERT(user->u_magic == SMB_USER_MAGIC); 412 413 mutex_enter(&user->u_mutex); 414 ASSERT(user->u_refcnt); 415 user->u_refcnt--; 416 switch (user->u_state) { 417 case SMB_USER_STATE_LOGGED_OFF: 418 if (user->u_refcnt == 0) { 419 mutex_exit(&user->u_mutex); 420 smb_user_delete(user); 421 return; 422 } 423 break; 424 425 case SMB_USER_STATE_LOGGED_IN: 426 case SMB_USER_STATE_LOGGING_OFF: 427 break; 428 429 default: 430 ASSERT(0); 431 break; 432 } 433 mutex_exit(&user->u_mutex); 434 } 435 436 /* 437 * smb_user_lookup_by_uid 438 * 439 * Find the appropriate user for this request. The request credentials 440 * set here may be overridden by the tree credentials. In domain mode, 441 * the user and tree credentials should be the same. In share mode, the 442 * tree credentials (defined in the share definition) should override 443 * the user credentials. 444 */ 445 smb_user_t * 446 smb_user_lookup_by_uid( 447 smb_session_t *session, 448 uint16_t uid) 449 { 450 smb_user_t *user; 451 452 ASSERT(session); 453 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 454 455 smb_llist_enter(&session->s_user_list, RW_READER); 456 user = smb_llist_head(&session->s_user_list); 457 while (user) { 458 ASSERT(user->u_magic == SMB_USER_MAGIC); 459 ASSERT(user->u_session == session); 460 if (user->u_uid == uid) { 461 if (smb_user_hold(user)) { 462 smb_llist_exit(&session->s_user_list); 463 return (user); 464 } else { 465 smb_llist_exit(&session->s_user_list); 466 return (NULL); 467 } 468 } 469 user = smb_llist_next(&session->s_user_list, user); 470 } 471 smb_llist_exit(&session->s_user_list); 472 return (NULL); 473 } 474 475 /* 476 * smb_user_lookup_by_state 477 * 478 * This function returns the first user in the logged in state. If the user 479 * provided is NULL the search starts from the beginning of the list passed 480 * in. It a user is provided the search starts just after that user. 481 */ 482 smb_user_t * 483 smb_user_lookup_by_state( 484 smb_session_t *session, 485 smb_user_t *user) 486 { 487 smb_llist_t *lst; 488 smb_user_t *next; 489 490 ASSERT(session); 491 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 492 493 lst = &session->s_user_list; 494 495 smb_llist_enter(lst, RW_READER); 496 if (user) { 497 ASSERT(user); 498 ASSERT(user->u_magic == SMB_USER_MAGIC); 499 ASSERT(user->u_refcnt); 500 next = smb_llist_next(lst, user); 501 } else { 502 next = smb_llist_head(lst); 503 } 504 while (next) { 505 ASSERT(next->u_magic == SMB_USER_MAGIC); 506 ASSERT(next->u_session == session); 507 508 if (smb_user_hold(next)) 509 break; 510 511 next = smb_llist_next(lst, next); 512 } 513 smb_llist_exit(lst); 514 515 return (next); 516 } 517 518 /* 519 * Find a tree by tree-id. 520 */ 521 smb_tree_t * 522 smb_user_lookup_tree( 523 smb_user_t *user, 524 uint16_t tid) 525 526 { 527 smb_tree_t *tree; 528 529 ASSERT(user); 530 ASSERT(user->u_magic == SMB_USER_MAGIC); 531 532 smb_llist_enter(&user->u_tree_list, RW_READER); 533 tree = smb_llist_head(&user->u_tree_list); 534 535 while (tree) { 536 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 537 ASSERT(tree->t_user == user); 538 539 if (tree->t_tid == tid) { 540 if (smb_tree_hold(tree)) { 541 smb_llist_exit(&user->u_tree_list); 542 return (tree); 543 } else { 544 smb_llist_exit(&user->u_tree_list); 545 return (NULL); 546 } 547 } 548 549 tree = smb_llist_next(&user->u_tree_list, tree); 550 } 551 552 smb_llist_exit(&user->u_tree_list); 553 return (NULL); 554 } 555 556 /* 557 * Find the first connected tree that matches the specified sharename. 558 * If the specified tree is NULL the search starts from the beginning of 559 * the user's tree list. If a tree is provided the search starts just 560 * after that tree. 561 */ 562 smb_tree_t * 563 smb_user_lookup_share( 564 smb_user_t *user, 565 const char *sharename, 566 smb_tree_t *tree) 567 { 568 ASSERT(user); 569 ASSERT(user->u_magic == SMB_USER_MAGIC); 570 ASSERT(sharename); 571 572 smb_llist_enter(&user->u_tree_list, RW_READER); 573 574 if (tree) { 575 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 576 ASSERT(tree->t_user == user); 577 tree = smb_llist_next(&user->u_tree_list, tree); 578 } else { 579 tree = smb_llist_head(&user->u_tree_list); 580 } 581 582 while (tree) { 583 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 584 ASSERT(tree->t_user == user); 585 if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) { 586 if (smb_tree_hold(tree)) { 587 smb_llist_exit(&user->u_tree_list); 588 return (tree); 589 } 590 } 591 tree = smb_llist_next(&user->u_tree_list, tree); 592 } 593 594 smb_llist_exit(&user->u_tree_list); 595 return (NULL); 596 } 597 598 /* 599 * Find the first connected tree that matches the specified volume name. 600 * If the specified tree is NULL the search starts from the beginning of 601 * the user's tree list. If a tree is provided the search starts just 602 * after that tree. 603 */ 604 smb_tree_t * 605 smb_user_lookup_volume( 606 smb_user_t *user, 607 const char *name, 608 smb_tree_t *tree) 609 { 610 ASSERT(user); 611 ASSERT(user->u_magic == SMB_USER_MAGIC); 612 ASSERT(name); 613 614 smb_llist_enter(&user->u_tree_list, RW_READER); 615 616 if (tree) { 617 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 618 ASSERT(tree->t_user == user); 619 tree = smb_llist_next(&user->u_tree_list, tree); 620 } else { 621 tree = smb_llist_head(&user->u_tree_list); 622 } 623 624 while (tree) { 625 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 626 ASSERT(tree->t_user == user); 627 628 if (smb_strcasecmp(tree->t_volume, name, 0) == 0) { 629 if (smb_tree_hold(tree)) { 630 smb_llist_exit(&user->u_tree_list); 631 return (tree); 632 } 633 } 634 635 tree = smb_llist_next(&user->u_tree_list, tree); 636 } 637 638 smb_llist_exit(&user->u_tree_list); 639 return (NULL); 640 } 641 642 /* 643 * Disconnect all trees that match the specified client process-id. 644 */ 645 void 646 smb_user_close_pid( 647 smb_user_t *user, 648 uint16_t pid) 649 { 650 smb_tree_t *tree; 651 652 ASSERT(user); 653 ASSERT(user->u_magic == SMB_USER_MAGIC); 654 655 tree = smb_user_get_tree(&user->u_tree_list, NULL); 656 while (tree) { 657 smb_tree_t *next; 658 ASSERT(tree->t_user == user); 659 smb_tree_close_pid(tree, pid); 660 next = smb_user_get_tree(&user->u_tree_list, tree); 661 smb_tree_release(tree); 662 tree = next; 663 } 664 } 665 666 /* 667 * Disconnect all trees that this user has connected. 668 */ 669 void 670 smb_user_disconnect_trees( 671 smb_user_t *user) 672 { 673 smb_tree_t *tree; 674 675 ASSERT(user); 676 ASSERT(user->u_magic == SMB_USER_MAGIC); 677 678 tree = smb_user_get_tree(&user->u_tree_list, NULL); 679 while (tree) { 680 ASSERT(tree->t_user == user); 681 smb_tree_disconnect(tree, B_TRUE); 682 smb_tree_release(tree); 683 tree = smb_user_get_tree(&user->u_tree_list, NULL); 684 } 685 } 686 687 /* 688 * Disconnect all trees that match the specified share name. 689 */ 690 void 691 smb_user_disconnect_share( 692 smb_user_t *user, 693 const char *sharename) 694 { 695 smb_tree_t *tree; 696 smb_tree_t *next; 697 698 ASSERT(user); 699 ASSERT(user->u_magic == SMB_USER_MAGIC); 700 ASSERT(user->u_refcnt); 701 702 tree = smb_user_lookup_share(user, sharename, NULL); 703 while (tree) { 704 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 705 smb_session_cancel_requests(user->u_session, tree, NULL); 706 smb_tree_disconnect(tree, B_TRUE); 707 next = smb_user_lookup_share(user, sharename, tree); 708 smb_tree_release(tree); 709 tree = next; 710 } 711 } 712 713 /* 714 * Close a file by its unique id. 715 */ 716 int 717 smb_user_fclose(smb_user_t *user, uint32_t uniqid) 718 { 719 smb_llist_t *tree_list; 720 smb_tree_t *tree; 721 int rc = ENOENT; 722 723 ASSERT(user); 724 ASSERT(user->u_magic == SMB_USER_MAGIC); 725 726 tree_list = &user->u_tree_list; 727 ASSERT(tree_list); 728 729 smb_llist_enter(tree_list, RW_READER); 730 tree = smb_llist_head(tree_list); 731 732 while ((tree != NULL) && (rc == ENOENT)) { 733 ASSERT(tree->t_user == user); 734 735 if (smb_tree_hold(tree)) { 736 rc = smb_tree_fclose(tree, uniqid); 737 smb_tree_release(tree); 738 } 739 740 tree = smb_llist_next(tree_list, tree); 741 } 742 743 smb_llist_exit(tree_list); 744 return (rc); 745 } 746 747 /* 748 * Determine whether or not the user is an administrator. 749 * Members of the administrators group have administrative rights. 750 */ 751 boolean_t 752 smb_user_is_admin( 753 smb_user_t *user) 754 { 755 cred_t *u_cred; 756 757 ASSERT(user); 758 u_cred = user->u_cred; 759 ASSERT(u_cred); 760 761 if (smb_admins_sid == NULL) 762 return (B_FALSE); 763 764 if (smb_cred_is_member(u_cred, smb_admins_sid)) 765 return (B_TRUE); 766 767 return (B_FALSE); 768 } 769 770 /* 771 * This function should be called with a hold on the user. 772 */ 773 boolean_t 774 smb_user_namecmp(smb_user_t *user, const char *name) 775 { 776 char *fq_name; 777 boolean_t match; 778 779 if (smb_strcasecmp(name, user->u_name, 0) == 0) 780 return (B_TRUE); 781 782 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 783 784 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 785 user->u_domain, user->u_name); 786 787 match = (smb_strcasecmp(name, fq_name, 0) == 0); 788 if (!match) { 789 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 790 user->u_name, user->u_domain); 791 792 match = (smb_strcasecmp(name, fq_name, 0) == 0); 793 } 794 795 kmem_free(fq_name, MAXNAMELEN); 796 return (match); 797 } 798 799 /* 800 * If the enumeration request is for user data, handle the request 801 * here. Otherwise, pass it on to the trees. 802 * 803 * This function should be called with a hold on the user. 804 */ 805 int 806 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 807 { 808 smb_tree_t *tree; 809 smb_tree_t *next; 810 int rc; 811 812 ASSERT(user); 813 ASSERT(user->u_magic == SMB_USER_MAGIC); 814 815 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 816 return (smb_user_enum_private(user, svcenum)); 817 818 tree = smb_user_get_tree(&user->u_tree_list, NULL); 819 while (tree) { 820 ASSERT(tree->t_user == user); 821 822 rc = smb_tree_enum(tree, svcenum); 823 if (rc != 0) { 824 smb_tree_release(tree); 825 break; 826 } 827 828 next = smb_user_get_tree(&user->u_tree_list, tree); 829 smb_tree_release(tree); 830 tree = next; 831 } 832 833 return (rc); 834 } 835 836 /* *************************** Static Functions ***************************** */ 837 838 /* 839 * Determine whether or not a user is logged in. 840 * Typically, a reference can only be taken on a logged-in user. 841 * 842 * This is a private function and must be called with the user 843 * mutex held. 844 */ 845 static boolean_t 846 smb_user_is_logged_in(smb_user_t *user) 847 { 848 switch (user->u_state) { 849 case SMB_USER_STATE_LOGGED_IN: 850 return (B_TRUE); 851 852 case SMB_USER_STATE_LOGGING_OFF: 853 case SMB_USER_STATE_LOGGED_OFF: 854 return (B_FALSE); 855 856 default: 857 ASSERT(0); 858 return (B_FALSE); 859 } 860 } 861 862 /* 863 * smb_user_delete 864 */ 865 static void 866 smb_user_delete( 867 smb_user_t *user) 868 { 869 smb_session_t *session; 870 871 ASSERT(user); 872 ASSERT(user->u_magic == SMB_USER_MAGIC); 873 ASSERT(user->u_refcnt == 0); 874 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 875 876 session = user->u_session; 877 /* 878 * Let's remove the user from the list of users of the session. This 879 * has to be done before any resources associated with the user are 880 * deleted. 881 */ 882 smb_llist_enter(&session->s_user_list, RW_WRITER); 883 smb_llist_remove(&session->s_user_list, user); 884 smb_llist_exit(&session->s_user_list); 885 886 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 887 mutex_destroy(&user->u_mutex); 888 smb_llist_destructor(&user->u_tree_list); 889 smb_idpool_destructor(&user->u_tid_pool); 890 smb_idpool_free(&session->s_uid_pool, user->u_uid); 891 crfree(user->u_cred); 892 if (user->u_privcred) 893 crfree(user->u_privcred); 894 smb_mfree(user->u_name); 895 smb_mfree(user->u_domain); 896 kmem_cache_free(user->u_server->si_cache_user, user); 897 } 898 899 /* 900 * Get the next connected tree in the list. A reference is taken on 901 * the tree, which can be released later with smb_tree_release(). 902 * 903 * If the specified tree is NULL the search starts from the beginning of 904 * the tree list. If a tree is provided the search starts just after 905 * that tree. 906 * 907 * Returns NULL if there are no connected trees in the list. 908 */ 909 static smb_tree_t * 910 smb_user_get_tree( 911 smb_llist_t *tree_list, 912 smb_tree_t *tree) 913 { 914 ASSERT(tree_list); 915 916 smb_llist_enter(tree_list, RW_READER); 917 918 if (tree) { 919 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 920 tree = smb_llist_next(tree_list, tree); 921 } else { 922 tree = smb_llist_head(tree_list); 923 } 924 925 while (tree) { 926 if (smb_tree_hold(tree)) 927 break; 928 929 tree = smb_llist_next(tree_list, tree); 930 } 931 932 smb_llist_exit(tree_list); 933 return (tree); 934 } 935 936 cred_t * 937 smb_user_getcred(smb_user_t *user) 938 { 939 return (user->u_cred); 940 } 941 942 cred_t * 943 smb_user_getprivcred(smb_user_t *user) 944 { 945 return ((user->u_privcred)? user->u_privcred : user->u_cred); 946 } 947 948 /* 949 * Private function to support smb_user_enum. 950 */ 951 static int 952 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 953 { 954 uint8_t *pb; 955 uint_t nbytes; 956 int rc; 957 958 if (svcenum->se_nskip > 0) { 959 svcenum->se_nskip--; 960 return (0); 961 } 962 963 if (svcenum->se_nitems >= svcenum->se_nlimit) { 964 svcenum->se_nitems = svcenum->se_nlimit; 965 return (0); 966 } 967 968 pb = &svcenum->se_buf[svcenum->se_bused]; 969 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 970 if (rc == 0) { 971 svcenum->se_bavail -= nbytes; 972 svcenum->se_bused += nbytes; 973 svcenum->se_nitems++; 974 } 975 976 return (rc); 977 } 978 979 /* 980 * Encode the NetInfo for a user into a buffer. NetInfo contains 981 * information that is often needed in user space to support RPC 982 * requests. 983 */ 984 int 985 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 986 uint32_t *nbytes) 987 { 988 smb_netuserinfo_t info; 989 int rc; 990 991 smb_user_netinfo_init(user, &info); 992 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 993 smb_user_netinfo_fini(&info); 994 995 return (rc); 996 } 997 998 void 999 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 1000 { 1001 smb_session_t *session; 1002 char *buf; 1003 1004 ASSERT(user); 1005 ASSERT(user->u_domain); 1006 ASSERT(user->u_name); 1007 1008 session = user->u_session; 1009 ASSERT(session); 1010 ASSERT(session->workstation); 1011 1012 info->ui_session_id = session->s_kid; 1013 info->ui_native_os = session->native_os; 1014 info->ui_ipaddr = session->ipaddr; 1015 info->ui_numopens = session->s_file_cnt; 1016 info->ui_uid = user->u_uid; 1017 info->ui_logon_time = user->u_logon_time; 1018 info->ui_flags = user->u_flags; 1019 1020 info->ui_domain_len = user->u_domain_len; 1021 info->ui_domain = smb_strdup(user->u_domain); 1022 1023 info->ui_account_len = user->u_name_len; 1024 info->ui_account = smb_strdup(user->u_name); 1025 1026 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1027 smb_session_getclient(session, buf, MAXNAMELEN); 1028 info->ui_workstation_len = strlen(buf) + 1; 1029 info->ui_workstation = smb_strdup(buf); 1030 kmem_free(buf, MAXNAMELEN); 1031 } 1032 1033 void 1034 smb_user_netinfo_fini(smb_netuserinfo_t *info) 1035 { 1036 if (info == NULL) 1037 return; 1038 1039 if (info->ui_domain) 1040 smb_mfree(info->ui_domain); 1041 if (info->ui_account) 1042 smb_mfree(info->ui_account); 1043 if (info->ui_workstation) 1044 smb_mfree(info->ui_workstation); 1045 1046 bzero(info, sizeof (smb_netuserinfo_t)); 1047 } 1048