1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * General Structures Layout 27 * ------------------------- 28 * 29 * This is a simplified diagram showing the relationship between most of the 30 * main structures. 31 * 32 * +-------------------+ 33 * | SMB_INFO | 34 * +-------------------+ 35 * | 36 * | 37 * v 38 * +-------------------+ +-------------------+ +-------------------+ 39 * | SESSION |<----->| SESSION |......| SESSION | 40 * +-------------------+ +-------------------+ +-------------------+ 41 * | 42 * | 43 * v 44 * +-------------------+ +-------------------+ +-------------------+ 45 * | USER |<----->| USER |......| USER | 46 * +-------------------+ +-------------------+ +-------------------+ 47 * | 48 * | 49 * v 50 * +-------------------+ +-------------------+ +-------------------+ 51 * | TREE |<----->| TREE |......| TREE | 52 * +-------------------+ +-------------------+ +-------------------+ 53 * | | 54 * | | 55 * | v 56 * | +-------+ +-------+ +-------+ 57 * | | OFILE |<----->| OFILE |......| OFILE | 58 * | +-------+ +-------+ +-------+ 59 * | 60 * | 61 * v 62 * +-------+ +------+ +------+ 63 * | ODIR |<----->| ODIR |......| ODIR | 64 * +-------+ +------+ +------+ 65 * 66 * 67 * User State Machine 68 * ------------------ 69 * 70 * +-----------------------------+ T0 71 * | SMB_USER_STATE_LOGGED_IN |<----------- Creation/Allocation 72 * +-----------------------------+ 73 * | 74 * | T1 75 * | 76 * v 77 * +-----------------------------+ 78 * | SMB_USER_STATE_LOGGING_OFF | 79 * +-----------------------------+ 80 * | 81 * | T2 82 * | 83 * v 84 * +-----------------------------+ T3 85 * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free 86 * +-----------------------------+ 87 * 88 * SMB_USER_STATE_LOGGED_IN 89 * 90 * While in this state: 91 * - The user is queued in the list of users of his session. 92 * - References will be given out if the user is looked up. 93 * - The user can access files and pipes. 94 * 95 * SMB_USER_STATE_LOGGING_OFF 96 * 97 * While in this state: 98 * - The user is queued in the list of users of his session. 99 * - References will not be given out if the user is looked up. 100 * - The trees the user connected are being disconnected. 101 * - The resources associated with the user remain. 102 * 103 * SMB_USER_STATE_LOGGING_OFF 104 * 105 * While in this state: 106 * - The user is queued in the list of users of his session. 107 * - References will not be given out if the user is looked up. 108 * - The user has no more trees connected. 109 * - The resources associated with the user remain. 110 * 111 * Transition T0 112 * 113 * This transition occurs in smb_user_login(). A new user is created and 114 * added to the list of users of a session. 115 * 116 * Transition T1 117 * 118 * This transition occurs in smb_user_logoff(). 119 * 120 * Transition T2 121 * 122 * This transition occurs in smb_user_release(). The resources associated 123 * with the user are deleted as well as the user. For the transition to 124 * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the 125 * reference count be zero. 126 * 127 * Comments 128 * -------- 129 * 130 * The state machine of the user structures is controlled by 3 elements: 131 * - The list of users of the session he belongs to. 132 * - The mutex embedded in the structure itself. 133 * - The reference count. 134 * 135 * There's a mutex embedded in the user structure used to protect its fields 136 * and there's a lock embedded in the list of users of a session. To 137 * increment or to decrement the reference count the mutex must be entered. 138 * To insert the user into the list of users of the session and to remove 139 * the user from it, the lock must be entered in RW_WRITER mode. 140 * 141 * Rules of access to a user structure: 142 * 143 * 1) In order to avoid deadlocks, when both (mutex and lock of the session 144 * list) have to be entered, the lock must be entered first. 145 * 146 * 2) All actions applied to a user require a reference count. 147 * 148 * 3) There are 2 ways of getting a reference count. One is when the user 149 * logs in. The other when the user is looked up. 150 * 151 * It should be noted that the reference count of a user registers the 152 * number of references to the user in other structures (such as an smb 153 * request). The reference count is not incremented in these 2 instances: 154 * 155 * 1) The user is logged in. An user is anchored by his state. If there's 156 * no activity involving a user currently logged in, the reference 157 * count of that user is zero. 158 * 159 * 2) The user is queued in the list of users of the session. The fact of 160 * being queued in that list is NOT registered by incrementing the 161 * reference count. 162 */ 163 #include <sys/types.h> 164 #include <sys/sid.h> 165 #include <sys/priv_names.h> 166 #include <smbsrv/smb_kproto.h> 167 #include <smbsrv/smb_door.h> 168 169 #define ADMINISTRATORS_SID "S-1-5-32-544" 170 171 static boolean_t smb_user_is_logged_in(smb_user_t *); 172 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); 173 static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *); 174 static void smb_user_setcred(smb_user_t *, cred_t *, uint32_t); 175 static void smb_user_nonauth_logon(uint32_t); 176 static void smb_user_auth_logoff(uint32_t); 177 178 /* 179 * Create a new user. 180 */ 181 smb_user_t * 182 smb_user_login( 183 smb_session_t *session, 184 cred_t *cr, 185 char *domain_name, 186 char *account_name, 187 uint32_t flags, 188 uint32_t privileges, 189 uint32_t audit_sid) 190 { 191 smb_user_t *user; 192 193 ASSERT(session); 194 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 195 ASSERT(cr); 196 ASSERT(account_name); 197 ASSERT(domain_name); 198 199 user = kmem_cache_alloc(session->s_server->si_cache_user, KM_SLEEP); 200 bzero(user, sizeof (smb_user_t)); 201 user->u_refcnt = 1; 202 user->u_session = session; 203 user->u_server = session->s_server; 204 user->u_logon_time = gethrestime_sec(); 205 user->u_flags = flags; 206 user->u_name_len = strlen(account_name) + 1; 207 user->u_domain_len = strlen(domain_name) + 1; 208 user->u_name = smb_mem_strdup(account_name); 209 user->u_domain = smb_mem_strdup(domain_name); 210 user->u_audit_sid = audit_sid; 211 212 if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) { 213 if (!smb_idpool_constructor(&user->u_tid_pool)) { 214 smb_llist_constructor(&user->u_tree_list, 215 sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd)); 216 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 217 smb_user_setcred(user, cr, privileges); 218 user->u_state = SMB_USER_STATE_LOGGED_IN; 219 user->u_magic = SMB_USER_MAGIC; 220 smb_llist_enter(&session->s_user_list, RW_WRITER); 221 smb_llist_insert_tail(&session->s_user_list, user); 222 smb_llist_exit(&session->s_user_list); 223 smb_server_inc_users(session->s_server); 224 return (user); 225 } 226 smb_idpool_free(&session->s_uid_pool, user->u_uid); 227 } 228 smb_mem_free(user->u_name); 229 smb_mem_free(user->u_domain); 230 kmem_cache_free(session->s_server->si_cache_user, user); 231 return (NULL); 232 } 233 234 /* 235 * Create a new user based on an existing user, used to support 236 * additional SessionSetupX requests for a user on a session. 237 * 238 * Assumes the caller has a reference on the original user from 239 * a user_lookup_by_x call. 240 */ 241 smb_user_t * 242 smb_user_dup( 243 smb_user_t *orig_user) 244 { 245 smb_user_t *user; 246 247 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 248 ASSERT(orig_user->u_refcnt); 249 250 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 251 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 252 orig_user->u_privileges, orig_user->u_audit_sid); 253 254 if (user) 255 smb_user_nonauth_logon(orig_user->u_audit_sid); 256 257 return (user); 258 } 259 260 /* 261 * smb_user_logoff 262 * 263 * Change the user state and disconnect trees. 264 * The user list must not be entered or modified here. 265 */ 266 void 267 smb_user_logoff( 268 smb_user_t *user) 269 { 270 ASSERT(user->u_magic == SMB_USER_MAGIC); 271 272 mutex_enter(&user->u_mutex); 273 ASSERT(user->u_refcnt); 274 switch (user->u_state) { 275 case SMB_USER_STATE_LOGGED_IN: { 276 /* 277 * The user is moved into a state indicating that the log off 278 * process has started. 279 */ 280 user->u_state = SMB_USER_STATE_LOGGING_OFF; 281 mutex_exit(&user->u_mutex); 282 /* 283 * All the trees hanging off of this user are disconnected. 284 */ 285 smb_user_disconnect_trees(user); 286 smb_user_auth_logoff(user->u_audit_sid); 287 mutex_enter(&user->u_mutex); 288 user->u_state = SMB_USER_STATE_LOGGED_OFF; 289 smb_server_dec_users(user->u_server); 290 break; 291 } 292 case SMB_USER_STATE_LOGGED_OFF: 293 case SMB_USER_STATE_LOGGING_OFF: 294 break; 295 296 default: 297 ASSERT(0); 298 break; 299 } 300 mutex_exit(&user->u_mutex); 301 } 302 303 /* 304 * Take a reference on a user. 305 */ 306 boolean_t 307 smb_user_hold(smb_user_t *user) 308 { 309 ASSERT(user); 310 ASSERT(user->u_magic == SMB_USER_MAGIC); 311 312 mutex_enter(&user->u_mutex); 313 314 if (smb_user_is_logged_in(user)) { 315 user->u_refcnt++; 316 mutex_exit(&user->u_mutex); 317 return (B_TRUE); 318 } 319 320 mutex_exit(&user->u_mutex); 321 return (B_FALSE); 322 } 323 324 /* 325 * Release a reference on a user. If the reference count falls to 326 * zero and the user has logged off, post the object for deletion. 327 * Object deletion is deferred to avoid modifying a list while an 328 * iteration may be in progress. 329 */ 330 void 331 smb_user_release( 332 smb_user_t *user) 333 { 334 ASSERT(user->u_magic == SMB_USER_MAGIC); 335 336 mutex_enter(&user->u_mutex); 337 ASSERT(user->u_refcnt); 338 user->u_refcnt--; 339 340 /* flush the tree list's delete queue */ 341 smb_llist_flush(&user->u_tree_list); 342 343 switch (user->u_state) { 344 case SMB_USER_STATE_LOGGED_OFF: 345 if (user->u_refcnt == 0) 346 smb_session_post_user(user->u_session, user); 347 break; 348 349 case SMB_USER_STATE_LOGGED_IN: 350 case SMB_USER_STATE_LOGGING_OFF: 351 break; 352 353 default: 354 ASSERT(0); 355 break; 356 } 357 mutex_exit(&user->u_mutex); 358 } 359 360 void 361 smb_user_post_tree(smb_user_t *user, smb_tree_t *tree) 362 { 363 SMB_USER_VALID(user); 364 SMB_TREE_VALID(tree); 365 ASSERT(tree->t_refcnt == 0); 366 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 367 ASSERT(tree->t_user == user); 368 369 smb_llist_post(&user->u_tree_list, tree, smb_tree_dealloc); 370 } 371 372 373 /* 374 * Find a tree by tree-id. 375 */ 376 smb_tree_t * 377 smb_user_lookup_tree( 378 smb_user_t *user, 379 uint16_t tid) 380 381 { 382 smb_tree_t *tree; 383 384 ASSERT(user); 385 ASSERT(user->u_magic == SMB_USER_MAGIC); 386 387 smb_llist_enter(&user->u_tree_list, RW_READER); 388 tree = smb_llist_head(&user->u_tree_list); 389 390 while (tree) { 391 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 392 ASSERT(tree->t_user == user); 393 394 if (tree->t_tid == tid) { 395 if (smb_tree_hold(tree)) { 396 smb_llist_exit(&user->u_tree_list); 397 return (tree); 398 } else { 399 smb_llist_exit(&user->u_tree_list); 400 return (NULL); 401 } 402 } 403 404 tree = smb_llist_next(&user->u_tree_list, tree); 405 } 406 407 smb_llist_exit(&user->u_tree_list); 408 return (NULL); 409 } 410 411 /* 412 * Find the first connected tree that matches the specified sharename. 413 * If the specified tree is NULL the search starts from the beginning of 414 * the user's tree list. If a tree is provided the search starts just 415 * after that tree. 416 */ 417 smb_tree_t * 418 smb_user_lookup_share( 419 smb_user_t *user, 420 const char *sharename, 421 smb_tree_t *tree) 422 { 423 ASSERT(user); 424 ASSERT(user->u_magic == SMB_USER_MAGIC); 425 ASSERT(sharename); 426 427 smb_llist_enter(&user->u_tree_list, RW_READER); 428 429 if (tree) { 430 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 431 ASSERT(tree->t_user == user); 432 tree = smb_llist_next(&user->u_tree_list, tree); 433 } else { 434 tree = smb_llist_head(&user->u_tree_list); 435 } 436 437 while (tree) { 438 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 439 ASSERT(tree->t_user == user); 440 if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) { 441 if (smb_tree_hold(tree)) { 442 smb_llist_exit(&user->u_tree_list); 443 return (tree); 444 } 445 } 446 tree = smb_llist_next(&user->u_tree_list, tree); 447 } 448 449 smb_llist_exit(&user->u_tree_list); 450 return (NULL); 451 } 452 453 /* 454 * Find the first connected tree that matches the specified volume name. 455 * If the specified tree is NULL the search starts from the beginning of 456 * the user's tree list. If a tree is provided the search starts just 457 * after that tree. 458 */ 459 smb_tree_t * 460 smb_user_lookup_volume( 461 smb_user_t *user, 462 const char *name, 463 smb_tree_t *tree) 464 { 465 ASSERT(user); 466 ASSERT(user->u_magic == SMB_USER_MAGIC); 467 ASSERT(name); 468 469 smb_llist_enter(&user->u_tree_list, RW_READER); 470 471 if (tree) { 472 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 473 ASSERT(tree->t_user == user); 474 tree = smb_llist_next(&user->u_tree_list, tree); 475 } else { 476 tree = smb_llist_head(&user->u_tree_list); 477 } 478 479 while (tree) { 480 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 481 ASSERT(tree->t_user == user); 482 483 if (smb_strcasecmp(tree->t_volume, name, 0) == 0) { 484 if (smb_tree_hold(tree)) { 485 smb_llist_exit(&user->u_tree_list); 486 return (tree); 487 } 488 } 489 490 tree = smb_llist_next(&user->u_tree_list, tree); 491 } 492 493 smb_llist_exit(&user->u_tree_list); 494 return (NULL); 495 } 496 497 /* 498 * Disconnect all trees that match the specified client process-id. 499 */ 500 void 501 smb_user_close_pid( 502 smb_user_t *user, 503 uint16_t pid) 504 { 505 smb_tree_t *tree; 506 507 ASSERT(user); 508 ASSERT(user->u_magic == SMB_USER_MAGIC); 509 510 tree = smb_user_get_tree(&user->u_tree_list, NULL); 511 while (tree) { 512 smb_tree_t *next; 513 ASSERT(tree->t_user == user); 514 smb_tree_close_pid(tree, pid); 515 next = smb_user_get_tree(&user->u_tree_list, tree); 516 smb_tree_release(tree); 517 tree = next; 518 } 519 } 520 521 /* 522 * Disconnect all trees that this user has connected. 523 */ 524 void 525 smb_user_disconnect_trees( 526 smb_user_t *user) 527 { 528 smb_tree_t *tree; 529 530 ASSERT(user); 531 ASSERT(user->u_magic == SMB_USER_MAGIC); 532 533 tree = smb_user_get_tree(&user->u_tree_list, NULL); 534 while (tree) { 535 ASSERT(tree->t_user == user); 536 smb_tree_disconnect(tree, B_TRUE); 537 smb_tree_release(tree); 538 tree = smb_user_get_tree(&user->u_tree_list, NULL); 539 } 540 } 541 542 /* 543 * Disconnect all trees that match the specified share name. 544 */ 545 void 546 smb_user_disconnect_share( 547 smb_user_t *user, 548 const char *sharename) 549 { 550 smb_tree_t *tree; 551 smb_tree_t *next; 552 553 ASSERT(user); 554 ASSERT(user->u_magic == SMB_USER_MAGIC); 555 ASSERT(user->u_refcnt); 556 557 tree = smb_user_lookup_share(user, sharename, NULL); 558 while (tree) { 559 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 560 smb_session_cancel_requests(user->u_session, tree, NULL); 561 smb_tree_disconnect(tree, B_TRUE); 562 next = smb_user_lookup_share(user, sharename, tree); 563 smb_tree_release(tree); 564 tree = next; 565 } 566 } 567 568 /* 569 * Close a file by its unique id. 570 */ 571 int 572 smb_user_fclose(smb_user_t *user, uint32_t uniqid) 573 { 574 smb_llist_t *tree_list; 575 smb_tree_t *tree; 576 int rc = ENOENT; 577 578 ASSERT(user); 579 ASSERT(user->u_magic == SMB_USER_MAGIC); 580 581 tree_list = &user->u_tree_list; 582 ASSERT(tree_list); 583 584 smb_llist_enter(tree_list, RW_READER); 585 tree = smb_llist_head(tree_list); 586 587 while ((tree != NULL) && (rc == ENOENT)) { 588 ASSERT(tree->t_user == user); 589 590 if (smb_tree_hold(tree)) { 591 rc = smb_tree_fclose(tree, uniqid); 592 smb_tree_release(tree); 593 } 594 595 tree = smb_llist_next(tree_list, tree); 596 } 597 598 smb_llist_exit(tree_list); 599 return (rc); 600 } 601 602 /* 603 * Determine whether or not the user is an administrator. 604 * Members of the administrators group have administrative rights. 605 */ 606 boolean_t 607 smb_user_is_admin(smb_user_t *user) 608 { 609 char sidstr[SMB_SID_STRSZ]; 610 ksidlist_t *ksidlist; 611 ksid_t ksid1; 612 ksid_t *ksid2; 613 boolean_t rc = B_FALSE; 614 int i; 615 616 ASSERT(user); 617 ASSERT(user->u_cred); 618 619 if (SMB_USER_IS_ADMIN(user)) 620 return (B_TRUE); 621 622 bzero(&ksid1, sizeof (ksid_t)); 623 (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ); 624 ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0); 625 ksid1.ks_domain = ksid_lookupdomain(sidstr); 626 627 ksidlist = crgetsidlist(user->u_cred); 628 ASSERT(ksidlist); 629 ASSERT(ksid1.ks_domain); 630 ASSERT(ksid1.ks_domain->kd_name); 631 632 i = 0; 633 ksid2 = crgetsid(user->u_cred, KSID_USER); 634 do { 635 ASSERT(ksid2->ks_domain); 636 ASSERT(ksid2->ks_domain->kd_name); 637 638 if (strcmp(ksid1.ks_domain->kd_name, 639 ksid2->ks_domain->kd_name) == 0 && 640 ksid1.ks_rid == ksid2->ks_rid) { 641 user->u_flags |= SMB_USER_FLAG_ADMIN; 642 rc = B_TRUE; 643 break; 644 } 645 646 ksid2 = &ksidlist->ksl_sids[i]; 647 } while (i++ < ksidlist->ksl_nsid); 648 649 ksid_rele(&ksid1); 650 return (rc); 651 } 652 653 /* 654 * This function should be called with a hold on the user. 655 */ 656 boolean_t 657 smb_user_namecmp(smb_user_t *user, const char *name) 658 { 659 char *fq_name; 660 boolean_t match; 661 662 if (smb_strcasecmp(name, user->u_name, 0) == 0) 663 return (B_TRUE); 664 665 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 666 667 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 668 user->u_domain, user->u_name); 669 670 match = (smb_strcasecmp(name, fq_name, 0) == 0); 671 if (!match) { 672 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 673 user->u_name, user->u_domain); 674 675 match = (smb_strcasecmp(name, fq_name, 0) == 0); 676 } 677 678 kmem_free(fq_name, MAXNAMELEN); 679 return (match); 680 } 681 682 /* 683 * If the enumeration request is for user data, handle the request 684 * here. Otherwise, pass it on to the trees. 685 * 686 * This function should be called with a hold on the user. 687 */ 688 int 689 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 690 { 691 smb_tree_t *tree; 692 smb_tree_t *next; 693 int rc; 694 695 ASSERT(user); 696 ASSERT(user->u_magic == SMB_USER_MAGIC); 697 698 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 699 return (smb_user_enum_private(user, svcenum)); 700 701 tree = smb_user_get_tree(&user->u_tree_list, NULL); 702 while (tree) { 703 ASSERT(tree->t_user == user); 704 705 rc = smb_tree_enum(tree, svcenum); 706 if (rc != 0) { 707 smb_tree_release(tree); 708 break; 709 } 710 711 next = smb_user_get_tree(&user->u_tree_list, tree); 712 smb_tree_release(tree); 713 tree = next; 714 } 715 716 return (rc); 717 } 718 719 /* *************************** Static Functions ***************************** */ 720 721 /* 722 * Determine whether or not a user is logged in. 723 * Typically, a reference can only be taken on a logged-in user. 724 * 725 * This is a private function and must be called with the user 726 * mutex held. 727 */ 728 static boolean_t 729 smb_user_is_logged_in(smb_user_t *user) 730 { 731 switch (user->u_state) { 732 case SMB_USER_STATE_LOGGED_IN: 733 return (B_TRUE); 734 735 case SMB_USER_STATE_LOGGING_OFF: 736 case SMB_USER_STATE_LOGGED_OFF: 737 return (B_FALSE); 738 739 default: 740 ASSERT(0); 741 return (B_FALSE); 742 } 743 } 744 745 /* 746 * Delete a user. The tree list should be empty. 747 * 748 * Remove the user from the session's user list before freeing resources 749 * associated with the user. 750 */ 751 void 752 smb_user_delete(void *arg) 753 { 754 smb_session_t *session; 755 smb_user_t *user = (smb_user_t *)arg; 756 757 SMB_USER_VALID(user); 758 ASSERT(user->u_refcnt == 0); 759 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 760 761 session = user->u_session; 762 smb_llist_enter(&session->s_user_list, RW_WRITER); 763 smb_llist_remove(&session->s_user_list, user); 764 smb_idpool_free(&session->s_uid_pool, user->u_uid); 765 smb_llist_exit(&session->s_user_list); 766 767 mutex_enter(&user->u_mutex); 768 mutex_exit(&user->u_mutex); 769 770 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 771 mutex_destroy(&user->u_mutex); 772 smb_llist_destructor(&user->u_tree_list); 773 smb_idpool_destructor(&user->u_tid_pool); 774 if (user->u_cred) 775 crfree(user->u_cred); 776 if (user->u_privcred) 777 crfree(user->u_privcred); 778 smb_mem_free(user->u_name); 779 smb_mem_free(user->u_domain); 780 kmem_cache_free(user->u_server->si_cache_user, user); 781 } 782 783 /* 784 * Get the next connected tree in the list. A reference is taken on 785 * the tree, which can be released later with smb_tree_release(). 786 * 787 * If the specified tree is NULL the search starts from the beginning of 788 * the tree list. If a tree is provided the search starts just after 789 * that tree. 790 * 791 * Returns NULL if there are no connected trees in the list. 792 */ 793 static smb_tree_t * 794 smb_user_get_tree( 795 smb_llist_t *tree_list, 796 smb_tree_t *tree) 797 { 798 ASSERT(tree_list); 799 800 smb_llist_enter(tree_list, RW_READER); 801 802 if (tree) { 803 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 804 tree = smb_llist_next(tree_list, tree); 805 } else { 806 tree = smb_llist_head(tree_list); 807 } 808 809 while (tree) { 810 if (smb_tree_hold(tree)) 811 break; 812 813 tree = smb_llist_next(tree_list, tree); 814 } 815 816 smb_llist_exit(tree_list); 817 return (tree); 818 } 819 820 cred_t * 821 smb_user_getcred(smb_user_t *user) 822 { 823 return (user->u_cred); 824 } 825 826 cred_t * 827 smb_user_getprivcred(smb_user_t *user) 828 { 829 return ((user->u_privcred)? user->u_privcred : user->u_cred); 830 } 831 832 /* 833 * Assign the user cred and privileges. 834 * 835 * If the user has backup and/or restore privleges, dup the cred 836 * and add those privileges to this new privileged cred. 837 */ 838 static void 839 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges) 840 { 841 cred_t *privcred = NULL; 842 843 ASSERT(cr); 844 crhold(cr); 845 846 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE)) 847 privcred = crdup(cr); 848 849 if (privcred != NULL) { 850 if (privileges & SMB_USER_PRIV_BACKUP) { 851 (void) crsetpriv(privcred, PRIV_FILE_DAC_READ, 852 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL); 853 } 854 855 if (privileges & SMB_USER_PRIV_RESTORE) { 856 (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE, 857 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF, 858 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY, 859 PRIV_FILE_OWNER, PRIV_FILE_SETID, 860 PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL); 861 } 862 } 863 864 user->u_cred = cr; 865 user->u_privcred = privcred; 866 user->u_privileges = privileges; 867 } 868 869 /* 870 * Private function to support smb_user_enum. 871 */ 872 static int 873 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 874 { 875 uint8_t *pb; 876 uint_t nbytes; 877 int rc; 878 879 if (svcenum->se_nskip > 0) { 880 svcenum->se_nskip--; 881 return (0); 882 } 883 884 if (svcenum->se_nitems >= svcenum->se_nlimit) { 885 svcenum->se_nitems = svcenum->se_nlimit; 886 return (0); 887 } 888 889 pb = &svcenum->se_buf[svcenum->se_bused]; 890 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 891 if (rc == 0) { 892 svcenum->se_bavail -= nbytes; 893 svcenum->se_bused += nbytes; 894 svcenum->se_nitems++; 895 } 896 897 return (rc); 898 } 899 900 /* 901 * Encode the NetInfo for a user into a buffer. NetInfo contains 902 * information that is often needed in user space to support RPC 903 * requests. 904 */ 905 int 906 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 907 uint32_t *nbytes) 908 { 909 smb_netuserinfo_t info; 910 int rc; 911 912 smb_user_netinfo_init(user, &info); 913 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 914 smb_user_netinfo_fini(&info); 915 916 return (rc); 917 } 918 919 void 920 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 921 { 922 smb_session_t *session; 923 char *buf; 924 925 ASSERT(user); 926 ASSERT(user->u_domain); 927 ASSERT(user->u_name); 928 929 session = user->u_session; 930 ASSERT(session); 931 ASSERT(session->workstation); 932 933 info->ui_session_id = session->s_kid; 934 info->ui_native_os = session->native_os; 935 info->ui_ipaddr = session->ipaddr; 936 info->ui_numopens = session->s_file_cnt; 937 info->ui_smb_uid = user->u_uid; 938 info->ui_logon_time = user->u_logon_time; 939 info->ui_flags = user->u_flags; 940 info->ui_posix_uid = crgetuid(user->u_cred); 941 942 info->ui_domain_len = user->u_domain_len; 943 info->ui_domain = smb_mem_strdup(user->u_domain); 944 945 info->ui_account_len = user->u_name_len; 946 info->ui_account = smb_mem_strdup(user->u_name); 947 948 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 949 smb_session_getclient(session, buf, MAXNAMELEN); 950 info->ui_workstation_len = strlen(buf) + 1; 951 info->ui_workstation = smb_mem_strdup(buf); 952 kmem_free(buf, MAXNAMELEN); 953 } 954 955 void 956 smb_user_netinfo_fini(smb_netuserinfo_t *info) 957 { 958 if (info == NULL) 959 return; 960 961 if (info->ui_domain) 962 smb_mem_free(info->ui_domain); 963 if (info->ui_account) 964 smb_mem_free(info->ui_account); 965 if (info->ui_workstation) 966 smb_mem_free(info->ui_workstation); 967 968 bzero(info, sizeof (smb_netuserinfo_t)); 969 } 970 971 static void 972 smb_user_nonauth_logon(uint32_t audit_sid) 973 { 974 (void) smb_kdoor_upcall(SMB_DR_USER_NONAUTH_LOGON, 975 &audit_sid, xdr_uint32_t, NULL, NULL); 976 } 977 978 static void 979 smb_user_auth_logoff(uint32_t audit_sid) 980 { 981 (void) smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGOFF, 982 &audit_sid, xdr_uint32_t, NULL, NULL); 983 } 984 985 smb_token_t * 986 smb_get_token(smb_logon_t *user_info) 987 { 988 smb_token_t *token; 989 int rc; 990 991 token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP); 992 993 rc = smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGON, 994 user_info, smb_logon_xdr, token, smb_token_xdr); 995 996 if (rc != 0) { 997 kmem_free(token, sizeof (smb_token_t)); 998 return (NULL); 999 } 1000 1001 if (!smb_token_valid(token)) { 1002 smb_token_free(token); 1003 return (NULL); 1004 } 1005 1006 return (token); 1007 } 1008