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 2014 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 * 72 * | T0: Creation/Allocation 73 * | (1st session setup) 74 * v 75 * +-----------------------------+ 76 * | SMB_USER_STATE_LOGGING_ON |<----------+ 77 * +-----------------------------+ addl. session setup 78 * | | (more proc. required) 79 * | T2 | ^ 80 * | | | T1: (cont.) 81 * | +------->-------? 82 * v | T3: (fail) 83 * +-----------------------------+ v 84 * | SMB_USER_STATE_LOGGED_ON | (logged off) 85 * +-----------------------------+ 86 * | 87 * | T4 88 * | 89 * v 90 * +-----------------------------+ 91 * | SMB_USER_STATE_LOGGING_OFF | 92 * +-----------------------------+ 93 * | 94 * | T5 95 * | 96 * v 97 * +-----------------------------+ T6 98 * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free 99 * +-----------------------------+ 100 * 101 * SMB_USER_STATE_LOGGING_ON 102 * 103 * While in this state: 104 * - The user is in the list of users for his session. 105 * - References will be given out ONLY for session setup. 106 * - This user can not access anything yet. 107 * 108 * SMB_USER_STATE_LOGGED_ON 109 * 110 * While in this state: 111 * - The user is in the list of users for his session. 112 * - References will be given out if the user is looked up. 113 * - The user can access files and pipes. 114 * 115 * SMB_USER_STATE_LOGGING_OFF 116 * 117 * While in this state: 118 * - The user is in the list of users for his session. 119 * - References will not be given out if the user is looked up. 120 * - The trees the user connected are being disconnected. 121 * - The resources associated with the user remain. 122 * 123 * SMB_USER_STATE_LOGGED_OFF 124 * 125 * While in this state: 126 * - The user is queued in the list of users of his session. 127 * - References will not be given out if the user is looked up. 128 * - The user has no more trees connected. 129 * - The resources associated with the user remain. 130 * 131 * Transition T0 132 * 133 * First request in an SMB Session Setup sequence creates a 134 * new user object and adds it to the list of users for 135 * this session. User UID is assigned and returned. 136 * 137 * Transition T1 138 * 139 * Subsequent SMB Session Setup requests (on the same UID 140 * assigned in T0) update the state of this user object, 141 * communicating with smbd for the crypto work. 142 * 143 * Transition T2 144 * 145 * If the SMB Session Setup sequence is successful, T2 146 * makes the new user object available for requests. 147 * 148 * Transition T3 149 * 150 * If an Session Setup request gets an error other than 151 * the expected "more processing required", then T3 152 * leads to state "LOGGED_OFF" and then tear-down of the 153 * partially constructed user. 154 * 155 * Transition T4 156 * 157 * Normal SMB User Logoff request, or session tear-down. 158 * 159 * Transition T5 160 * 161 * This transition occurs in smb_user_release(). The resources associated 162 * with the user are deleted as well as the user. For the transition to 163 * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the 164 * reference count be zero. 165 * 166 * Comments 167 * -------- 168 * 169 * The state machine of the user structures is controlled by 3 elements: 170 * - The list of users of the session he belongs to. 171 * - The mutex embedded in the structure itself. 172 * - The reference count. 173 * 174 * There's a mutex embedded in the user structure used to protect its fields 175 * and there's a lock embedded in the list of users of a session. To 176 * increment or to decrement the reference count the mutex must be entered. 177 * To insert the user into the list of users of the session and to remove 178 * the user from it, the lock must be entered in RW_WRITER mode. 179 * 180 * Rules of access to a user structure: 181 * 182 * 1) In order to avoid deadlocks, when both (mutex and lock of the session 183 * list) have to be entered, the lock must be entered first. 184 * 185 * 2) All actions applied to a user require a reference count. 186 * 187 * 3) There are 2 ways of getting a reference count. One is when the user 188 * logs in. The other when the user is looked up. 189 * 190 * It should be noted that the reference count of a user registers the 191 * number of references to the user in other structures (such as an smb 192 * request). The reference count is not incremented in these 2 instances: 193 * 194 * 1) The user is logged in. An user is anchored by his state. If there's 195 * no activity involving a user currently logged in, the reference 196 * count of that user is zero. 197 * 198 * 2) The user is queued in the list of users of the session. The fact of 199 * being queued in that list is NOT registered by incrementing the 200 * reference count. 201 */ 202 #include <sys/types.h> 203 #include <sys/sid.h> 204 #include <sys/priv_names.h> 205 #include <smbsrv/smb_kproto.h> 206 #include <smbsrv/smb_door.h> 207 208 #define ADMINISTRATORS_SID "S-1-5-32-544" 209 210 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); 211 static void smb_user_auth_logoff(smb_user_t *); 212 213 214 /* 215 * Create a new user. 216 */ 217 smb_user_t * 218 smb_user_new(smb_session_t *session) 219 { 220 smb_user_t *user; 221 222 ASSERT(session); 223 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 224 225 user = kmem_cache_alloc(smb_cache_user, KM_SLEEP); 226 bzero(user, sizeof (smb_user_t)); 227 228 user->u_refcnt = 1; 229 user->u_session = session; 230 user->u_server = session->s_server; 231 user->u_logon_time = gethrestime_sec(); 232 233 if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) 234 goto errout; 235 236 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 237 user->u_state = SMB_USER_STATE_LOGGING_ON; 238 user->u_magic = SMB_USER_MAGIC; 239 240 smb_llist_enter(&session->s_user_list, RW_WRITER); 241 smb_llist_insert_tail(&session->s_user_list, user); 242 smb_llist_exit(&session->s_user_list); 243 smb_server_inc_users(session->s_server); 244 245 return (user); 246 247 errout: 248 if (user->u_uid != 0) 249 smb_idpool_free(&session->s_uid_pool, user->u_uid); 250 kmem_cache_free(smb_cache_user, user); 251 return (NULL); 252 } 253 254 /* 255 * Fill in the details of a user, meaning a transition 256 * from state LOGGING_ON to state LOGGED_ON. 257 */ 258 int 259 smb_user_logon( 260 smb_user_t *user, 261 cred_t *cr, 262 char *domain_name, 263 char *account_name, 264 uint32_t flags, 265 uint32_t privileges, 266 uint32_t audit_sid) 267 { 268 269 ASSERT(user->u_magic == SMB_USER_MAGIC); 270 ASSERT(cr); 271 ASSERT(account_name); 272 ASSERT(domain_name); 273 274 mutex_enter(&user->u_mutex); 275 276 if (user->u_state != SMB_USER_STATE_LOGGING_ON) { 277 mutex_exit(&user->u_mutex); 278 return (-1); 279 } 280 281 smb_authsock_close(user); 282 283 user->u_state = SMB_USER_STATE_LOGGED_ON; 284 user->u_flags = flags; 285 user->u_name_len = strlen(account_name) + 1; 286 user->u_domain_len = strlen(domain_name) + 1; 287 user->u_name = smb_mem_strdup(account_name); 288 user->u_domain = smb_mem_strdup(domain_name); 289 user->u_audit_sid = audit_sid; 290 291 smb_user_setcred(user, cr, privileges); 292 293 mutex_exit(&user->u_mutex); 294 295 return (0); 296 } 297 298 /* 299 * smb_user_logoff 300 * 301 * Change the user state and disconnect trees. 302 * The user list must not be entered or modified here. 303 */ 304 void 305 smb_user_logoff( 306 smb_user_t *user) 307 { 308 ASSERT(user->u_magic == SMB_USER_MAGIC); 309 310 mutex_enter(&user->u_mutex); 311 ASSERT(user->u_refcnt); 312 switch (user->u_state) { 313 case SMB_USER_STATE_LOGGING_ON: { 314 smb_authsock_close(user); 315 user->u_state = SMB_USER_STATE_LOGGED_OFF; 316 smb_server_dec_users(user->u_server); 317 break; 318 } 319 320 case SMB_USER_STATE_LOGGED_ON: { 321 /* 322 * The user is moved into a state indicating that the log off 323 * process has started. 324 */ 325 user->u_state = SMB_USER_STATE_LOGGING_OFF; 326 mutex_exit(&user->u_mutex); 327 smb_session_disconnect_owned_trees(user->u_session, user); 328 smb_user_auth_logoff(user); 329 mutex_enter(&user->u_mutex); 330 user->u_state = SMB_USER_STATE_LOGGED_OFF; 331 smb_server_dec_users(user->u_server); 332 break; 333 } 334 case SMB_USER_STATE_LOGGED_OFF: 335 case SMB_USER_STATE_LOGGING_OFF: 336 break; 337 338 default: 339 ASSERT(0); 340 break; 341 } 342 mutex_exit(&user->u_mutex); 343 } 344 345 /* 346 * Take a reference on a user. Do not return a reference unless the user is in 347 * the logged-in state. 348 */ 349 boolean_t 350 smb_user_hold(smb_user_t *user) 351 { 352 SMB_USER_VALID(user); 353 354 mutex_enter(&user->u_mutex); 355 356 if (user->u_state == SMB_USER_STATE_LOGGED_ON) { 357 user->u_refcnt++; 358 mutex_exit(&user->u_mutex); 359 return (B_TRUE); 360 } 361 362 mutex_exit(&user->u_mutex); 363 return (B_FALSE); 364 } 365 366 /* 367 * Unconditionally take a reference on a user. 368 */ 369 void 370 smb_user_hold_internal(smb_user_t *user) 371 { 372 SMB_USER_VALID(user); 373 374 mutex_enter(&user->u_mutex); 375 user->u_refcnt++; 376 mutex_exit(&user->u_mutex); 377 } 378 379 /* 380 * Release a reference on a user. If the reference count falls to 381 * zero and the user has logged off, post the object for deletion. 382 * Object deletion is deferred to avoid modifying a list while an 383 * iteration may be in progress. 384 */ 385 void 386 smb_user_release( 387 smb_user_t *user) 388 { 389 ASSERT(user->u_magic == SMB_USER_MAGIC); 390 391 mutex_enter(&user->u_mutex); 392 ASSERT(user->u_refcnt); 393 user->u_refcnt--; 394 395 switch (user->u_state) { 396 case SMB_USER_STATE_LOGGED_OFF: 397 if (user->u_refcnt == 0) 398 smb_session_post_user(user->u_session, user); 399 break; 400 401 case SMB_USER_STATE_LOGGING_ON: 402 case SMB_USER_STATE_LOGGED_ON: 403 case SMB_USER_STATE_LOGGING_OFF: 404 break; 405 406 default: 407 ASSERT(0); 408 break; 409 } 410 mutex_exit(&user->u_mutex); 411 } 412 413 /* 414 * Determine whether or not the user is an administrator. 415 * Members of the administrators group have administrative rights. 416 */ 417 boolean_t 418 smb_user_is_admin(smb_user_t *user) 419 { 420 #ifdef _KERNEL 421 char sidstr[SMB_SID_STRSZ]; 422 ksidlist_t *ksidlist; 423 ksid_t ksid1; 424 ksid_t *ksid2; 425 int i; 426 #endif /* _KERNEL */ 427 boolean_t rc = B_FALSE; 428 429 ASSERT(user); 430 ASSERT(user->u_cred); 431 432 if (SMB_USER_IS_ADMIN(user)) 433 return (B_TRUE); 434 435 #ifdef _KERNEL 436 bzero(&ksid1, sizeof (ksid_t)); 437 (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ); 438 ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0); 439 ksid1.ks_domain = ksid_lookupdomain(sidstr); 440 441 ksidlist = crgetsidlist(user->u_cred); 442 ASSERT(ksidlist); 443 ASSERT(ksid1.ks_domain); 444 ASSERT(ksid1.ks_domain->kd_name); 445 446 i = 0; 447 ksid2 = crgetsid(user->u_cred, KSID_USER); 448 do { 449 ASSERT(ksid2->ks_domain); 450 ASSERT(ksid2->ks_domain->kd_name); 451 452 if (strcmp(ksid1.ks_domain->kd_name, 453 ksid2->ks_domain->kd_name) == 0 && 454 ksid1.ks_rid == ksid2->ks_rid) { 455 user->u_flags |= SMB_USER_FLAG_ADMIN; 456 rc = B_TRUE; 457 break; 458 } 459 460 ksid2 = &ksidlist->ksl_sids[i]; 461 } while (i++ < ksidlist->ksl_nsid); 462 463 ksid_rele(&ksid1); 464 #endif /* _KERNEL */ 465 return (rc); 466 } 467 468 /* 469 * This function should be called with a hold on the user. 470 */ 471 boolean_t 472 smb_user_namecmp(smb_user_t *user, const char *name) 473 { 474 char *fq_name; 475 boolean_t match; 476 477 if (smb_strcasecmp(name, user->u_name, 0) == 0) 478 return (B_TRUE); 479 480 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 481 482 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 483 user->u_domain, user->u_name); 484 485 match = (smb_strcasecmp(name, fq_name, 0) == 0); 486 if (!match) { 487 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 488 user->u_name, user->u_domain); 489 490 match = (smb_strcasecmp(name, fq_name, 0) == 0); 491 } 492 493 kmem_free(fq_name, MAXNAMELEN); 494 return (match); 495 } 496 497 /* 498 * If the enumeration request is for user data, handle the request 499 * here. Otherwise, pass it on to the trees. 500 * 501 * This function should be called with a hold on the user. 502 */ 503 int 504 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 505 { 506 int rc = 0; 507 508 ASSERT(user); 509 ASSERT(user->u_magic == SMB_USER_MAGIC); 510 511 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 512 return (smb_user_enum_private(user, svcenum)); 513 514 return (rc); 515 } 516 517 /* *************************** Static Functions ***************************** */ 518 519 /* 520 * Delete a user. The tree list should be empty. 521 * 522 * Remove the user from the session's user list before freeing resources 523 * associated with the user. 524 */ 525 void 526 smb_user_delete(void *arg) 527 { 528 smb_session_t *session; 529 smb_user_t *user = (smb_user_t *)arg; 530 531 SMB_USER_VALID(user); 532 ASSERT(user->u_refcnt == 0); 533 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 534 ASSERT(user->u_authsock == NULL); 535 536 session = user->u_session; 537 smb_llist_enter(&session->s_user_list, RW_WRITER); 538 smb_llist_remove(&session->s_user_list, user); 539 smb_idpool_free(&session->s_uid_pool, user->u_uid); 540 smb_llist_exit(&session->s_user_list); 541 542 mutex_enter(&user->u_mutex); 543 mutex_exit(&user->u_mutex); 544 545 user->u_magic = (uint32_t)~SMB_USER_MAGIC; 546 mutex_destroy(&user->u_mutex); 547 if (user->u_cred) 548 crfree(user->u_cred); 549 if (user->u_privcred) 550 crfree(user->u_privcred); 551 smb_mem_free(user->u_name); 552 smb_mem_free(user->u_domain); 553 kmem_cache_free(smb_cache_user, user); 554 } 555 556 cred_t * 557 smb_user_getcred(smb_user_t *user) 558 { 559 return (user->u_cred); 560 } 561 562 cred_t * 563 smb_user_getprivcred(smb_user_t *user) 564 { 565 return ((user->u_privcred)? user->u_privcred : user->u_cred); 566 } 567 568 #ifdef _KERNEL 569 /* 570 * Assign the user cred and privileges. 571 * 572 * If the user has backup and/or restore privleges, dup the cred 573 * and add those privileges to this new privileged cred. 574 */ 575 void 576 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges) 577 { 578 cred_t *privcred = NULL; 579 580 ASSERT(cr); 581 crhold(cr); 582 583 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE)) 584 privcred = crdup(cr); 585 586 if (privcred != NULL) { 587 if (privileges & SMB_USER_PRIV_BACKUP) { 588 (void) crsetpriv(privcred, PRIV_FILE_DAC_READ, 589 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL); 590 } 591 592 if (privileges & SMB_USER_PRIV_RESTORE) { 593 (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE, 594 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF, 595 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY, 596 PRIV_FILE_OWNER, PRIV_FILE_SETID, 597 PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL); 598 } 599 } 600 601 user->u_cred = cr; 602 user->u_privcred = privcred; 603 user->u_privileges = privileges; 604 } 605 #endif /* _KERNEL */ 606 607 /* 608 * Private function to support smb_user_enum. 609 */ 610 static int 611 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 612 { 613 uint8_t *pb; 614 uint_t nbytes; 615 int rc; 616 617 if (svcenum->se_nskip > 0) { 618 svcenum->se_nskip--; 619 return (0); 620 } 621 622 if (svcenum->se_nitems >= svcenum->se_nlimit) { 623 svcenum->se_nitems = svcenum->se_nlimit; 624 return (0); 625 } 626 627 pb = &svcenum->se_buf[svcenum->se_bused]; 628 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 629 if (rc == 0) { 630 svcenum->se_bavail -= nbytes; 631 svcenum->se_bused += nbytes; 632 svcenum->se_nitems++; 633 } 634 635 return (rc); 636 } 637 638 /* 639 * Encode the NetInfo for a user into a buffer. NetInfo contains 640 * information that is often needed in user space to support RPC 641 * requests. 642 */ 643 int 644 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 645 uint32_t *nbytes) 646 { 647 smb_netuserinfo_t info; 648 int rc; 649 650 smb_user_netinfo_init(user, &info); 651 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 652 smb_user_netinfo_fini(&info); 653 654 return (rc); 655 } 656 657 void 658 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 659 { 660 smb_session_t *session; 661 char *buf; 662 663 ASSERT(user); 664 ASSERT(user->u_domain); 665 ASSERT(user->u_name); 666 667 session = user->u_session; 668 ASSERT(session); 669 ASSERT(session->workstation); 670 671 info->ui_session_id = session->s_kid; 672 info->ui_native_os = session->native_os; 673 info->ui_ipaddr = session->ipaddr; 674 info->ui_numopens = session->s_file_cnt; 675 info->ui_smb_uid = user->u_uid; 676 info->ui_logon_time = user->u_logon_time; 677 info->ui_flags = user->u_flags; 678 info->ui_posix_uid = crgetuid(user->u_cred); 679 680 info->ui_domain_len = user->u_domain_len; 681 info->ui_domain = smb_mem_strdup(user->u_domain); 682 683 info->ui_account_len = user->u_name_len; 684 info->ui_account = smb_mem_strdup(user->u_name); 685 686 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 687 smb_session_getclient(session, buf, MAXNAMELEN); 688 info->ui_workstation_len = strlen(buf) + 1; 689 info->ui_workstation = smb_mem_strdup(buf); 690 kmem_free(buf, MAXNAMELEN); 691 } 692 693 void 694 smb_user_netinfo_fini(smb_netuserinfo_t *info) 695 { 696 if (info == NULL) 697 return; 698 699 if (info->ui_domain) 700 smb_mem_free(info->ui_domain); 701 if (info->ui_account) 702 smb_mem_free(info->ui_account); 703 if (info->ui_workstation) 704 smb_mem_free(info->ui_workstation); 705 706 bzero(info, sizeof (smb_netuserinfo_t)); 707 } 708 709 static void 710 smb_user_auth_logoff(smb_user_t *user) 711 { 712 uint32_t audit_sid = user->u_audit_sid; 713 714 (void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF, 715 &audit_sid, xdr_uint32_t, NULL, NULL); 716 } 717