xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_user.c (revision 8f70e16bf3f533fa0e164d0da06d00cffc63b9bb)
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.
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 static void smb_user_logoff_tq(void *);
214 
215 
216 /*
217  * Create a new user.
218  */
219 smb_user_t *
220 smb_user_new(smb_session_t *session)
221 {
222 	smb_user_t	*user;
223 
224 	ASSERT(session);
225 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
226 
227 	user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
228 	bzero(user, sizeof (smb_user_t));
229 
230 	user->u_refcnt = 1;
231 	user->u_session = session;
232 	user->u_server = session->s_server;
233 	user->u_logon_time = gethrestime_sec();
234 
235 	if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
236 		goto errout;
237 
238 	mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
239 	user->u_state = SMB_USER_STATE_LOGGING_ON;
240 	user->u_magic = SMB_USER_MAGIC;
241 
242 	smb_llist_enter(&session->s_user_list, RW_WRITER);
243 	smb_llist_insert_tail(&session->s_user_list, user);
244 	smb_llist_exit(&session->s_user_list);
245 	smb_server_inc_users(session->s_server);
246 
247 	return (user);
248 
249 errout:
250 	if (user->u_uid != 0)
251 		smb_idpool_free(&session->s_uid_pool, user->u_uid);
252 	kmem_cache_free(smb_cache_user, user);
253 	return (NULL);
254 }
255 
256 /*
257  * Fill in the details of a user, meaning a transition
258  * from state LOGGING_ON to state LOGGED_ON.
259  */
260 int
261 smb_user_logon(
262     smb_user_t		*user,
263     cred_t		*cr,
264     char		*domain_name,
265     char		*account_name,
266     uint32_t		flags,
267     uint32_t		privileges,
268     uint32_t		audit_sid)
269 {
270 	ksocket_t authsock = NULL;
271 	timeout_id_t tmo = NULL;
272 
273 	ASSERT(user->u_magic == SMB_USER_MAGIC);
274 	ASSERT(cr);
275 	ASSERT(account_name);
276 	ASSERT(domain_name);
277 
278 	mutex_enter(&user->u_mutex);
279 
280 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
281 		mutex_exit(&user->u_mutex);
282 		return (-1);
283 	}
284 
285 	/*
286 	 * In the transition from LOGGING_ON to LOGGED_ON,
287 	 * we always have an auth. socket to close.
288 	 */
289 	authsock = user->u_authsock;
290 	ASSERT(authsock != NULL);
291 	user->u_authsock = NULL;
292 	tmo = user->u_auth_tmo;
293 	user->u_auth_tmo = NULL;
294 
295 	user->u_state = SMB_USER_STATE_LOGGED_ON;
296 	user->u_flags = flags;
297 	user->u_name_len = strlen(account_name) + 1;
298 	user->u_domain_len = strlen(domain_name) + 1;
299 	user->u_name = smb_mem_strdup(account_name);
300 	user->u_domain = smb_mem_strdup(domain_name);
301 	user->u_audit_sid = audit_sid;
302 
303 	smb_user_setcred(user, cr, privileges);
304 
305 	mutex_exit(&user->u_mutex);
306 
307 	/* Timeout callback takes u_mutex. See untimeout(9f) */
308 	if (tmo != NULL)
309 		(void) untimeout(tmo);
310 
311 	/* This close can block, so not under the mutex. */
312 	smb_authsock_close(user, authsock);
313 
314 	return (0);
315 }
316 
317 /*
318  * smb_user_logoff
319  *
320  * Change the user state and disconnect trees.
321  * The user list must not be entered or modified here.
322  */
323 void
324 smb_user_logoff(
325     smb_user_t		*user)
326 {
327 	ksocket_t authsock = NULL;
328 	timeout_id_t tmo = NULL;
329 
330 	ASSERT(user->u_magic == SMB_USER_MAGIC);
331 
332 	mutex_enter(&user->u_mutex);
333 	ASSERT(user->u_refcnt);
334 	switch (user->u_state) {
335 	case SMB_USER_STATE_LOGGING_ON:
336 		authsock = user->u_authsock;
337 		user->u_authsock = NULL;
338 		tmo = user->u_auth_tmo;
339 		user->u_auth_tmo = NULL;
340 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
341 		smb_server_dec_users(user->u_server);
342 		break;
343 
344 	case SMB_USER_STATE_LOGGED_ON:
345 		/*
346 		 * The user is moved into a state indicating that the log off
347 		 * process has started.
348 		 */
349 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
350 		mutex_exit(&user->u_mutex);
351 		smb_session_disconnect_owned_trees(user->u_session, user);
352 		smb_user_auth_logoff(user);
353 		mutex_enter(&user->u_mutex);
354 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
355 		smb_server_dec_users(user->u_server);
356 		break;
357 
358 	case SMB_USER_STATE_LOGGED_OFF:
359 	case SMB_USER_STATE_LOGGING_OFF:
360 		break;
361 
362 	default:
363 		ASSERT(0);
364 		break;
365 	}
366 	mutex_exit(&user->u_mutex);
367 
368 	/* Timeout callback takes u_mutex. See untimeout(9f) */
369 	if (tmo != NULL)
370 		(void) untimeout(tmo);
371 
372 	/* This close can block, so not under the mutex. */
373 	if (authsock != NULL) {
374 		smb_authsock_close(user, authsock);
375 	}
376 }
377 
378 /*
379  * Take a reference on a user.  Do not return a reference unless the user is in
380  * the logged-in state.
381  */
382 boolean_t
383 smb_user_hold(smb_user_t *user)
384 {
385 	SMB_USER_VALID(user);
386 
387 	mutex_enter(&user->u_mutex);
388 
389 	if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
390 		user->u_refcnt++;
391 		mutex_exit(&user->u_mutex);
392 		return (B_TRUE);
393 	}
394 
395 	mutex_exit(&user->u_mutex);
396 	return (B_FALSE);
397 }
398 
399 /*
400  * Unconditionally take a reference on a user.
401  */
402 void
403 smb_user_hold_internal(smb_user_t *user)
404 {
405 	SMB_USER_VALID(user);
406 
407 	mutex_enter(&user->u_mutex);
408 	user->u_refcnt++;
409 	mutex_exit(&user->u_mutex);
410 }
411 
412 /*
413  * Release a reference on a user.  If the reference count falls to
414  * zero and the user has logged off, post the object for deletion.
415  * Object deletion is deferred to avoid modifying a list while an
416  * iteration may be in progress.
417  */
418 void
419 smb_user_release(
420     smb_user_t		*user)
421 {
422 	ASSERT(user->u_magic == SMB_USER_MAGIC);
423 
424 	mutex_enter(&user->u_mutex);
425 	ASSERT(user->u_refcnt);
426 	user->u_refcnt--;
427 
428 	switch (user->u_state) {
429 	case SMB_USER_STATE_LOGGED_OFF:
430 		if (user->u_refcnt == 0)
431 			smb_session_post_user(user->u_session, user);
432 		break;
433 
434 	case SMB_USER_STATE_LOGGING_ON:
435 	case SMB_USER_STATE_LOGGED_ON:
436 	case SMB_USER_STATE_LOGGING_OFF:
437 		break;
438 
439 	default:
440 		ASSERT(0);
441 		break;
442 	}
443 	mutex_exit(&user->u_mutex);
444 }
445 
446 /*
447  * Timeout handler for user logons that stay too long in
448  * state SMB_USER_STATE_LOGGING_ON.  This is setup by a
449  * timeout call in smb_authsock_open, and called in a
450  * callout thread, so schedule a taskq job to do the
451  * real work of logging off this user.
452  */
453 void
454 smb_user_auth_tmo(void *arg)
455 {
456 	smb_user_t *user = arg;
457 	smb_request_t *sr;
458 
459 	SMB_USER_VALID(user);
460 
461 	/*
462 	 * If we can't allocate a request, it means the
463 	 * session is being torn down, so nothing to do.
464 	 */
465 	sr = smb_request_alloc(user->u_session, 0);
466 	if (sr == NULL)
467 		return;
468 
469 	/*
470 	 * Check user state, and take a hold if it's
471 	 * still logging on.  If not, we're done.
472 	 */
473 	mutex_enter(&user->u_mutex);
474 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
475 		mutex_exit(&user->u_mutex);
476 		smb_request_free(sr);
477 		return;
478 	}
479 	/* smb_user_hold_internal */
480 	user->u_refcnt++;
481 	mutex_exit(&user->u_mutex);
482 
483 	/*
484 	 * The user hold is given to the SR, and released in
485 	 * smb_user_logoff_tq / smb_request_free
486 	 */
487 	sr->uid_user = user;
488 	sr->user_cr = user->u_cred;
489 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
490 
491 	(void) taskq_dispatch(
492 	    user->u_server->sv_worker_pool,
493 	    smb_user_logoff_tq, sr, TQ_SLEEP);
494 }
495 
496 /*
497  * Helper for smb_user_auth_tmo()
498  */
499 static void
500 smb_user_logoff_tq(void *arg)
501 {
502 	smb_request_t	*sr = arg;
503 
504 	SMB_REQ_VALID(sr);
505 
506 	mutex_enter(&sr->sr_mutex);
507 	sr->sr_worker = curthread;
508 	sr->sr_state = SMB_REQ_STATE_ACTIVE;
509 	mutex_exit(&sr->sr_mutex);
510 
511 	smb_user_logoff(sr->uid_user);
512 
513 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
514 	smb_request_free(sr);
515 }
516 
517 /*
518  * Determine whether or not the user is an administrator.
519  * Members of the administrators group have administrative rights.
520  */
521 boolean_t
522 smb_user_is_admin(smb_user_t *user)
523 {
524 #ifdef	_KERNEL
525 	char		sidstr[SMB_SID_STRSZ];
526 	ksidlist_t	*ksidlist;
527 	ksid_t		ksid1;
528 	ksid_t		*ksid2;
529 	int		i;
530 #endif	/* _KERNEL */
531 	boolean_t	rc = B_FALSE;
532 
533 	ASSERT(user);
534 	ASSERT(user->u_cred);
535 
536 	if (SMB_USER_IS_ADMIN(user))
537 		return (B_TRUE);
538 
539 #ifdef	_KERNEL
540 	bzero(&ksid1, sizeof (ksid_t));
541 	(void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
542 	ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
543 	ksid1.ks_domain = ksid_lookupdomain(sidstr);
544 
545 	ksidlist = crgetsidlist(user->u_cred);
546 	ASSERT(ksidlist);
547 	ASSERT(ksid1.ks_domain);
548 	ASSERT(ksid1.ks_domain->kd_name);
549 
550 	i = 0;
551 	ksid2 = crgetsid(user->u_cred, KSID_USER);
552 	do {
553 		ASSERT(ksid2->ks_domain);
554 		ASSERT(ksid2->ks_domain->kd_name);
555 
556 		if (strcmp(ksid1.ks_domain->kd_name,
557 		    ksid2->ks_domain->kd_name) == 0 &&
558 		    ksid1.ks_rid == ksid2->ks_rid) {
559 			user->u_flags |= SMB_USER_FLAG_ADMIN;
560 			rc = B_TRUE;
561 			break;
562 		}
563 
564 		ksid2 = &ksidlist->ksl_sids[i];
565 	} while (i++ < ksidlist->ksl_nsid);
566 
567 	ksid_rele(&ksid1);
568 #endif	/* _KERNEL */
569 	return (rc);
570 }
571 
572 /*
573  * This function should be called with a hold on the user.
574  */
575 boolean_t
576 smb_user_namecmp(smb_user_t *user, const char *name)
577 {
578 	char		*fq_name;
579 	boolean_t	match;
580 
581 	if (smb_strcasecmp(name, user->u_name, 0) == 0)
582 		return (B_TRUE);
583 
584 	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
585 
586 	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
587 	    user->u_domain, user->u_name);
588 
589 	match = (smb_strcasecmp(name, fq_name, 0) == 0);
590 	if (!match) {
591 		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
592 		    user->u_name, user->u_domain);
593 
594 		match = (smb_strcasecmp(name, fq_name, 0) == 0);
595 	}
596 
597 	kmem_free(fq_name, MAXNAMELEN);
598 	return (match);
599 }
600 
601 /*
602  * If the enumeration request is for user data, handle the request
603  * here.  Otherwise, pass it on to the trees.
604  *
605  * This function should be called with a hold on the user.
606  */
607 int
608 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
609 {
610 	int		rc = 0;
611 
612 	ASSERT(user);
613 	ASSERT(user->u_magic == SMB_USER_MAGIC);
614 
615 	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
616 		return (smb_user_enum_private(user, svcenum));
617 
618 	return (rc);
619 }
620 
621 /* *************************** Static Functions ***************************** */
622 
623 /*
624  * Delete a user.  The tree list should be empty.
625  *
626  * Remove the user from the session's user list before freeing resources
627  * associated with the user.
628  */
629 void
630 smb_user_delete(void *arg)
631 {
632 	smb_session_t	*session;
633 	smb_user_t	*user = (smb_user_t *)arg;
634 
635 	SMB_USER_VALID(user);
636 	ASSERT(user->u_refcnt == 0);
637 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
638 	ASSERT(user->u_authsock == NULL);
639 	ASSERT(user->u_auth_tmo == NULL);
640 
641 	session = user->u_session;
642 	smb_llist_enter(&session->s_user_list, RW_WRITER);
643 	smb_llist_remove(&session->s_user_list, user);
644 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
645 	smb_llist_exit(&session->s_user_list);
646 
647 	mutex_enter(&user->u_mutex);
648 	mutex_exit(&user->u_mutex);
649 
650 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
651 	mutex_destroy(&user->u_mutex);
652 	if (user->u_cred)
653 		crfree(user->u_cred);
654 	if (user->u_privcred)
655 		crfree(user->u_privcred);
656 	smb_mem_free(user->u_name);
657 	smb_mem_free(user->u_domain);
658 	kmem_cache_free(smb_cache_user, user);
659 }
660 
661 cred_t *
662 smb_user_getcred(smb_user_t *user)
663 {
664 	return (user->u_cred);
665 }
666 
667 cred_t *
668 smb_user_getprivcred(smb_user_t *user)
669 {
670 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
671 }
672 
673 #ifdef	_KERNEL
674 /*
675  * Assign the user cred and privileges.
676  *
677  * If the user has backup and/or restore privleges, dup the cred
678  * and add those privileges to this new privileged cred.
679  */
680 void
681 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
682 {
683 	cred_t *privcred = NULL;
684 
685 	ASSERT(cr);
686 	crhold(cr);
687 
688 	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
689 		privcred = crdup(cr);
690 
691 	if (privcred != NULL) {
692 		if (privileges & SMB_USER_PRIV_BACKUP) {
693 			(void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
694 			    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
695 		}
696 
697 		if (privileges & SMB_USER_PRIV_RESTORE) {
698 			(void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
699 			    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
700 			    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
701 			    PRIV_FILE_OWNER, PRIV_FILE_SETID,
702 			    PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
703 		}
704 	}
705 
706 	user->u_cred = cr;
707 	user->u_privcred = privcred;
708 	user->u_privileges = privileges;
709 }
710 #endif	/* _KERNEL */
711 
712 /*
713  * Private function to support smb_user_enum.
714  */
715 static int
716 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
717 {
718 	uint8_t *pb;
719 	uint_t nbytes;
720 	int rc;
721 
722 	if (svcenum->se_nskip > 0) {
723 		svcenum->se_nskip--;
724 		return (0);
725 	}
726 
727 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
728 		svcenum->se_nitems = svcenum->se_nlimit;
729 		return (0);
730 	}
731 
732 	pb = &svcenum->se_buf[svcenum->se_bused];
733 	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
734 	if (rc == 0) {
735 		svcenum->se_bavail -= nbytes;
736 		svcenum->se_bused += nbytes;
737 		svcenum->se_nitems++;
738 	}
739 
740 	return (rc);
741 }
742 
743 /*
744  * Encode the NetInfo for a user into a buffer.  NetInfo contains
745  * information that is often needed in user space to support RPC
746  * requests.
747  */
748 int
749 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
750     uint32_t *nbytes)
751 {
752 	smb_netuserinfo_t	info;
753 	int			rc;
754 
755 	smb_user_netinfo_init(user, &info);
756 	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
757 	smb_user_netinfo_fini(&info);
758 
759 	return (rc);
760 }
761 
762 void
763 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
764 {
765 	smb_session_t	*session;
766 	char		*buf;
767 
768 	ASSERT(user);
769 	ASSERT(user->u_domain);
770 	ASSERT(user->u_name);
771 
772 	session = user->u_session;
773 	ASSERT(session);
774 	ASSERT(session->workstation);
775 
776 	info->ui_session_id = session->s_kid;
777 	info->ui_native_os = session->native_os;
778 	info->ui_ipaddr = session->ipaddr;
779 	info->ui_numopens = session->s_file_cnt;
780 	info->ui_smb_uid = user->u_uid;
781 	info->ui_logon_time = user->u_logon_time;
782 	info->ui_flags = user->u_flags;
783 	info->ui_posix_uid = crgetuid(user->u_cred);
784 
785 	info->ui_domain_len = user->u_domain_len;
786 	info->ui_domain = smb_mem_strdup(user->u_domain);
787 
788 	info->ui_account_len = user->u_name_len;
789 	info->ui_account = smb_mem_strdup(user->u_name);
790 
791 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
792 	smb_session_getclient(session, buf, MAXNAMELEN);
793 	info->ui_workstation_len = strlen(buf) + 1;
794 	info->ui_workstation = smb_mem_strdup(buf);
795 	kmem_free(buf, MAXNAMELEN);
796 }
797 
798 void
799 smb_user_netinfo_fini(smb_netuserinfo_t *info)
800 {
801 	if (info == NULL)
802 		return;
803 
804 	if (info->ui_domain)
805 		smb_mem_free(info->ui_domain);
806 	if (info->ui_account)
807 		smb_mem_free(info->ui_account);
808 	if (info->ui_workstation)
809 		smb_mem_free(info->ui_workstation);
810 
811 	bzero(info, sizeof (smb_netuserinfo_t));
812 }
813 
814 static void
815 smb_user_auth_logoff(smb_user_t *user)
816 {
817 	uint32_t audit_sid = user->u_audit_sid;
818 
819 	(void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF,
820 	    &audit_sid, xdr_uint32_t, NULL, NULL);
821 }
822