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 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 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 <sys/types.h> 165 #include <sys/sid.h> 166 #include <sys/priv_names.h> 167 #include <smbsrv/smb_kproto.h> 168 #include <smbsrv/smb_door.h> 169 170 #define ADMINISTRATORS_SID "S-1-5-32-544" 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 void smb_user_nonauth_logon(smb_user_t *); 175 static void smb_user_auth_logoff(smb_user_t *); 176 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(smb_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 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 214 smb_user_setcred(user, cr, privileges); 215 user->u_state = SMB_USER_STATE_LOGGED_IN; 216 user->u_magic = SMB_USER_MAGIC; 217 smb_llist_enter(&session->s_user_list, RW_WRITER); 218 smb_llist_insert_tail(&session->s_user_list, user); 219 smb_llist_exit(&session->s_user_list); 220 smb_server_inc_users(session->s_server); 221 return (user); 222 } 223 smb_mem_free(user->u_name); 224 smb_mem_free(user->u_domain); 225 kmem_cache_free(smb_cache_user, user); 226 return (NULL); 227 } 228 229 /* 230 * Create a new user based on an existing user, used to support 231 * additional SessionSetupX requests for a user on a session. 232 * 233 * Assumes the caller has a reference on the original user from 234 * a user_lookup_by_x call. 235 */ 236 smb_user_t * 237 smb_user_dup( 238 smb_user_t *orig_user) 239 { 240 smb_user_t *user; 241 242 ASSERT(orig_user->u_magic == SMB_USER_MAGIC); 243 ASSERT(orig_user->u_refcnt); 244 245 user = smb_user_login(orig_user->u_session, orig_user->u_cred, 246 orig_user->u_domain, orig_user->u_name, orig_user->u_flags, 247 orig_user->u_privileges, orig_user->u_audit_sid); 248 249 if (user) 250 smb_user_nonauth_logon(orig_user); 251 252 return (user); 253 } 254 255 /* 256 * smb_user_logoff 257 * 258 * Change the user state and disconnect trees. 259 * The user list must not be entered or modified here. 260 */ 261 void 262 smb_user_logoff( 263 smb_user_t *user) 264 { 265 ASSERT(user->u_magic == SMB_USER_MAGIC); 266 267 mutex_enter(&user->u_mutex); 268 ASSERT(user->u_refcnt); 269 switch (user->u_state) { 270 case SMB_USER_STATE_LOGGED_IN: { 271 /* 272 * The user is moved into a state indicating that the log off 273 * process has started. 274 */ 275 user->u_state = SMB_USER_STATE_LOGGING_OFF; 276 mutex_exit(&user->u_mutex); 277 smb_session_disconnect_owned_trees(user->u_session, user); 278 smb_user_auth_logoff(user); 279 mutex_enter(&user->u_mutex); 280 user->u_state = SMB_USER_STATE_LOGGED_OFF; 281 smb_server_dec_users(user->u_server); 282 break; 283 } 284 case SMB_USER_STATE_LOGGED_OFF: 285 case SMB_USER_STATE_LOGGING_OFF: 286 break; 287 288 default: 289 ASSERT(0); 290 break; 291 } 292 mutex_exit(&user->u_mutex); 293 } 294 295 /* 296 * Take a reference on a user. Do not return a reference unless the user is in 297 * the logged-in state. 298 */ 299 boolean_t 300 smb_user_hold(smb_user_t *user) 301 { 302 SMB_USER_VALID(user); 303 304 mutex_enter(&user->u_mutex); 305 306 if (smb_user_is_logged_in(user)) { 307 user->u_refcnt++; 308 mutex_exit(&user->u_mutex); 309 return (B_TRUE); 310 } 311 312 mutex_exit(&user->u_mutex); 313 return (B_FALSE); 314 } 315 316 /* 317 * Unconditionally take a reference on a user. 318 */ 319 void 320 smb_user_hold_internal(smb_user_t *user) 321 { 322 SMB_USER_VALID(user); 323 324 mutex_enter(&user->u_mutex); 325 user->u_refcnt++; 326 mutex_exit(&user->u_mutex); 327 } 328 329 /* 330 * Release a reference on a user. If the reference count falls to 331 * zero and the user has logged off, post the object for deletion. 332 * Object deletion is deferred to avoid modifying a list while an 333 * iteration may be in progress. 334 */ 335 void 336 smb_user_release( 337 smb_user_t *user) 338 { 339 ASSERT(user->u_magic == SMB_USER_MAGIC); 340 341 mutex_enter(&user->u_mutex); 342 ASSERT(user->u_refcnt); 343 user->u_refcnt--; 344 345 switch (user->u_state) { 346 case SMB_USER_STATE_LOGGED_OFF: 347 if (user->u_refcnt == 0) 348 smb_session_post_user(user->u_session, user); 349 break; 350 351 case SMB_USER_STATE_LOGGED_IN: 352 case SMB_USER_STATE_LOGGING_OFF: 353 break; 354 355 default: 356 ASSERT(0); 357 break; 358 } 359 mutex_exit(&user->u_mutex); 360 } 361 362 /* 363 * Determine whether or not the user is an administrator. 364 * Members of the administrators group have administrative rights. 365 */ 366 boolean_t 367 smb_user_is_admin(smb_user_t *user) 368 { 369 #ifdef _KERNEL 370 char sidstr[SMB_SID_STRSZ]; 371 ksidlist_t *ksidlist; 372 ksid_t ksid1; 373 ksid_t *ksid2; 374 int i; 375 #endif /* _KERNEL */ 376 boolean_t rc = B_FALSE; 377 378 ASSERT(user); 379 ASSERT(user->u_cred); 380 381 if (SMB_USER_IS_ADMIN(user)) 382 return (B_TRUE); 383 384 #ifdef _KERNEL 385 bzero(&ksid1, sizeof (ksid_t)); 386 (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ); 387 ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0); 388 ksid1.ks_domain = ksid_lookupdomain(sidstr); 389 390 ksidlist = crgetsidlist(user->u_cred); 391 ASSERT(ksidlist); 392 ASSERT(ksid1.ks_domain); 393 ASSERT(ksid1.ks_domain->kd_name); 394 395 i = 0; 396 ksid2 = crgetsid(user->u_cred, KSID_USER); 397 do { 398 ASSERT(ksid2->ks_domain); 399 ASSERT(ksid2->ks_domain->kd_name); 400 401 if (strcmp(ksid1.ks_domain->kd_name, 402 ksid2->ks_domain->kd_name) == 0 && 403 ksid1.ks_rid == ksid2->ks_rid) { 404 user->u_flags |= SMB_USER_FLAG_ADMIN; 405 rc = B_TRUE; 406 break; 407 } 408 409 ksid2 = &ksidlist->ksl_sids[i]; 410 } while (i++ < ksidlist->ksl_nsid); 411 412 ksid_rele(&ksid1); 413 #endif /* _KERNEL */ 414 return (rc); 415 } 416 417 /* 418 * This function should be called with a hold on the user. 419 */ 420 boolean_t 421 smb_user_namecmp(smb_user_t *user, const char *name) 422 { 423 char *fq_name; 424 boolean_t match; 425 426 if (smb_strcasecmp(name, user->u_name, 0) == 0) 427 return (B_TRUE); 428 429 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 430 431 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 432 user->u_domain, user->u_name); 433 434 match = (smb_strcasecmp(name, fq_name, 0) == 0); 435 if (!match) { 436 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 437 user->u_name, user->u_domain); 438 439 match = (smb_strcasecmp(name, fq_name, 0) == 0); 440 } 441 442 kmem_free(fq_name, MAXNAMELEN); 443 return (match); 444 } 445 446 /* 447 * If the enumeration request is for user data, handle the request 448 * here. Otherwise, pass it on to the trees. 449 * 450 * This function should be called with a hold on the user. 451 */ 452 int 453 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 454 { 455 int rc = 0; 456 457 ASSERT(user); 458 ASSERT(user->u_magic == SMB_USER_MAGIC); 459 460 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 461 return (smb_user_enum_private(user, svcenum)); 462 463 return (rc); 464 } 465 466 /* *************************** Static Functions ***************************** */ 467 468 /* 469 * Determine whether or not a user is logged in. 470 * Typically, a reference can only be taken on a logged-in user. 471 * 472 * This is a private function and must be called with the user 473 * mutex held. 474 */ 475 static boolean_t 476 smb_user_is_logged_in(smb_user_t *user) 477 { 478 switch (user->u_state) { 479 case SMB_USER_STATE_LOGGED_IN: 480 return (B_TRUE); 481 482 case SMB_USER_STATE_LOGGING_OFF: 483 case SMB_USER_STATE_LOGGED_OFF: 484 return (B_FALSE); 485 486 default: 487 ASSERT(0); 488 return (B_FALSE); 489 } 490 } 491 492 /* 493 * Delete a user. The tree list should be empty. 494 * 495 * Remove the user from the session's user list before freeing resources 496 * associated with the user. 497 */ 498 void 499 smb_user_delete(void *arg) 500 { 501 smb_session_t *session; 502 smb_user_t *user = (smb_user_t *)arg; 503 504 SMB_USER_VALID(user); 505 ASSERT(user->u_refcnt == 0); 506 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 507 508 session = user->u_session; 509 smb_llist_enter(&session->s_user_list, RW_WRITER); 510 smb_llist_remove(&session->s_user_list, user); 511 smb_idpool_free(&session->s_uid_pool, user->u_uid); 512 smb_llist_exit(&session->s_user_list); 513 514 mutex_enter(&user->u_mutex); 515 mutex_exit(&user->u_mutex); 516 517 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 518 mutex_destroy(&user->u_mutex); 519 if (user->u_cred) 520 crfree(user->u_cred); 521 if (user->u_privcred) 522 crfree(user->u_privcred); 523 smb_mem_free(user->u_name); 524 smb_mem_free(user->u_domain); 525 kmem_cache_free(smb_cache_user, user); 526 } 527 528 cred_t * 529 smb_user_getcred(smb_user_t *user) 530 { 531 return (user->u_cred); 532 } 533 534 cred_t * 535 smb_user_getprivcred(smb_user_t *user) 536 { 537 return ((user->u_privcred)? user->u_privcred : user->u_cred); 538 } 539 540 #ifdef _KERNEL 541 /* 542 * Assign the user cred and privileges. 543 * 544 * If the user has backup and/or restore privleges, dup the cred 545 * and add those privileges to this new privileged cred. 546 */ 547 void 548 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges) 549 { 550 cred_t *privcred = NULL; 551 552 ASSERT(cr); 553 crhold(cr); 554 555 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE)) 556 privcred = crdup(cr); 557 558 if (privcred != NULL) { 559 if (privileges & SMB_USER_PRIV_BACKUP) { 560 (void) crsetpriv(privcred, PRIV_FILE_DAC_READ, 561 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL); 562 } 563 564 if (privileges & SMB_USER_PRIV_RESTORE) { 565 (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE, 566 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF, 567 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY, 568 PRIV_FILE_OWNER, PRIV_FILE_SETID, 569 PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL); 570 } 571 } 572 573 user->u_cred = cr; 574 user->u_privcred = privcred; 575 user->u_privileges = privileges; 576 } 577 #endif /* _KERNEL */ 578 579 /* 580 * Private function to support smb_user_enum. 581 */ 582 static int 583 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 584 { 585 uint8_t *pb; 586 uint_t nbytes; 587 int rc; 588 589 if (svcenum->se_nskip > 0) { 590 svcenum->se_nskip--; 591 return (0); 592 } 593 594 if (svcenum->se_nitems >= svcenum->se_nlimit) { 595 svcenum->se_nitems = svcenum->se_nlimit; 596 return (0); 597 } 598 599 pb = &svcenum->se_buf[svcenum->se_bused]; 600 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 601 if (rc == 0) { 602 svcenum->se_bavail -= nbytes; 603 svcenum->se_bused += nbytes; 604 svcenum->se_nitems++; 605 } 606 607 return (rc); 608 } 609 610 /* 611 * Encode the NetInfo for a user into a buffer. NetInfo contains 612 * information that is often needed in user space to support RPC 613 * requests. 614 */ 615 int 616 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 617 uint32_t *nbytes) 618 { 619 smb_netuserinfo_t info; 620 int rc; 621 622 smb_user_netinfo_init(user, &info); 623 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 624 smb_user_netinfo_fini(&info); 625 626 return (rc); 627 } 628 629 void 630 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 631 { 632 smb_session_t *session; 633 char *buf; 634 635 ASSERT(user); 636 ASSERT(user->u_domain); 637 ASSERT(user->u_name); 638 639 session = user->u_session; 640 ASSERT(session); 641 ASSERT(session->workstation); 642 643 info->ui_session_id = session->s_kid; 644 info->ui_native_os = session->native_os; 645 info->ui_ipaddr = session->ipaddr; 646 info->ui_numopens = session->s_file_cnt; 647 info->ui_smb_uid = user->u_uid; 648 info->ui_logon_time = user->u_logon_time; 649 info->ui_flags = user->u_flags; 650 info->ui_posix_uid = crgetuid(user->u_cred); 651 652 info->ui_domain_len = user->u_domain_len; 653 info->ui_domain = smb_mem_strdup(user->u_domain); 654 655 info->ui_account_len = user->u_name_len; 656 info->ui_account = smb_mem_strdup(user->u_name); 657 658 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 659 smb_session_getclient(session, buf, MAXNAMELEN); 660 info->ui_workstation_len = strlen(buf) + 1; 661 info->ui_workstation = smb_mem_strdup(buf); 662 kmem_free(buf, MAXNAMELEN); 663 } 664 665 void 666 smb_user_netinfo_fini(smb_netuserinfo_t *info) 667 { 668 if (info == NULL) 669 return; 670 671 if (info->ui_domain) 672 smb_mem_free(info->ui_domain); 673 if (info->ui_account) 674 smb_mem_free(info->ui_account); 675 if (info->ui_workstation) 676 smb_mem_free(info->ui_workstation); 677 678 bzero(info, sizeof (smb_netuserinfo_t)); 679 } 680 681 static void 682 smb_user_nonauth_logon(smb_user_t *user) 683 { 684 uint32_t audit_sid = user->u_audit_sid; 685 686 (void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_NONAUTH_LOGON, 687 &audit_sid, xdr_uint32_t, NULL, NULL); 688 } 689 690 static void 691 smb_user_auth_logoff(smb_user_t *user) 692 { 693 uint32_t audit_sid = user->u_audit_sid; 694 695 (void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF, 696 &audit_sid, xdr_uint32_t, NULL, NULL); 697 } 698 699 smb_token_t * 700 smb_get_token(smb_session_t *session, smb_logon_t *user_info) 701 { 702 smb_token_t *token; 703 int rc; 704 705 token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP); 706 707 rc = smb_kdoor_upcall(session->s_server, SMB_DR_USER_AUTH_LOGON, 708 user_info, smb_logon_xdr, token, smb_token_xdr); 709 710 if (rc != 0) { 711 kmem_free(token, sizeof (smb_token_t)); 712 return (NULL); 713 } 714 715 if (!smb_token_valid(token)) { 716 smb_token_free(token); 717 return (NULL); 718 } 719 720 return (token); 721 } 722