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 2010 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. 151 * 152 * It should be noted that the reference count of a user registers the 153 * number of references to the user in other structures (such as an smb 154 * request). The reference count is not incremented in these 2 instances: 155 * 156 * 1) The user is logged in. An user is anchored by his state. If there's 157 * no activity involving a user currently logged in, the reference 158 * count of that user is zero. 159 * 160 * 2) The user is queued in the list of users of the session. The fact of 161 * being queued in that list is NOT registered by incrementing the 162 * reference count. 163 */ 164 #include <smbsrv/smb_kproto.h> 165 #include <smbsrv/smb_door.h> 166 167 168 #define ADMINISTRATORS_SID "S-1-5-32-544" 169 170 static smb_sid_t *smb_admins_sid = NULL; 171 172 static boolean_t smb_user_is_logged_in(smb_user_t *); 173 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); 174 static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *); 175 static void smb_user_nonauth_logon(uint32_t); 176 static void smb_user_auth_logoff(uint32_t); 177 178 int 179 smb_user_init(void) 180 { 181 if (smb_admins_sid != NULL) 182 return (0); 183 184 if ((smb_admins_sid = smb_sid_fromstr(ADMINISTRATORS_SID)) == NULL) 185 return (-1); 186 187 return (0); 188 } 189 190 void 191 smb_user_fini(void) 192 { 193 if (smb_admins_sid != NULL) { 194 smb_sid_free(smb_admins_sid); 195 smb_admins_sid = NULL; 196 } 197 } 198 199 /* 200 * smb_user_login 201 * 202 * 203 */ 204 smb_user_t * 205 smb_user_login( 206 smb_session_t *session, 207 cred_t *cr, 208 char *domain_name, 209 char *account_name, 210 uint32_t flags, 211 uint32_t privileges, 212 uint32_t audit_sid) 213 { 214 smb_user_t *user; 215 216 ASSERT(session); 217 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 218 ASSERT(cr); 219 ASSERT(account_name); 220 ASSERT(domain_name); 221 222 user = kmem_cache_alloc(session->s_server->si_cache_user, KM_SLEEP); 223 bzero(user, sizeof (smb_user_t)); 224 user->u_refcnt = 1; 225 user->u_session = session; 226 user->u_server = session->s_server; 227 user->u_logon_time = gethrestime_sec(); 228 user->u_flags = flags; 229 user->u_privileges = privileges; 230 user->u_name_len = strlen(account_name) + 1; 231 user->u_domain_len = strlen(domain_name) + 1; 232 user->u_name = smb_mem_strdup(account_name); 233 user->u_domain = smb_mem_strdup(domain_name); 234 user->u_cred = cr; 235 user->u_privcred = smb_cred_create_privs(cr, privileges); 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(user->u_cred); 244 if (user->u_privcred) 245 crhold(user->u_privcred); 246 user->u_state = SMB_USER_STATE_LOGGED_IN; 247 user->u_magic = SMB_USER_MAGIC; 248 smb_llist_enter(&session->s_user_list, RW_WRITER); 249 smb_llist_insert_tail(&session->s_user_list, user); 250 smb_llist_exit(&session->s_user_list); 251 atomic_inc_32(&session->s_server->sv_open_users); 252 return (user); 253 } 254 smb_idpool_free(&session->s_uid_pool, user->u_uid); 255 } 256 smb_mem_free(user->u_name); 257 smb_mem_free(user->u_domain); 258 kmem_cache_free(session->s_server->si_cache_user, user); 259 return (NULL); 260 } 261 262 /* 263 * Create a new user based on an existing user, used to support 264 * additional SessionSetupX requests for a user on a session. 265 * 266 * Assumes the caller has a reference on the original user from 267 * a user_lookup_by_x call. 268 */ 269 smb_user_t * 270 smb_user_dup( 271 smb_user_t *orig_user) 272 { 273 smb_user_t *user; 274 275 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 276 ASSERT(orig_user->u_refcnt); 277 278 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 279 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 280 orig_user->u_privileges, orig_user->u_audit_sid); 281 282 if (user) 283 smb_user_nonauth_logon(orig_user->u_audit_sid); 284 285 return (user); 286 } 287 288 /* 289 * smb_user_logoff 290 * 291 * Change the user state and disconnect trees. 292 * The user list must not be entered or modified here. 293 */ 294 void 295 smb_user_logoff( 296 smb_user_t *user) 297 { 298 ASSERT(user->u_magic == SMB_USER_MAGIC); 299 300 mutex_enter(&user->u_mutex); 301 ASSERT(user->u_refcnt); 302 switch (user->u_state) { 303 case SMB_USER_STATE_LOGGED_IN: { 304 /* 305 * The user is moved into a state indicating that the log off 306 * process has started. 307 */ 308 user->u_state = SMB_USER_STATE_LOGGING_OFF; 309 mutex_exit(&user->u_mutex); 310 atomic_dec_32(&user->u_server->sv_open_users); 311 /* 312 * All the trees hanging off of this user are disconnected. 313 */ 314 smb_user_disconnect_trees(user); 315 smb_user_auth_logoff(user->u_audit_sid); 316 mutex_enter(&user->u_mutex); 317 user->u_state = SMB_USER_STATE_LOGGED_OFF; 318 break; 319 } 320 case SMB_USER_STATE_LOGGED_OFF: 321 case SMB_USER_STATE_LOGGING_OFF: 322 break; 323 324 default: 325 ASSERT(0); 326 break; 327 } 328 mutex_exit(&user->u_mutex); 329 } 330 331 /* 332 * Take a reference on a user. 333 */ 334 boolean_t 335 smb_user_hold(smb_user_t *user) 336 { 337 ASSERT(user); 338 ASSERT(user->u_magic == SMB_USER_MAGIC); 339 340 mutex_enter(&user->u_mutex); 341 342 if (smb_user_is_logged_in(user)) { 343 user->u_refcnt++; 344 mutex_exit(&user->u_mutex); 345 return (B_TRUE); 346 } 347 348 mutex_exit(&user->u_mutex); 349 return (B_FALSE); 350 } 351 352 /* 353 * Release a reference on a user. If the reference count falls to 354 * zero and the user has logged off, post the object for deletion. 355 * Object deletion is deferred to avoid modifying a list while an 356 * iteration may be in progress. 357 */ 358 void 359 smb_user_release( 360 smb_user_t *user) 361 { 362 ASSERT(user->u_magic == SMB_USER_MAGIC); 363 364 mutex_enter(&user->u_mutex); 365 ASSERT(user->u_refcnt); 366 user->u_refcnt--; 367 switch (user->u_state) { 368 case SMB_USER_STATE_LOGGED_OFF: 369 if (user->u_refcnt == 0) 370 smb_session_post_user(user->u_session, user); 371 break; 372 373 case SMB_USER_STATE_LOGGED_IN: 374 case SMB_USER_STATE_LOGGING_OFF: 375 break; 376 377 default: 378 ASSERT(0); 379 break; 380 } 381 mutex_exit(&user->u_mutex); 382 } 383 384 void 385 smb_user_post_tree(smb_user_t *user, smb_tree_t *tree) 386 { 387 SMB_USER_VALID(user); 388 SMB_TREE_VALID(tree); 389 ASSERT(tree->t_refcnt == 0); 390 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED); 391 ASSERT(tree->t_user == user); 392 393 smb_llist_post(&user->u_tree_list, tree, smb_tree_dealloc); 394 } 395 396 397 /* 398 * Find a tree by tree-id. 399 */ 400 smb_tree_t * 401 smb_user_lookup_tree( 402 smb_user_t *user, 403 uint16_t tid) 404 405 { 406 smb_tree_t *tree; 407 408 ASSERT(user); 409 ASSERT(user->u_magic == SMB_USER_MAGIC); 410 411 smb_llist_enter(&user->u_tree_list, RW_READER); 412 tree = smb_llist_head(&user->u_tree_list); 413 414 while (tree) { 415 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 416 ASSERT(tree->t_user == user); 417 418 if (tree->t_tid == tid) { 419 if (smb_tree_hold(tree)) { 420 smb_llist_exit(&user->u_tree_list); 421 return (tree); 422 } else { 423 smb_llist_exit(&user->u_tree_list); 424 return (NULL); 425 } 426 } 427 428 tree = smb_llist_next(&user->u_tree_list, tree); 429 } 430 431 smb_llist_exit(&user->u_tree_list); 432 return (NULL); 433 } 434 435 /* 436 * Find the first connected tree that matches the specified sharename. 437 * If the specified tree is NULL the search starts from the beginning of 438 * the user's tree list. If a tree is provided the search starts just 439 * after that tree. 440 */ 441 smb_tree_t * 442 smb_user_lookup_share( 443 smb_user_t *user, 444 const char *sharename, 445 smb_tree_t *tree) 446 { 447 ASSERT(user); 448 ASSERT(user->u_magic == SMB_USER_MAGIC); 449 ASSERT(sharename); 450 451 smb_llist_enter(&user->u_tree_list, RW_READER); 452 453 if (tree) { 454 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 455 ASSERT(tree->t_user == user); 456 tree = smb_llist_next(&user->u_tree_list, tree); 457 } else { 458 tree = smb_llist_head(&user->u_tree_list); 459 } 460 461 while (tree) { 462 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 463 ASSERT(tree->t_user == user); 464 if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) { 465 if (smb_tree_hold(tree)) { 466 smb_llist_exit(&user->u_tree_list); 467 return (tree); 468 } 469 } 470 tree = smb_llist_next(&user->u_tree_list, tree); 471 } 472 473 smb_llist_exit(&user->u_tree_list); 474 return (NULL); 475 } 476 477 /* 478 * Find the first connected tree that matches the specified volume name. 479 * If the specified tree is NULL the search starts from the beginning of 480 * the user's tree list. If a tree is provided the search starts just 481 * after that tree. 482 */ 483 smb_tree_t * 484 smb_user_lookup_volume( 485 smb_user_t *user, 486 const char *name, 487 smb_tree_t *tree) 488 { 489 ASSERT(user); 490 ASSERT(user->u_magic == SMB_USER_MAGIC); 491 ASSERT(name); 492 493 smb_llist_enter(&user->u_tree_list, RW_READER); 494 495 if (tree) { 496 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 497 ASSERT(tree->t_user == user); 498 tree = smb_llist_next(&user->u_tree_list, tree); 499 } else { 500 tree = smb_llist_head(&user->u_tree_list); 501 } 502 503 while (tree) { 504 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 505 ASSERT(tree->t_user == user); 506 507 if (smb_strcasecmp(tree->t_volume, name, 0) == 0) { 508 if (smb_tree_hold(tree)) { 509 smb_llist_exit(&user->u_tree_list); 510 return (tree); 511 } 512 } 513 514 tree = smb_llist_next(&user->u_tree_list, tree); 515 } 516 517 smb_llist_exit(&user->u_tree_list); 518 return (NULL); 519 } 520 521 /* 522 * Disconnect all trees that match the specified client process-id. 523 */ 524 void 525 smb_user_close_pid( 526 smb_user_t *user, 527 uint16_t pid) 528 { 529 smb_tree_t *tree; 530 531 ASSERT(user); 532 ASSERT(user->u_magic == SMB_USER_MAGIC); 533 534 tree = smb_user_get_tree(&user->u_tree_list, NULL); 535 while (tree) { 536 smb_tree_t *next; 537 ASSERT(tree->t_user == user); 538 smb_tree_close_pid(tree, pid); 539 next = smb_user_get_tree(&user->u_tree_list, tree); 540 smb_tree_release(tree); 541 tree = next; 542 } 543 } 544 545 /* 546 * Disconnect all trees that this user has connected. 547 */ 548 void 549 smb_user_disconnect_trees( 550 smb_user_t *user) 551 { 552 smb_tree_t *tree; 553 554 ASSERT(user); 555 ASSERT(user->u_magic == SMB_USER_MAGIC); 556 557 tree = smb_user_get_tree(&user->u_tree_list, NULL); 558 while (tree) { 559 ASSERT(tree->t_user == user); 560 smb_tree_disconnect(tree, B_TRUE); 561 smb_tree_release(tree); 562 tree = smb_user_get_tree(&user->u_tree_list, NULL); 563 } 564 } 565 566 /* 567 * Disconnect all trees that match the specified share name. 568 */ 569 void 570 smb_user_disconnect_share( 571 smb_user_t *user, 572 const char *sharename) 573 { 574 smb_tree_t *tree; 575 smb_tree_t *next; 576 577 ASSERT(user); 578 ASSERT(user->u_magic == SMB_USER_MAGIC); 579 ASSERT(user->u_refcnt); 580 581 tree = smb_user_lookup_share(user, sharename, NULL); 582 while (tree) { 583 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 584 smb_session_cancel_requests(user->u_session, tree, NULL); 585 smb_tree_disconnect(tree, B_TRUE); 586 next = smb_user_lookup_share(user, sharename, tree); 587 smb_tree_release(tree); 588 tree = next; 589 } 590 } 591 592 /* 593 * Close a file by its unique id. 594 */ 595 int 596 smb_user_fclose(smb_user_t *user, uint32_t uniqid) 597 { 598 smb_llist_t *tree_list; 599 smb_tree_t *tree; 600 int rc = ENOENT; 601 602 ASSERT(user); 603 ASSERT(user->u_magic == SMB_USER_MAGIC); 604 605 tree_list = &user->u_tree_list; 606 ASSERT(tree_list); 607 608 smb_llist_enter(tree_list, RW_READER); 609 tree = smb_llist_head(tree_list); 610 611 while ((tree != NULL) && (rc == ENOENT)) { 612 ASSERT(tree->t_user == user); 613 614 if (smb_tree_hold(tree)) { 615 rc = smb_tree_fclose(tree, uniqid); 616 smb_tree_release(tree); 617 } 618 619 tree = smb_llist_next(tree_list, tree); 620 } 621 622 smb_llist_exit(tree_list); 623 return (rc); 624 } 625 626 /* 627 * Determine whether or not the user is an administrator. 628 * Members of the administrators group have administrative rights. 629 */ 630 boolean_t 631 smb_user_is_admin( 632 smb_user_t *user) 633 { 634 cred_t *u_cred; 635 636 ASSERT(user); 637 u_cred = user->u_cred; 638 ASSERT(u_cred); 639 640 if (smb_admins_sid == NULL) 641 return (B_FALSE); 642 643 if (smb_cred_is_member(u_cred, smb_admins_sid)) 644 return (B_TRUE); 645 646 return (B_FALSE); 647 } 648 649 /* 650 * This function should be called with a hold on the user. 651 */ 652 boolean_t 653 smb_user_namecmp(smb_user_t *user, const char *name) 654 { 655 char *fq_name; 656 boolean_t match; 657 658 if (smb_strcasecmp(name, user->u_name, 0) == 0) 659 return (B_TRUE); 660 661 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 662 663 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 664 user->u_domain, user->u_name); 665 666 match = (smb_strcasecmp(name, fq_name, 0) == 0); 667 if (!match) { 668 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 669 user->u_name, user->u_domain); 670 671 match = (smb_strcasecmp(name, fq_name, 0) == 0); 672 } 673 674 kmem_free(fq_name, MAXNAMELEN); 675 return (match); 676 } 677 678 /* 679 * If the enumeration request is for user data, handle the request 680 * here. Otherwise, pass it on to the trees. 681 * 682 * This function should be called with a hold on the user. 683 */ 684 int 685 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 686 { 687 smb_tree_t *tree; 688 smb_tree_t *next; 689 int rc; 690 691 ASSERT(user); 692 ASSERT(user->u_magic == SMB_USER_MAGIC); 693 694 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 695 return (smb_user_enum_private(user, svcenum)); 696 697 tree = smb_user_get_tree(&user->u_tree_list, NULL); 698 while (tree) { 699 ASSERT(tree->t_user == user); 700 701 rc = smb_tree_enum(tree, svcenum); 702 if (rc != 0) { 703 smb_tree_release(tree); 704 break; 705 } 706 707 next = smb_user_get_tree(&user->u_tree_list, tree); 708 smb_tree_release(tree); 709 tree = next; 710 } 711 712 return (rc); 713 } 714 715 /* *************************** Static Functions ***************************** */ 716 717 /* 718 * Determine whether or not a user is logged in. 719 * Typically, a reference can only be taken on a logged-in user. 720 * 721 * This is a private function and must be called with the user 722 * mutex held. 723 */ 724 static boolean_t 725 smb_user_is_logged_in(smb_user_t *user) 726 { 727 switch (user->u_state) { 728 case SMB_USER_STATE_LOGGED_IN: 729 return (B_TRUE); 730 731 case SMB_USER_STATE_LOGGING_OFF: 732 case SMB_USER_STATE_LOGGED_OFF: 733 return (B_FALSE); 734 735 default: 736 ASSERT(0); 737 return (B_FALSE); 738 } 739 } 740 741 /* 742 * Delete a user. The tree list should be empty. 743 * 744 * Remove the user from the session's user list before freeing resources 745 * associated with the user. 746 */ 747 void 748 smb_user_delete(void *arg) 749 { 750 smb_session_t *session; 751 smb_user_t *user = (smb_user_t *)arg; 752 753 SMB_USER_VALID(user); 754 ASSERT(user->u_refcnt == 0); 755 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 756 757 session = user->u_session; 758 smb_llist_enter(&session->s_user_list, RW_WRITER); 759 smb_llist_remove(&session->s_user_list, user); 760 smb_idpool_free(&session->s_uid_pool, user->u_uid); 761 smb_llist_exit(&session->s_user_list); 762 763 mutex_enter(&user->u_mutex); 764 mutex_exit(&user->u_mutex); 765 766 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 767 mutex_destroy(&user->u_mutex); 768 smb_llist_destructor(&user->u_tree_list); 769 smb_idpool_destructor(&user->u_tid_pool); 770 crfree(user->u_cred); 771 if (user->u_privcred) 772 crfree(user->u_privcred); 773 smb_mem_free(user->u_name); 774 smb_mem_free(user->u_domain); 775 kmem_cache_free(user->u_server->si_cache_user, user); 776 } 777 778 /* 779 * Get the next connected tree in the list. A reference is taken on 780 * the tree, which can be released later with smb_tree_release(). 781 * 782 * If the specified tree is NULL the search starts from the beginning of 783 * the tree list. If a tree is provided the search starts just after 784 * that tree. 785 * 786 * Returns NULL if there are no connected trees in the list. 787 */ 788 static smb_tree_t * 789 smb_user_get_tree( 790 smb_llist_t *tree_list, 791 smb_tree_t *tree) 792 { 793 ASSERT(tree_list); 794 795 smb_llist_enter(tree_list, RW_READER); 796 797 if (tree) { 798 ASSERT(tree->t_magic == SMB_TREE_MAGIC); 799 tree = smb_llist_next(tree_list, tree); 800 } else { 801 tree = smb_llist_head(tree_list); 802 } 803 804 while (tree) { 805 if (smb_tree_hold(tree)) 806 break; 807 808 tree = smb_llist_next(tree_list, tree); 809 } 810 811 smb_llist_exit(tree_list); 812 return (tree); 813 } 814 815 cred_t * 816 smb_user_getcred(smb_user_t *user) 817 { 818 return (user->u_cred); 819 } 820 821 cred_t * 822 smb_user_getprivcred(smb_user_t *user) 823 { 824 return ((user->u_privcred)? user->u_privcred : user->u_cred); 825 } 826 827 /* 828 * Private function to support smb_user_enum. 829 */ 830 static int 831 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 832 { 833 uint8_t *pb; 834 uint_t nbytes; 835 int rc; 836 837 if (svcenum->se_nskip > 0) { 838 svcenum->se_nskip--; 839 return (0); 840 } 841 842 if (svcenum->se_nitems >= svcenum->se_nlimit) { 843 svcenum->se_nitems = svcenum->se_nlimit; 844 return (0); 845 } 846 847 pb = &svcenum->se_buf[svcenum->se_bused]; 848 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 849 if (rc == 0) { 850 svcenum->se_bavail -= nbytes; 851 svcenum->se_bused += nbytes; 852 svcenum->se_nitems++; 853 } 854 855 return (rc); 856 } 857 858 /* 859 * Encode the NetInfo for a user into a buffer. NetInfo contains 860 * information that is often needed in user space to support RPC 861 * requests. 862 */ 863 int 864 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 865 uint32_t *nbytes) 866 { 867 smb_netuserinfo_t info; 868 int rc; 869 870 smb_user_netinfo_init(user, &info); 871 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 872 smb_user_netinfo_fini(&info); 873 874 return (rc); 875 } 876 877 void 878 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 879 { 880 smb_session_t *session; 881 char *buf; 882 883 ASSERT(user); 884 ASSERT(user->u_domain); 885 ASSERT(user->u_name); 886 887 session = user->u_session; 888 ASSERT(session); 889 ASSERT(session->workstation); 890 891 info->ui_session_id = session->s_kid; 892 info->ui_native_os = session->native_os; 893 info->ui_ipaddr = session->ipaddr; 894 info->ui_numopens = session->s_file_cnt; 895 info->ui_uid = user->u_uid; 896 info->ui_logon_time = user->u_logon_time; 897 info->ui_flags = user->u_flags; 898 899 info->ui_domain_len = user->u_domain_len; 900 info->ui_domain = smb_mem_strdup(user->u_domain); 901 902 info->ui_account_len = user->u_name_len; 903 info->ui_account = smb_mem_strdup(user->u_name); 904 905 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 906 smb_session_getclient(session, buf, MAXNAMELEN); 907 info->ui_workstation_len = strlen(buf) + 1; 908 info->ui_workstation = smb_mem_strdup(buf); 909 kmem_free(buf, MAXNAMELEN); 910 } 911 912 void 913 smb_user_netinfo_fini(smb_netuserinfo_t *info) 914 { 915 if (info == NULL) 916 return; 917 918 if (info->ui_domain) 919 smb_mem_free(info->ui_domain); 920 if (info->ui_account) 921 smb_mem_free(info->ui_account); 922 if (info->ui_workstation) 923 smb_mem_free(info->ui_workstation); 924 925 bzero(info, sizeof (smb_netuserinfo_t)); 926 } 927 928 static void 929 smb_user_nonauth_logon(uint32_t audit_sid) 930 { 931 (void) smb_kdoor_upcall(SMB_DR_USER_NONAUTH_LOGON, 932 &audit_sid, xdr_uint32_t, NULL, NULL); 933 } 934 935 static void 936 smb_user_auth_logoff(uint32_t audit_sid) 937 { 938 (void) smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGOFF, 939 &audit_sid, xdr_uint32_t, NULL, NULL); 940 } 941 942 smb_token_t * 943 smb_get_token(smb_logon_t *user_info) 944 { 945 smb_token_t *token; 946 int rc; 947 948 token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP); 949 950 rc = smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGON, 951 user_info, smb_logon_xdr, token, smb_token_xdr); 952 953 if (rc != 0) { 954 kmem_free(token, sizeof (smb_token_t)); 955 return (NULL); 956 } 957 958 if (!smb_token_valid(token)) { 959 smb_token_free(token); 960 return (NULL); 961 } 962 963 return (token); 964 } 965