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