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 2018 Nexenta Systems, Inc. All rights reserved.
  24  * Copyright (c) 2016 by Delphix. All rights reserved.
  25  */
  26 
  27 /*
  28  * General Structures Layout
  29  * -------------------------
  30  *
  31  * This is a simplified diagram showing the relationship between most of the
  32  * main structures.
  33  *
  34  * +-------------------+
  35  * |     SMB_INFO      |
  36  * +-------------------+
  37  *          |
  38  *          |
  39  *          v
  40  * +-------------------+       +-------------------+      +-------------------+
  41  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
  42  * +-------------------+       +-------------------+      +-------------------+
  43  *   |          |
  44  *   |          |
  45  *   |          v
  46  *   |  +-------------------+     +-------------------+   +-------------------+
  47  *   |  |       USER        |<--->|       USER        |...|       USER        |
  48  *   |  +-------------------+     +-------------------+   +-------------------+
  49  *   |
  50  *   |
  51  *   v
  52  * +-------------------+       +-------------------+      +-------------------+
  53  * |       TREE        |<----->|       TREE        |......|       TREE        |
  54  * +-------------------+       +-------------------+      +-------------------+
  55  *      |         |
  56  *      |         |
  57  *      |         v
  58  *      |     +-------+       +-------+      +-------+
  59  *      |     | OFILE |<----->| OFILE |......| OFILE |
  60  *      |     +-------+       +-------+      +-------+
  61  *      |
  62  *      |
  63  *      v
  64  *  +-------+       +------+      +------+
  65  *  | ODIR  |<----->| ODIR |......| ODIR |
  66  *  +-------+       +------+      +------+
  67  *
  68  *
  69  * User State Machine
  70  * ------------------
  71  *
  72  *
  73  *                  | T0:  Creation/Allocation
  74  *                  |      (1st session setup)
  75  *                  v
  76  *    +-----------------------------+
  77  *    |  SMB_USER_STATE_LOGGING_ON  |<----------+
  78  *    +-----------------------------+    addl. session setup
  79  *                  |           |       (more proc. required)
  80  *                  | T2        |               ^
  81  *                  |           |               | T1: (cont.)
  82  *                  |           +------->-------?
  83  *                  v                           | T3: (fail)
  84  *    +-----------------------------+           v
  85  *    |  SMB_USER_STATE_LOGGED_ON   |       (logged off)
  86  *    +-----------------------------+
  87  *                  |
  88  *                  | T4
  89  *                  |
  90  *                  v
  91  *    +-----------------------------+
  92  *    |  SMB_USER_STATE_LOGGING_OFF |
  93  *    +-----------------------------+
  94  *                  |
  95  *                  | T5
  96  *                  |
  97  *                  v
  98  *    +-----------------------------+    T6
  99  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
 100  *    +-----------------------------+
 101  *
 102  * SMB_USER_STATE_LOGGING_ON
 103  *
 104  *    While in this state:
 105  *      - The user is in the list of users for their session.
 106  *      - References will be given out ONLY for session setup.
 107  *      - This user can not access anything yet.
 108  *
 109  * SMB_USER_STATE_LOGGED_ON
 110  *
 111  *    While in this state:
 112  *      - The user is in the list of users for their session.
 113  *      - References will be given out if the user is looked up.
 114  *      - The user can access files and pipes.
 115  *
 116  * SMB_USER_STATE_LOGGING_OFF
 117  *
 118  *    While in this state:
 119  *      - The user is in the list of users for their session.
 120  *      - References will not be given out if the user is looked up.
 121  *      - The trees the user connected are being disconnected.
 122  *      - The resources associated with the user remain.
 123  *
 124  * SMB_USER_STATE_LOGGED_OFF
 125  *
 126  *    While in this state:
 127  *      - The user is queued in the list of users of their session.
 128  *      - References will not be given out if the user is looked up.
 129  *      - The user has no more trees connected.
 130  *      - The resources associated with the user remain.
 131  *
 132  * Transition T0
 133  *
 134  *    First request in an SMB Session Setup sequence creates a
 135  *    new user object and adds it to the list of users for
 136  *    this session.  User UID is assigned and returned.
 137  *
 138  * Transition T1
 139  *
 140  *    Subsequent SMB Session Setup requests (on the same UID
 141  *    assigned in T0) update the state of this user object,
 142  *    communicating with smbd for the crypto work.
 143  *
 144  * Transition T2
 145  *
 146  *    If the SMB Session Setup sequence is successful, T2
 147  *    makes the new user object available for requests.
 148  *
 149  * Transition T3
 150  *
 151  *    If an Session Setup request gets an error other than
 152  *    the expected "more processing required", then T3
 153  *    leads to state "LOGGED_OFF" and then tear-down of the
 154  *    partially constructed user.
 155  *
 156  * Transition T4
 157  *
 158  *    Normal SMB User Logoff request, or session tear-down.
 159  *
 160  * Transition T5
 161  *
 162  *    This transition occurs in smb_user_release(). The resources associated
 163  *    with the user are deleted as well as the user. For the transition to
 164  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
 165  *    reference count be zero.
 166  *
 167  * Comments
 168  * --------
 169  *
 170  *    The state machine of the user structures is controlled by 3 elements:
 171  *      - The list of users of the session they belong to.
 172  *      - The mutex embedded in the structure itself.
 173  *      - The reference count.
 174  *
 175  *    There's a mutex embedded in the user structure used to protect its fields
 176  *    and there's a lock embedded in the list of users of a session. To
 177  *    increment or to decrement the reference count the mutex must be entered.
 178  *    To insert the user into the list of users of the session and to remove
 179  *    the user from it, the lock must be entered in RW_WRITER mode.
 180  *
 181  *    Rules of access to a user structure:
 182  *
 183  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
 184  *       list) have to be entered, the lock must be entered first. Additionally,
 185  *       one may NOT flush the deleteq of either the tree list or the ofile list
 186  *       while the user mutex is held.
 187  *
 188  *    2) All actions applied to a user require a reference count.
 189  *
 190  *    3) There are 2 ways of getting a reference count. One is when the user
 191  *       logs in. The other when the user is looked up.
 192  *
 193  *    It should be noted that the reference count of a user registers the
 194  *    number of references to the user in other structures (such as an smb
 195  *    request). The reference count is not incremented in these 2 instances:
 196  *
 197  *    1) The user is logged in. An user is anchored by their state. If there's
 198  *       no activity involving a user currently logged in, the reference
 199  *       count of that user is zero.
 200  *
 201  *    2) The user is queued in the list of users of the session. The fact of
 202  *       being queued in that list is NOT registered by incrementing the
 203  *       reference count.
 204  */
 205 #include <sys/types.h>
 206 #include <sys/sid.h>
 207 #include <sys/priv_names.h>
 208 #include <smbsrv/smb_kproto.h>
 209 #include <smbsrv/smb_door.h>
 210 
 211 #define ADMINISTRATORS_SID      "S-1-5-32-544"
 212 
 213 /* Don't leak object addresses */
 214 #define SMB_USER_SSNID(u) \
 215         ((uintptr_t)&smb_cache_user ^ (uintptr_t)(u))
 216 
 217 static void smb_user_delete(void *);
 218 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
 219 static void smb_user_auth_logoff(smb_user_t *);
 220 static void smb_user_logoff_tq(void *);
 221 
 222 /*
 223  * Create a new user.
 224  *
 225  * For SMB2 and later, session IDs (u_ssnid) need to be unique among all
 226  * current and "recent" sessions.  The session ID is derived from the
 227  * address of the smb_user object (obscured by XOR with a constant).
 228  * This adds a 3-bit generation number in the low bits, incremented
 229  * when we allocate an smb_user_t from its kmem cache, so it can't
 230  * be confused with a (recent) previous incarnation of this object.
 231  */
 232 smb_user_t *
 233 smb_user_new(smb_session_t *session)
 234 {
 235         smb_user_t      *user;
 236         uint_t          gen;    // generation (low 3 bits of ssnid)
 237 
 238         ASSERT(session);
 239         ASSERT(session->s_magic == SMB_SESSION_MAGIC);
 240 
 241         user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
 242         gen = (user->u_ssnid + 1) & 7;
 243         bzero(user, sizeof (smb_user_t));
 244 
 245         user->u_refcnt = 1;
 246         user->u_session = session;
 247         user->u_server = session->s_server;
 248         user->u_logon_time = gethrestime_sec();
 249 
 250         if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
 251                 goto errout;
 252         user->u_ssnid = SMB_USER_SSNID(user) + gen;
 253 
 254         mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
 255         user->u_state = SMB_USER_STATE_LOGGING_ON;
 256         user->u_magic = SMB_USER_MAGIC;
 257 
 258         smb_llist_enter(&session->s_user_list, RW_WRITER);
 259         smb_llist_insert_tail(&session->s_user_list, user);
 260         smb_llist_exit(&session->s_user_list);
 261         smb_server_inc_users(session->s_server);
 262 
 263         return (user);
 264 
 265 errout:
 266         if (user->u_uid != 0)
 267                 smb_idpool_free(&session->s_uid_pool, user->u_uid);
 268         kmem_cache_free(smb_cache_user, user);
 269         return (NULL);
 270 }
 271 
 272 /*
 273  * Fill in the details of a user, meaning a transition
 274  * from state LOGGING_ON to state LOGGED_ON.
 275  */
 276 int
 277 smb_user_logon(
 278     smb_user_t          *user,
 279     cred_t              *cr,
 280     char                *domain_name,
 281     char                *account_name,
 282     uint32_t            flags,
 283     uint32_t            privileges,
 284     uint32_t            audit_sid)
 285 {
 286         ksocket_t authsock = NULL;
 287 
 288         ASSERT(user->u_magic == SMB_USER_MAGIC);
 289         ASSERT(cr);
 290         ASSERT(account_name);
 291         ASSERT(domain_name);
 292 
 293         mutex_enter(&user->u_mutex);
 294 
 295         if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
 296                 mutex_exit(&user->u_mutex);
 297                 return (-1);
 298         }
 299 
 300         /*
 301          * In the transition from LOGGING_ON to LOGGED_ON,
 302          * we always have an auth. socket to close.
 303          */
 304         authsock = user->u_authsock;
 305         user->u_authsock = NULL;
 306         if (user->u_auth_tmo != NULL) {
 307                 (void) untimeout(user->u_auth_tmo);
 308                 user->u_auth_tmo = NULL;
 309         }
 310 
 311         user->u_state = SMB_USER_STATE_LOGGED_ON;
 312         user->u_flags = flags;
 313         user->u_name_len = strlen(account_name) + 1;
 314         user->u_domain_len = strlen(domain_name) + 1;
 315         user->u_name = smb_mem_strdup(account_name);
 316         user->u_domain = smb_mem_strdup(domain_name);
 317         user->u_audit_sid = audit_sid;
 318 
 319         smb_user_setcred(user, cr, privileges);
 320 
 321         mutex_exit(&user->u_mutex);
 322 
 323         /* This close can block, so not under the mutex. */
 324         if (authsock != NULL)
 325                 smb_authsock_close(user, authsock);
 326 
 327         return (0);
 328 }
 329 
 330 /*
 331  * smb_user_logoff
 332  *
 333  * Change the user state to "logging off" and disconnect trees.
 334  * The user list must not be entered or modified here.
 335  *
 336  * We remain in state "logging off" until the last ref. is gone,
 337  * then smb_user_release takes us to state "logged off".
 338  */
 339 void
 340 smb_user_logoff(
 341     smb_user_t          *user)
 342 {
 343         ksocket_t authsock = NULL;
 344 
 345         ASSERT(user->u_magic == SMB_USER_MAGIC);
 346 
 347         mutex_enter(&user->u_mutex);
 348         ASSERT(user->u_refcnt);
 349         switch (user->u_state) {
 350         case SMB_USER_STATE_LOGGING_ON:
 351                 authsock = user->u_authsock;
 352                 user->u_authsock = NULL;
 353                 if (user->u_auth_tmo != NULL) {
 354                         (void) untimeout(user->u_auth_tmo);
 355                         user->u_auth_tmo = NULL;
 356                 }
 357                 user->u_state = SMB_USER_STATE_LOGGING_OFF;
 358                 mutex_exit(&user->u_mutex);
 359                 /* This close can block, so not under the mutex. */
 360                 if (authsock != NULL) {
 361                         smb_authsock_close(user, authsock);
 362                 }
 363                 break;
 364 
 365         case SMB_USER_STATE_LOGGED_ON:
 366                 /*
 367                  * The user is moved into a state indicating that the log off
 368                  * process has started.
 369                  */
 370                 user->u_state = SMB_USER_STATE_LOGGING_OFF;
 371                 mutex_exit(&user->u_mutex);
 372                 smb_session_disconnect_owned_trees(user->u_session, user);
 373                 smb_user_auth_logoff(user);
 374                 break;
 375 
 376         case SMB_USER_STATE_LOGGED_OFF:
 377         case SMB_USER_STATE_LOGGING_OFF:
 378                 mutex_exit(&user->u_mutex);
 379                 break;
 380 
 381         default:
 382                 ASSERT(0);
 383                 mutex_exit(&user->u_mutex);
 384                 break;
 385         }
 386 }
 387 
 388 /*
 389  * Take a reference on a user.  Do not return a reference unless the user is in
 390  * the logged-in state.
 391  */
 392 boolean_t
 393 smb_user_hold(smb_user_t *user)
 394 {
 395         SMB_USER_VALID(user);
 396 
 397         mutex_enter(&user->u_mutex);
 398 
 399         if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
 400                 user->u_refcnt++;
 401                 mutex_exit(&user->u_mutex);
 402                 return (B_TRUE);
 403         }
 404 
 405         mutex_exit(&user->u_mutex);
 406         return (B_FALSE);
 407 }
 408 
 409 /*
 410  * Unconditionally take a reference on a user.
 411  */
 412 void
 413 smb_user_hold_internal(smb_user_t *user)
 414 {
 415         SMB_USER_VALID(user);
 416 
 417         mutex_enter(&user->u_mutex);
 418         user->u_refcnt++;
 419         mutex_exit(&user->u_mutex);
 420 }
 421 
 422 /*
 423  * Release a reference on a user.  If the reference count falls to
 424  * zero and the user has logged off, post the object for deletion.
 425  * Object deletion is deferred to avoid modifying a list while an
 426  * iteration may be in progress.
 427  */
 428 void
 429 smb_user_release(
 430     smb_user_t          *user)
 431 {
 432         smb_session_t *ssn = user->u_session;
 433 
 434         SMB_USER_VALID(user);
 435 
 436         /* flush the tree list delete queue */
 437         smb_llist_flush(&ssn->s_tree_list);
 438 
 439         mutex_enter(&user->u_mutex);
 440         ASSERT(user->u_refcnt);
 441         user->u_refcnt--;
 442 
 443         switch (user->u_state) {
 444         case SMB_USER_STATE_LOGGING_OFF:
 445                 if (user->u_refcnt == 0) {
 446                         smb_session_t *ssn = user->u_session;
 447                         user->u_state = SMB_USER_STATE_LOGGED_OFF;
 448                         smb_llist_post(&ssn->s_user_list, user,
 449                             smb_user_delete);
 450                 }
 451                 break;
 452 
 453         case SMB_USER_STATE_LOGGING_ON:
 454         case SMB_USER_STATE_LOGGED_ON:
 455                 break;
 456 
 457         case SMB_USER_STATE_LOGGED_OFF:
 458         default:
 459                 ASSERT(0);
 460                 break;
 461         }
 462         mutex_exit(&user->u_mutex);
 463 }
 464 
 465 /*
 466  * Timeout handler for user logons that stay too long in
 467  * state SMB_USER_STATE_LOGGING_ON.  This is setup by a
 468  * timeout call in smb_authsock_open, and called in a
 469  * callout thread, so schedule a taskq job to do the
 470  * real work of logging off this user.
 471  */
 472 void
 473 smb_user_auth_tmo(void *arg)
 474 {
 475         smb_user_t *user = arg;
 476         smb_request_t *sr;
 477 
 478         SMB_USER_VALID(user);
 479 
 480         /*
 481          * If we can't allocate a request, it means the
 482          * session is being torn down, so nothing to do.
 483          */
 484         sr = smb_request_alloc(user->u_session, 0);
 485         if (sr == NULL)
 486                 return;
 487 
 488         /*
 489          * Check user state, and take a hold if it's
 490          * still logging on.  If not, we're done.
 491          */
 492         mutex_enter(&user->u_mutex);
 493         if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
 494                 mutex_exit(&user->u_mutex);
 495                 smb_request_free(sr);
 496                 return;
 497         }
 498         /* smb_user_hold_internal */
 499         user->u_refcnt++;
 500         mutex_exit(&user->u_mutex);
 501 
 502         /*
 503          * The user hold is given to the SR, and released in
 504          * smb_user_logoff_tq / smb_request_free
 505          */
 506         sr->uid_user = user;
 507         sr->user_cr = user->u_cred;
 508         sr->sr_state = SMB_REQ_STATE_SUBMITTED;
 509 
 510         (void) taskq_dispatch(
 511             user->u_server->sv_worker_pool,
 512             smb_user_logoff_tq, sr, TQ_SLEEP);
 513 }
 514 
 515 /*
 516  * Helper for smb_user_auth_tmo()
 517  */
 518 static void
 519 smb_user_logoff_tq(void *arg)
 520 {
 521         smb_request_t   *sr = arg;
 522 
 523         SMB_REQ_VALID(sr);
 524 
 525         mutex_enter(&sr->sr_mutex);
 526         sr->sr_worker = curthread;
 527         sr->sr_state = SMB_REQ_STATE_ACTIVE;
 528         mutex_exit(&sr->sr_mutex);
 529 
 530         smb_user_logoff(sr->uid_user);
 531 
 532         sr->sr_state = SMB_REQ_STATE_COMPLETED;
 533         smb_request_free(sr);
 534 }
 535 
 536 /*
 537  * Determine whether or not the user is an administrator.
 538  * Members of the administrators group have administrative rights.
 539  */
 540 boolean_t
 541 smb_user_is_admin(smb_user_t *user)
 542 {
 543 #ifdef  _KERNEL
 544         char            sidstr[SMB_SID_STRSZ];
 545         ksidlist_t      *ksidlist;
 546         ksid_t          ksid1;
 547         ksid_t          *ksid2;
 548         int             i;
 549 #endif  /* _KERNEL */
 550         boolean_t       rc = B_FALSE;
 551 
 552         ASSERT(user);
 553         ASSERT(user->u_cred);
 554 
 555         if (SMB_USER_IS_ADMIN(user))
 556                 return (B_TRUE);
 557 
 558 #ifdef  _KERNEL
 559         bzero(&ksid1, sizeof (ksid_t));
 560         (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
 561         ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
 562         ksid1.ks_domain = ksid_lookupdomain(sidstr);
 563 
 564         ksidlist = crgetsidlist(user->u_cred);
 565         ASSERT(ksidlist);
 566         ASSERT(ksid1.ks_domain);
 567         ASSERT(ksid1.ks_domain->kd_name);
 568 
 569         i = 0;
 570         ksid2 = crgetsid(user->u_cred, KSID_USER);
 571         do {
 572                 ASSERT(ksid2->ks_domain);
 573                 ASSERT(ksid2->ks_domain->kd_name);
 574 
 575                 if (strcmp(ksid1.ks_domain->kd_name,
 576                     ksid2->ks_domain->kd_name) == 0 &&
 577                     ksid1.ks_rid == ksid2->ks_rid) {
 578                         user->u_flags |= SMB_USER_FLAG_ADMIN;
 579                         rc = B_TRUE;
 580                         break;
 581                 }
 582 
 583                 ksid2 = &ksidlist->ksl_sids[i];
 584         } while (i++ < ksidlist->ksl_nsid);
 585 
 586         ksid_rele(&ksid1);
 587 #endif  /* _KERNEL */
 588         return (rc);
 589 }
 590 
 591 /*
 592  * This function should be called with a hold on the user.
 593  */
 594 boolean_t
 595 smb_user_namecmp(smb_user_t *user, const char *name)
 596 {
 597         char            *fq_name;
 598         boolean_t       match;
 599 
 600         if (smb_strcasecmp(name, user->u_name, 0) == 0)
 601                 return (B_TRUE);
 602 
 603         fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 604 
 605         (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
 606             user->u_domain, user->u_name);
 607 
 608         match = (smb_strcasecmp(name, fq_name, 0) == 0);
 609         if (!match) {
 610                 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
 611                     user->u_name, user->u_domain);
 612 
 613                 match = (smb_strcasecmp(name, fq_name, 0) == 0);
 614         }
 615 
 616         kmem_free(fq_name, MAXNAMELEN);
 617         return (match);
 618 }
 619 
 620 /*
 621  * If the enumeration request is for user data, handle the request
 622  * here.  Otherwise, pass it on to the trees.
 623  *
 624  * This function should be called with a hold on the user.
 625  */
 626 int
 627 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
 628 {
 629         int             rc = 0;
 630 
 631         ASSERT(user);
 632         ASSERT(user->u_magic == SMB_USER_MAGIC);
 633 
 634         if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
 635                 return (smb_user_enum_private(user, svcenum));
 636 
 637         return (rc);
 638 }
 639 
 640 /* *************************** Static Functions ***************************** */
 641 
 642 /*
 643  * Delete a user.  The tree list should be empty.
 644  *
 645  * Remove the user from the session's user list before freeing resources
 646  * associated with the user.
 647  */
 648 static void
 649 smb_user_delete(void *arg)
 650 {
 651         smb_session_t   *session;
 652         smb_user_t      *user = (smb_user_t *)arg;
 653         uint32_t        ucount;
 654 
 655         SMB_USER_VALID(user);
 656         ASSERT(user->u_refcnt == 0);
 657         ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
 658         ASSERT(user->u_authsock == NULL);
 659         ASSERT(user->u_auth_tmo == NULL);
 660 
 661         session = user->u_session;
 662 
 663         smb_server_dec_users(session->s_server);
 664         smb_llist_enter(&session->s_user_list, RW_WRITER);
 665         smb_llist_remove(&session->s_user_list, user);
 666         smb_idpool_free(&session->s_uid_pool, user->u_uid);
 667         ucount = smb_llist_get_count(&session->s_user_list);
 668         smb_llist_exit(&session->s_user_list);
 669 
 670         if (ucount == 0) {
 671                 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 672                 session->s_state = SMB_SESSION_STATE_SHUTDOWN;
 673                 smb_rwx_cvbcast(&session->s_lock);
 674                 smb_rwx_rwexit(&session->s_lock);
 675         }
 676 
 677         /*
 678          * This user is no longer on s_user_list, however...
 679          *
 680          * This is called via smb_llist_post, which means it may run
 681          * BEFORE smb_user_release drops u_mutex (if another thread
 682          * flushes the delete queue before we do).  Synchronize.
 683          */
 684         mutex_enter(&user->u_mutex);
 685         mutex_exit(&user->u_mutex);
 686 
 687         user->u_magic = (uint32_t)~SMB_USER_MAGIC;
 688         mutex_destroy(&user->u_mutex);
 689         if (user->u_cred)
 690                 crfree(user->u_cred);
 691         if (user->u_privcred)
 692                 crfree(user->u_privcred);
 693         smb_mem_free(user->u_name);
 694         smb_mem_free(user->u_domain);
 695         kmem_cache_free(smb_cache_user, user);
 696 }
 697 
 698 cred_t *
 699 smb_user_getcred(smb_user_t *user)
 700 {
 701         return (user->u_cred);
 702 }
 703 
 704 cred_t *
 705 smb_user_getprivcred(smb_user_t *user)
 706 {
 707         return ((user->u_privcred)? user->u_privcred : user->u_cred);
 708 }
 709 
 710 #ifdef  _KERNEL
 711 /*
 712  * Assign the user cred and privileges.
 713  *
 714  * If the user has backup and/or restore privleges, dup the cred
 715  * and add those privileges to this new privileged cred.
 716  */
 717 void
 718 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
 719 {
 720         cred_t *privcred = NULL;
 721 
 722         ASSERT(cr);
 723         crhold(cr);
 724 
 725         if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
 726                 privcred = crdup(cr);
 727 
 728         if (privcred != NULL) {
 729                 if (privileges & SMB_USER_PRIV_BACKUP) {
 730                         (void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
 731                             PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
 732                 }
 733 
 734                 if (privileges & SMB_USER_PRIV_RESTORE) {
 735                         (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
 736                             PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
 737                             PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
 738                             PRIV_FILE_OWNER, PRIV_FILE_SETID,
 739                             PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
 740                 }
 741         }
 742 
 743         user->u_cred = cr;
 744         user->u_privcred = privcred;
 745         user->u_privileges = privileges;
 746 }
 747 #endif  /* _KERNEL */
 748 
 749 /*
 750  * Private function to support smb_user_enum.
 751  */
 752 static int
 753 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
 754 {
 755         uint8_t *pb;
 756         uint_t nbytes;
 757         int rc;
 758 
 759         if (svcenum->se_nskip > 0) {
 760                 svcenum->se_nskip--;
 761                 return (0);
 762         }
 763 
 764         if (svcenum->se_nitems >= svcenum->se_nlimit) {
 765                 svcenum->se_nitems = svcenum->se_nlimit;
 766                 return (0);
 767         }
 768 
 769         pb = &svcenum->se_buf[svcenum->se_bused];
 770         rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
 771         if (rc == 0) {
 772                 svcenum->se_bavail -= nbytes;
 773                 svcenum->se_bused += nbytes;
 774                 svcenum->se_nitems++;
 775         }
 776 
 777         return (rc);
 778 }
 779 
 780 /*
 781  * Encode the NetInfo for a user into a buffer.  NetInfo contains
 782  * information that is often needed in user space to support RPC
 783  * requests.
 784  */
 785 int
 786 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
 787     uint32_t *nbytes)
 788 {
 789         smb_netuserinfo_t       info;
 790         int                     rc;
 791 
 792         smb_user_netinfo_init(user, &info);
 793         rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
 794         smb_user_netinfo_fini(&info);
 795 
 796         return (rc);
 797 }
 798 
 799 void
 800 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
 801 {
 802         smb_session_t   *session;
 803         char            *buf;
 804 
 805         ASSERT(user);
 806         ASSERT(user->u_domain);
 807         ASSERT(user->u_name);
 808 
 809         session = user->u_session;
 810         ASSERT(session);
 811         ASSERT(session->workstation);
 812 
 813         info->ui_session_id = session->s_kid;
 814         info->ui_native_os = session->native_os;
 815         info->ui_ipaddr = session->ipaddr;
 816         info->ui_numopens = session->s_file_cnt;
 817         info->ui_logon_time = user->u_logon_time;
 818         info->ui_flags = user->u_flags;
 819         info->ui_posix_uid = crgetuid(user->u_cred);
 820 
 821         info->ui_domain_len = user->u_domain_len;
 822         info->ui_domain = smb_mem_strdup(user->u_domain);
 823 
 824         info->ui_account_len = user->u_name_len;
 825         info->ui_account = smb_mem_strdup(user->u_name);
 826 
 827         buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 828         smb_session_getclient(session, buf, MAXNAMELEN);
 829         info->ui_workstation_len = strlen(buf) + 1;
 830         info->ui_workstation = smb_mem_strdup(buf);
 831         kmem_free(buf, MAXNAMELEN);
 832 }
 833 
 834 void
 835 smb_user_netinfo_fini(smb_netuserinfo_t *info)
 836 {
 837         if (info == NULL)
 838                 return;
 839 
 840         if (info->ui_domain)
 841                 smb_mem_free(info->ui_domain);
 842         if (info->ui_account)
 843                 smb_mem_free(info->ui_account);
 844         if (info->ui_workstation)
 845                 smb_mem_free(info->ui_workstation);
 846 
 847         bzero(info, sizeof (smb_netuserinfo_t));
 848 }
 849 
 850 /*
 851  * Tell smbd this user is going away so it can clean up their
 852  * audit session, autohome dir, etc.
 853  *
 854  * Note that when we're shutting down, smbd will already have set
 855  * smbd.s_shutting_down and therefore will ignore door calls.
 856  * Skip this during shutdown to reduce upcall noise.
 857  */
 858 static void
 859 smb_user_auth_logoff(smb_user_t *user)
 860 {
 861         smb_server_t *sv = user->u_server;
 862         uint32_t audit_sid;
 863 
 864         if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
 865                 return;
 866 
 867         audit_sid = user->u_audit_sid;
 868         (void) smb_kdoor_upcall(sv, SMB_DR_USER_AUTH_LOGOFF,
 869             &audit_sid, xdr_uint32_t, NULL, NULL);
 870 }
 871 
 872 boolean_t
 873 smb_is_same_user(cred_t *cr1, cred_t *cr2)
 874 {
 875         ksid_t *ks1 = crgetsid(cr1, KSID_USER);
 876         ksid_t *ks2 = crgetsid(cr2, KSID_USER);
 877 
 878         return (ks1->ks_rid == ks2->ks_rid &&
 879             strcmp(ks1->ks_domain->kd_name, ks2->ks_domain->kd_name) == 0);
 880 }