xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_user.c (revision 9788d6deb586816d79d2ee1d4c4215f15cb944f5)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22c5866007SKeyur Desai  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
230292c176SMatt Barden  * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * General Structures Layout
29da6c28aaSamw  * -------------------------
30da6c28aaSamw  *
31da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
32da6c28aaSamw  * main structures.
33da6c28aaSamw  *
34da6c28aaSamw  * +-------------------+
35da6c28aaSamw  * |     SMB_INFO      |
36da6c28aaSamw  * +-------------------+
37da6c28aaSamw  *          |
38da6c28aaSamw  *          |
39da6c28aaSamw  *          v
40da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
41da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
42da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
433b13a1efSThomas Keiser  *   |          |
443b13a1efSThomas Keiser  *   |          |
453b13a1efSThomas Keiser  *   |          v
463b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
473b13a1efSThomas Keiser  *   |  |       USER        |<--->|       USER        |...|       USER        |
483b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
49da6c28aaSamw  *   |
50da6c28aaSamw  *   |
51da6c28aaSamw  *   v
52da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
53da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
54da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
55da6c28aaSamw  *      |         |
56da6c28aaSamw  *      |         |
57da6c28aaSamw  *      |         v
58da6c28aaSamw  *      |     +-------+       +-------+      +-------+
59da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
60da6c28aaSamw  *      |     +-------+       +-------+      +-------+
61da6c28aaSamw  *      |
62da6c28aaSamw  *      |
63da6c28aaSamw  *      v
64da6c28aaSamw  *  +-------+       +------+      +------+
65da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
66da6c28aaSamw  *  +-------+       +------+      +------+
67da6c28aaSamw  *
68da6c28aaSamw  *
69da6c28aaSamw  * User State Machine
70da6c28aaSamw  * ------------------
71da6c28aaSamw  *
7212b65585SGordon Ross  *
7312b65585SGordon Ross  *		    | T0:  Creation/Allocation
7412b65585SGordon Ross  *		    |	   (1st session setup)
7512b65585SGordon Ross  *		    v
7612b65585SGordon Ross  *    +-----------------------------+
7712b65585SGordon Ross  *    |  SMB_USER_STATE_LOGGING_ON  |<----------+
7812b65585SGordon Ross  *    +-----------------------------+	 addl. session setup
7912b65585SGordon Ross  *		    |		|	(more proc. required)
8012b65585SGordon Ross  *		    | T2	|		^
8112b65585SGordon Ross  *		    |		|		| T1: (cont.)
8212b65585SGordon Ross  *		    |		+------->-------?
8312b65585SGordon Ross  *		    v				| T3: (fail)
8412b65585SGordon Ross  *    +-----------------------------+		v
8512b65585SGordon Ross  *    |  SMB_USER_STATE_LOGGED_ON   |	    (logged off)
86da6c28aaSamw  *    +-----------------------------+
87da6c28aaSamw  *		    |
8812b65585SGordon Ross  *		    | T4
89da6c28aaSamw  *		    |
90da6c28aaSamw  *		    v
91da6c28aaSamw  *    +-----------------------------+
92da6c28aaSamw  *    |  SMB_USER_STATE_LOGGING_OFF |
93da6c28aaSamw  *    +-----------------------------+
94da6c28aaSamw  *		    |
9512b65585SGordon Ross  *		    | T5
96da6c28aaSamw  *		    |
97da6c28aaSamw  *		    v
9812b65585SGordon Ross  *    +-----------------------------+    T6
99da6c28aaSamw  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
100da6c28aaSamw  *    +-----------------------------+
101da6c28aaSamw  *
10212b65585SGordon Ross  * SMB_USER_STATE_LOGGING_ON
103da6c28aaSamw  *
104da6c28aaSamw  *    While in this state:
10548bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
10612b65585SGordon Ross  *      - References will be given out ONLY for session setup.
10712b65585SGordon Ross  *      - This user can not access anything yet.
10812b65585SGordon Ross  *
10912b65585SGordon Ross  * SMB_USER_STATE_LOGGED_ON
11012b65585SGordon Ross  *
11112b65585SGordon Ross  *    While in this state:
11248bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
113da6c28aaSamw  *      - References will be given out if the user is looked up.
114da6c28aaSamw  *      - The user can access files and pipes.
115da6c28aaSamw  *
116da6c28aaSamw  * SMB_USER_STATE_LOGGING_OFF
117da6c28aaSamw  *
118da6c28aaSamw  *    While in this state:
11948bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
120da6c28aaSamw  *      - References will not be given out if the user is looked up.
121da6c28aaSamw  *      - The trees the user connected are being disconnected.
122da6c28aaSamw  *      - The resources associated with the user remain.
123da6c28aaSamw  *
12412b65585SGordon Ross  * SMB_USER_STATE_LOGGED_OFF
125da6c28aaSamw  *
126da6c28aaSamw  *    While in this state:
12748bbca81SDaniel Hoffman  *      - The user is queued in the list of users of their session.
128da6c28aaSamw  *      - References will not be given out if the user is looked up.
129da6c28aaSamw  *      - The user has no more trees connected.
130da6c28aaSamw  *      - The resources associated with the user remain.
131da6c28aaSamw  *
132da6c28aaSamw  * Transition T0
133da6c28aaSamw  *
13412b65585SGordon Ross  *    First request in an SMB Session Setup sequence creates a
13512b65585SGordon Ross  *    new user object and adds it to the list of users for
13612b65585SGordon Ross  *    this session.  User UID is assigned and returned.
137da6c28aaSamw  *
138da6c28aaSamw  * Transition T1
139da6c28aaSamw  *
14012b65585SGordon Ross  *    Subsequent SMB Session Setup requests (on the same UID
14112b65585SGordon Ross  *    assigned in T0) update the state of this user object,
14212b65585SGordon Ross  *    communicating with smbd for the crypto work.
143da6c28aaSamw  *
144da6c28aaSamw  * Transition T2
145da6c28aaSamw  *
14612b65585SGordon Ross  *    If the SMB Session Setup sequence is successful, T2
14712b65585SGordon Ross  *    makes the new user object available for requests.
14812b65585SGordon Ross  *
14912b65585SGordon Ross  * Transition T3
15012b65585SGordon Ross  *
15112b65585SGordon Ross  *    If an Session Setup request gets an error other than
15212b65585SGordon Ross  *    the expected "more processing required", then T3
15312b65585SGordon Ross  *    leads to state "LOGGED_OFF" and then tear-down of the
15412b65585SGordon Ross  *    partially constructed user.
15512b65585SGordon Ross  *
15612b65585SGordon Ross  * Transition T4
15712b65585SGordon Ross  *
15812b65585SGordon Ross  *    Normal SMB User Logoff request, or session tear-down.
15912b65585SGordon Ross  *
16012b65585SGordon Ross  * Transition T5
16112b65585SGordon Ross  *
162da6c28aaSamw  *    This transition occurs in smb_user_release(). The resources associated
163da6c28aaSamw  *    with the user are deleted as well as the user. For the transition to
164da6c28aaSamw  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
165da6c28aaSamw  *    reference count be zero.
166da6c28aaSamw  *
167da6c28aaSamw  * Comments
168da6c28aaSamw  * --------
169da6c28aaSamw  *
170da6c28aaSamw  *    The state machine of the user structures is controlled by 3 elements:
17148bbca81SDaniel Hoffman  *      - The list of users of the session they belong to.
172da6c28aaSamw  *      - The mutex embedded in the structure itself.
173da6c28aaSamw  *      - The reference count.
174da6c28aaSamw  *
175da6c28aaSamw  *    There's a mutex embedded in the user structure used to protect its fields
176da6c28aaSamw  *    and there's a lock embedded in the list of users of a session. To
177da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
178da6c28aaSamw  *    To insert the user into the list of users of the session and to remove
179da6c28aaSamw  *    the user from it, the lock must be entered in RW_WRITER mode.
180da6c28aaSamw  *
181da6c28aaSamw  *    Rules of access to a user structure:
182da6c28aaSamw  *
183da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
184811599a4SMatt Barden  *       list) have to be entered, the lock must be entered first. Additionally,
185811599a4SMatt Barden  *       one may NOT flush the deleteq of either the tree list or the ofile list
186811599a4SMatt Barden  *       while the user mutex is held.
187da6c28aaSamw  *
188da6c28aaSamw  *    2) All actions applied to a user require a reference count.
189da6c28aaSamw  *
190da6c28aaSamw  *    3) There are 2 ways of getting a reference count. One is when the user
1919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *       logs in. The other when the user is looked up.
192da6c28aaSamw  *
193da6c28aaSamw  *    It should be noted that the reference count of a user registers the
194da6c28aaSamw  *    number of references to the user in other structures (such as an smb
195da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
196da6c28aaSamw  *
19748bbca81SDaniel Hoffman  *    1) The user is logged in. An user is anchored by their state. If there's
198da6c28aaSamw  *       no activity involving a user currently logged in, the reference
199da6c28aaSamw  *       count of that user is zero.
200da6c28aaSamw  *
201da6c28aaSamw  *    2) The user is queued in the list of users of the session. The fact of
202da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
203da6c28aaSamw  *       reference count.
204da6c28aaSamw  */
205148c5f43SAlan Wright #include <sys/types.h>
206148c5f43SAlan Wright #include <sys/sid.h>
207148c5f43SAlan Wright #include <sys/priv_names.h>
2089e3ab9e9SMatt Barden #include <sys/priv.h>
2099e3ab9e9SMatt Barden #include <sys/policy.h>
210bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
2119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h>
212da6c28aaSamw 
213c8ec8eeaSjose borrego #define	ADMINISTRATORS_SID	"S-1-5-32-544"
214c8ec8eeaSjose borrego 
215811599a4SMatt Barden /* Don't leak object addresses */
216811599a4SMatt Barden #define	SMB_USER_SSNID(u) \
217811599a4SMatt Barden 	((uintptr_t)&smb_cache_user ^ (uintptr_t)(u))
218811599a4SMatt Barden 
219811599a4SMatt Barden static void smb_user_delete(void *);
2201fcced4cSJordan Brown static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
2218622ec45SGordon Ross static void smb_user_auth_logoff(smb_user_t *);
2228f70e16bSGordon Ross static void smb_user_logoff_tq(void *);
223c8ec8eeaSjose borrego 
224da6c28aaSamw /*
225148c5f43SAlan Wright  * Create a new user.
226811599a4SMatt Barden  *
227811599a4SMatt Barden  * For SMB2 and later, session IDs (u_ssnid) need to be unique among all
228811599a4SMatt Barden  * current and "recent" sessions.  The session ID is derived from the
229811599a4SMatt Barden  * address of the smb_user object (obscured by XOR with a constant).
230811599a4SMatt Barden  * This adds a 3-bit generation number in the low bits, incremented
231811599a4SMatt Barden  * when we allocate an smb_user_t from its kmem cache, so it can't
232811599a4SMatt Barden  * be confused with a (recent) previous incarnation of this object.
233da6c28aaSamw  */
234da6c28aaSamw smb_user_t *
23512b65585SGordon Ross smb_user_new(smb_session_t *session)
23612b65585SGordon Ross {
23712b65585SGordon Ross 	smb_user_t	*user;
238811599a4SMatt Barden 	uint_t		gen;	// generation (low 3 bits of ssnid)
239817fa55fSGordon Ross 	uint32_t	ucount;
24012b65585SGordon Ross 
24112b65585SGordon Ross 	ASSERT(session);
24212b65585SGordon Ross 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
24312b65585SGordon Ross 
24412b65585SGordon Ross 	user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
245811599a4SMatt Barden 	gen = (user->u_ssnid + 1) & 7;
24612b65585SGordon Ross 	bzero(user, sizeof (smb_user_t));
24712b65585SGordon Ross 
24812b65585SGordon Ross 	user->u_refcnt = 1;
24912b65585SGordon Ross 	user->u_session = session;
25012b65585SGordon Ross 	user->u_server = session->s_server;
25112b65585SGordon Ross 	user->u_logon_time = gethrestime_sec();
25212b65585SGordon Ross 
25312b65585SGordon Ross 	if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
25412b65585SGordon Ross 		goto errout;
255811599a4SMatt Barden 	user->u_ssnid = SMB_USER_SSNID(user) + gen;
25612b65585SGordon Ross 
25712b65585SGordon Ross 	mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
25812b65585SGordon Ross 	user->u_state = SMB_USER_STATE_LOGGING_ON;
25912b65585SGordon Ross 	user->u_magic = SMB_USER_MAGIC;
26012b65585SGordon Ross 
26112b65585SGordon Ross 	smb_llist_enter(&session->s_user_list, RW_WRITER);
262817fa55fSGordon Ross 	ucount = smb_llist_get_count(&session->s_user_list);
26312b65585SGordon Ross 	smb_llist_insert_tail(&session->s_user_list, user);
26412b65585SGordon Ross 	smb_llist_exit(&session->s_user_list);
26512b65585SGordon Ross 	smb_server_inc_users(session->s_server);
26612b65585SGordon Ross 
267817fa55fSGordon Ross 	/*
268817fa55fSGordon Ross 	 * If we added the first user to the session, cancel the
269817fa55fSGordon Ross 	 * timeout that was started in smb_session_receiver().
270817fa55fSGordon Ross 	 */
271817fa55fSGordon Ross 	if (ucount == 0) {
272817fa55fSGordon Ross 		timeout_id_t tmo = NULL;
273817fa55fSGordon Ross 
274817fa55fSGordon Ross 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
275817fa55fSGordon Ross 		tmo = session->s_auth_tmo;
276817fa55fSGordon Ross 		session->s_auth_tmo = NULL;
277817fa55fSGordon Ross 		smb_rwx_rwexit(&session->s_lock);
278817fa55fSGordon Ross 
279817fa55fSGordon Ross 		if (tmo != NULL)
280817fa55fSGordon Ross 			(void) untimeout(tmo);
281817fa55fSGordon Ross 	}
282817fa55fSGordon Ross 
28312b65585SGordon Ross 	return (user);
28412b65585SGordon Ross 
28512b65585SGordon Ross errout:
28612b65585SGordon Ross 	if (user->u_uid != 0)
28712b65585SGordon Ross 		smb_idpool_free(&session->s_uid_pool, user->u_uid);
28812b65585SGordon Ross 	kmem_cache_free(smb_cache_user, user);
28912b65585SGordon Ross 	return (NULL);
29012b65585SGordon Ross }
29112b65585SGordon Ross 
29212b65585SGordon Ross /*
29312b65585SGordon Ross  * Fill in the details of a user, meaning a transition
29412b65585SGordon Ross  * from state LOGGING_ON to state LOGGED_ON.
29512b65585SGordon Ross  */
29612b65585SGordon Ross int
29712b65585SGordon Ross smb_user_logon(
29812b65585SGordon Ross     smb_user_t		*user,
299da6c28aaSamw     cred_t		*cr,
300da6c28aaSamw     char		*domain_name,
301da6c28aaSamw     char		*account_name,
302da6c28aaSamw     uint32_t		flags,
303da6c28aaSamw     uint32_t		privileges,
304da6c28aaSamw     uint32_t		audit_sid)
305da6c28aaSamw {
306b210fedeSGordon Ross 	ksocket_t authsock = NULL;
3078f70e16bSGordon Ross 	timeout_id_t tmo = NULL;
308da6c28aaSamw 
30912b65585SGordon Ross 	ASSERT(user->u_magic == SMB_USER_MAGIC);
310da6c28aaSamw 	ASSERT(cr);
311da6c28aaSamw 	ASSERT(account_name);
312da6c28aaSamw 	ASSERT(domain_name);
313da6c28aaSamw 
31412b65585SGordon Ross 	mutex_enter(&user->u_mutex);
31512b65585SGordon Ross 
31612b65585SGordon Ross 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
31712b65585SGordon Ross 		mutex_exit(&user->u_mutex);
31812b65585SGordon Ross 		return (-1);
31912b65585SGordon Ross 	}
32012b65585SGordon Ross 
321b210fedeSGordon Ross 	/*
322b210fedeSGordon Ross 	 * In the transition from LOGGING_ON to LOGGED_ON,
323b210fedeSGordon Ross 	 * we always have an auth. socket to close.
324b210fedeSGordon Ross 	 */
325b210fedeSGordon Ross 	authsock = user->u_authsock;
326b210fedeSGordon Ross 	user->u_authsock = NULL;
3278f70e16bSGordon Ross 	tmo = user->u_auth_tmo;
3288f70e16bSGordon Ross 	user->u_auth_tmo = NULL;
32912b65585SGordon Ross 
33012b65585SGordon Ross 	user->u_state = SMB_USER_STATE_LOGGED_ON;
331da6c28aaSamw 	user->u_flags = flags;
332da6c28aaSamw 	user->u_name_len = strlen(account_name) + 1;
333da6c28aaSamw 	user->u_domain_len = strlen(domain_name) + 1;
3349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user->u_name = smb_mem_strdup(account_name);
3359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user->u_domain = smb_mem_strdup(domain_name);
336da6c28aaSamw 	user->u_audit_sid = audit_sid;
337da6c28aaSamw 
338148c5f43SAlan Wright 	smb_user_setcred(user, cr, privileges);
339da6c28aaSamw 
34012b65585SGordon Ross 	mutex_exit(&user->u_mutex);
341da6c28aaSamw 
3428f70e16bSGordon Ross 	/* Timeout callback takes u_mutex. See untimeout(9f) */
3438f70e16bSGordon Ross 	if (tmo != NULL)
3448f70e16bSGordon Ross 		(void) untimeout(tmo);
3458f70e16bSGordon Ross 
346b210fedeSGordon Ross 	/* This close can block, so not under the mutex. */
3478d94f651SGordon Ross 	if (authsock != NULL)
348b210fedeSGordon Ross 		smb_authsock_close(user, authsock);
349b210fedeSGordon Ross 
35012b65585SGordon Ross 	return (0);
351da6c28aaSamw }
352da6c28aaSamw 
353da6c28aaSamw /*
354da6c28aaSamw  * smb_user_logoff
355da6c28aaSamw  *
356811599a4SMatt Barden  * Change the user state to "logging off" and disconnect trees.
3571fcced4cSJordan Brown  * The user list must not be entered or modified here.
358811599a4SMatt Barden  *
359811599a4SMatt Barden  * We remain in state "logging off" until the last ref. is gone,
360811599a4SMatt Barden  * then smb_user_release takes us to state "logged off".
361da6c28aaSamw  */
362da6c28aaSamw void
363da6c28aaSamw smb_user_logoff(
364da6c28aaSamw     smb_user_t		*user)
365da6c28aaSamw {
366b210fedeSGordon Ross 	ksocket_t authsock = NULL;
3678f70e16bSGordon Ross 	timeout_id_t tmo = NULL;
368b210fedeSGordon Ross 
369da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
370da6c28aaSamw 
371da6c28aaSamw 	mutex_enter(&user->u_mutex);
372da6c28aaSamw 	ASSERT(user->u_refcnt);
373da6c28aaSamw 	switch (user->u_state) {
374b210fedeSGordon Ross 	case SMB_USER_STATE_LOGGING_ON:
375b210fedeSGordon Ross 		authsock = user->u_authsock;
376b210fedeSGordon Ross 		user->u_authsock = NULL;
3778f70e16bSGordon Ross 		tmo = user->u_auth_tmo;
3788f70e16bSGordon Ross 		user->u_auth_tmo = NULL;
379811599a4SMatt Barden 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
380811599a4SMatt Barden 		mutex_exit(&user->u_mutex);
381811599a4SMatt Barden 
382811599a4SMatt Barden 		/* Timeout callback takes u_mutex. See untimeout(9f) */
383811599a4SMatt Barden 		if (tmo != NULL)
384811599a4SMatt Barden 			(void) untimeout(tmo);
385811599a4SMatt Barden 		/* This close can block, so not under the mutex. */
386811599a4SMatt Barden 		if (authsock != NULL)
387811599a4SMatt Barden 			smb_authsock_close(user, authsock);
38812b65585SGordon Ross 		break;
38912b65585SGordon Ross 
390b210fedeSGordon Ross 	case SMB_USER_STATE_LOGGED_ON:
391da6c28aaSamw 		/*
392da6c28aaSamw 		 * The user is moved into a state indicating that the log off
393da6c28aaSamw 		 * process has started.
394da6c28aaSamw 		 */
395da6c28aaSamw 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
396da6c28aaSamw 		mutex_exit(&user->u_mutex);
3973b13a1efSThomas Keiser 		smb_session_disconnect_owned_trees(user->u_session, user);
3988622ec45SGordon Ross 		smb_user_auth_logoff(user);
399da6c28aaSamw 		break;
400b210fedeSGordon Ross 
401da6c28aaSamw 	case SMB_USER_STATE_LOGGED_OFF:
402da6c28aaSamw 	case SMB_USER_STATE_LOGGING_OFF:
403811599a4SMatt Barden 		mutex_exit(&user->u_mutex);
404da6c28aaSamw 		break;
405da6c28aaSamw 
406da6c28aaSamw 	default:
407da6c28aaSamw 		ASSERT(0);
408da6c28aaSamw 		mutex_exit(&user->u_mutex);
409811599a4SMatt Barden 		break;
410b210fedeSGordon Ross 	}
411da6c28aaSamw }
412da6c28aaSamw 
413da6c28aaSamw /*
4143b13a1efSThomas Keiser  * Take a reference on a user.  Do not return a reference unless the user is in
4153b13a1efSThomas Keiser  * the logged-in state.
4161fcced4cSJordan Brown  */
4171fcced4cSJordan Brown boolean_t
4181fcced4cSJordan Brown smb_user_hold(smb_user_t *user)
4191fcced4cSJordan Brown {
4203b13a1efSThomas Keiser 	SMB_USER_VALID(user);
4211fcced4cSJordan Brown 
4221fcced4cSJordan Brown 	mutex_enter(&user->u_mutex);
4231fcced4cSJordan Brown 
42412b65585SGordon Ross 	if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
4251fcced4cSJordan Brown 		user->u_refcnt++;
4261fcced4cSJordan Brown 		mutex_exit(&user->u_mutex);
4271fcced4cSJordan Brown 		return (B_TRUE);
4281fcced4cSJordan Brown 	}
4291fcced4cSJordan Brown 
4301fcced4cSJordan Brown 	mutex_exit(&user->u_mutex);
4311fcced4cSJordan Brown 	return (B_FALSE);
4321fcced4cSJordan Brown }
4331fcced4cSJordan Brown 
4341fcced4cSJordan Brown /*
4353b13a1efSThomas Keiser  * Unconditionally take a reference on a user.
4363b13a1efSThomas Keiser  */
4373b13a1efSThomas Keiser void
4383b13a1efSThomas Keiser smb_user_hold_internal(smb_user_t *user)
4393b13a1efSThomas Keiser {
4403b13a1efSThomas Keiser 	SMB_USER_VALID(user);
4413b13a1efSThomas Keiser 
4423b13a1efSThomas Keiser 	mutex_enter(&user->u_mutex);
4433b13a1efSThomas Keiser 	user->u_refcnt++;
4443b13a1efSThomas Keiser 	mutex_exit(&user->u_mutex);
4453b13a1efSThomas Keiser }
4463b13a1efSThomas Keiser 
4473b13a1efSThomas Keiser /*
4489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Release a reference on a user.  If the reference count falls to
4499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * zero and the user has logged off, post the object for deletion.
4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Object deletion is deferred to avoid modifying a list while an
4519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * iteration may be in progress.
452da6c28aaSamw  */
453da6c28aaSamw void
454da6c28aaSamw smb_user_release(
455da6c28aaSamw     smb_user_t		*user)
456da6c28aaSamw {
457811599a4SMatt Barden 	smb_session_t *ssn = user->u_session;
458811599a4SMatt Barden 
459811599a4SMatt Barden 	SMB_USER_VALID(user);
460811599a4SMatt Barden 
461811599a4SMatt Barden 	/* flush the tree list delete queue */
462811599a4SMatt Barden 	smb_llist_flush(&ssn->s_tree_list);
463da6c28aaSamw 
464da6c28aaSamw 	mutex_enter(&user->u_mutex);
465da6c28aaSamw 	ASSERT(user->u_refcnt);
466da6c28aaSamw 	user->u_refcnt--;
467c5866007SKeyur Desai 
468da6c28aaSamw 	switch (user->u_state) {
469811599a4SMatt Barden 	case SMB_USER_STATE_LOGGING_OFF:
470811599a4SMatt Barden 		if (user->u_refcnt == 0) {
471811599a4SMatt Barden 			smb_session_t *ssn = user->u_session;
472811599a4SMatt Barden 			user->u_state = SMB_USER_STATE_LOGGED_OFF;
473811599a4SMatt Barden 			smb_llist_post(&ssn->s_user_list, user,
474811599a4SMatt Barden 			    smb_user_delete);
475811599a4SMatt Barden 		}
476da6c28aaSamw 		break;
477da6c28aaSamw 
47812b65585SGordon Ross 	case SMB_USER_STATE_LOGGING_ON:
47912b65585SGordon Ross 	case SMB_USER_STATE_LOGGED_ON:
480da6c28aaSamw 		break;
481da6c28aaSamw 
482811599a4SMatt Barden 	case SMB_USER_STATE_LOGGED_OFF:
483da6c28aaSamw 	default:
484da6c28aaSamw 		ASSERT(0);
485da6c28aaSamw 		break;
486da6c28aaSamw 	}
487da6c28aaSamw 	mutex_exit(&user->u_mutex);
488da6c28aaSamw }
489da6c28aaSamw 
4901fcced4cSJordan Brown /*
4918f70e16bSGordon Ross  * Timeout handler for user logons that stay too long in
4928f70e16bSGordon Ross  * state SMB_USER_STATE_LOGGING_ON.  This is setup by a
4938f70e16bSGordon Ross  * timeout call in smb_authsock_open, and called in a
4948f70e16bSGordon Ross  * callout thread, so schedule a taskq job to do the
4958f70e16bSGordon Ross  * real work of logging off this user.
4968f70e16bSGordon Ross  */
4978f70e16bSGordon Ross void
4988f70e16bSGordon Ross smb_user_auth_tmo(void *arg)
4998f70e16bSGordon Ross {
5008f70e16bSGordon Ross 	smb_user_t *user = arg;
5018f70e16bSGordon Ross 	smb_request_t *sr;
502*9788d6deSGordon Ross 	taskqid_t tqid;
5038f70e16bSGordon Ross 
5048f70e16bSGordon Ross 	SMB_USER_VALID(user);
5058f70e16bSGordon Ross 
5068f70e16bSGordon Ross 	/*
5078f70e16bSGordon Ross 	 * If we can't allocate a request, it means the
5088f70e16bSGordon Ross 	 * session is being torn down, so nothing to do.
5098f70e16bSGordon Ross 	 */
5108f70e16bSGordon Ross 	sr = smb_request_alloc(user->u_session, 0);
5118f70e16bSGordon Ross 	if (sr == NULL)
5128f70e16bSGordon Ross 		return;
5138f70e16bSGordon Ross 
5148f70e16bSGordon Ross 	/*
5158f70e16bSGordon Ross 	 * Check user state, and take a hold if it's
5168f70e16bSGordon Ross 	 * still logging on.  If not, we're done.
5178f70e16bSGordon Ross 	 */
5188f70e16bSGordon Ross 	mutex_enter(&user->u_mutex);
5198f70e16bSGordon Ross 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
5208f70e16bSGordon Ross 		mutex_exit(&user->u_mutex);
5218f70e16bSGordon Ross 		smb_request_free(sr);
5228f70e16bSGordon Ross 		return;
5238f70e16bSGordon Ross 	}
5248f70e16bSGordon Ross 	/* smb_user_hold_internal */
5258f70e16bSGordon Ross 	user->u_refcnt++;
5268f70e16bSGordon Ross 	mutex_exit(&user->u_mutex);
5278f70e16bSGordon Ross 
5288f70e16bSGordon Ross 	/*
5298f70e16bSGordon Ross 	 * The user hold is given to the SR, and released in
5308f70e16bSGordon Ross 	 * smb_user_logoff_tq / smb_request_free
5318f70e16bSGordon Ross 	 */
5328f70e16bSGordon Ross 	sr->uid_user = user;
5338f70e16bSGordon Ross 	sr->user_cr = user->u_cred;
5348f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
535*9788d6deSGordon Ross 	tqid = taskq_dispatch(
5368f70e16bSGordon Ross 	    user->u_server->sv_worker_pool,
5378f70e16bSGordon Ross 	    smb_user_logoff_tq, sr, TQ_SLEEP);
538*9788d6deSGordon Ross 	VERIFY(tqid != TASKQID_INVALID);
5398f70e16bSGordon Ross }
5408f70e16bSGordon Ross 
5418f70e16bSGordon Ross /*
5428f70e16bSGordon Ross  * Helper for smb_user_auth_tmo()
5438f70e16bSGordon Ross  */
5448f70e16bSGordon Ross static void
5458f70e16bSGordon Ross smb_user_logoff_tq(void *arg)
5468f70e16bSGordon Ross {
5478f70e16bSGordon Ross 	smb_request_t	*sr = arg;
5488f70e16bSGordon Ross 
5498f70e16bSGordon Ross 	SMB_REQ_VALID(sr);
5508f70e16bSGordon Ross 
5518f70e16bSGordon Ross 	mutex_enter(&sr->sr_mutex);
5528f70e16bSGordon Ross 	sr->sr_worker = curthread;
5538f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_ACTIVE;
5548f70e16bSGordon Ross 	mutex_exit(&sr->sr_mutex);
5558f70e16bSGordon Ross 
5568f70e16bSGordon Ross 	smb_user_logoff(sr->uid_user);
5578f70e16bSGordon Ross 
5588f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
5598f70e16bSGordon Ross 	smb_request_free(sr);
5608f70e16bSGordon Ross }
5618f70e16bSGordon Ross 
5628f70e16bSGordon Ross /*
563c8ec8eeaSjose borrego  * Determine whether or not the user is an administrator.
564c8ec8eeaSjose borrego  * Members of the administrators group have administrative rights.
565c8ec8eeaSjose borrego  */
566c8ec8eeaSjose borrego boolean_t
567148c5f43SAlan Wright smb_user_is_admin(smb_user_t *user)
568c8ec8eeaSjose borrego {
569b819cea2SGordon Ross #ifdef	_KERNEL
570148c5f43SAlan Wright 	char		sidstr[SMB_SID_STRSZ];
571148c5f43SAlan Wright 	ksidlist_t	*ksidlist;
572148c5f43SAlan Wright 	ksid_t		ksid1;
573148c5f43SAlan Wright 	ksid_t		*ksid2;
574148c5f43SAlan Wright 	int		i;
575b819cea2SGordon Ross #endif	/* _KERNEL */
576b819cea2SGordon Ross 	boolean_t	rc = B_FALSE;
577c8ec8eeaSjose borrego 
578c8ec8eeaSjose borrego 	ASSERT(user);
579148c5f43SAlan Wright 	ASSERT(user->u_cred);
580c8ec8eeaSjose borrego 
581148c5f43SAlan Wright 	if (SMB_USER_IS_ADMIN(user))
582c8ec8eeaSjose borrego 		return (B_TRUE);
583c8ec8eeaSjose borrego 
584b819cea2SGordon Ross #ifdef	_KERNEL
585148c5f43SAlan Wright 	bzero(&ksid1, sizeof (ksid_t));
586148c5f43SAlan Wright 	(void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
587148c5f43SAlan Wright 	ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
588148c5f43SAlan Wright 	ksid1.ks_domain = ksid_lookupdomain(sidstr);
589148c5f43SAlan Wright 
590148c5f43SAlan Wright 	ksidlist = crgetsidlist(user->u_cred);
591148c5f43SAlan Wright 	ASSERT(ksidlist);
592148c5f43SAlan Wright 	ASSERT(ksid1.ks_domain);
593148c5f43SAlan Wright 	ASSERT(ksid1.ks_domain->kd_name);
594148c5f43SAlan Wright 
595148c5f43SAlan Wright 	i = 0;
596148c5f43SAlan Wright 	ksid2 = crgetsid(user->u_cred, KSID_USER);
597148c5f43SAlan Wright 	do {
598148c5f43SAlan Wright 		ASSERT(ksid2->ks_domain);
599148c5f43SAlan Wright 		ASSERT(ksid2->ks_domain->kd_name);
600148c5f43SAlan Wright 
601148c5f43SAlan Wright 		if (strcmp(ksid1.ks_domain->kd_name,
602148c5f43SAlan Wright 		    ksid2->ks_domain->kd_name) == 0 &&
603148c5f43SAlan Wright 		    ksid1.ks_rid == ksid2->ks_rid) {
604148c5f43SAlan Wright 			user->u_flags |= SMB_USER_FLAG_ADMIN;
605148c5f43SAlan Wright 			rc = B_TRUE;
606148c5f43SAlan Wright 			break;
607148c5f43SAlan Wright 		}
608148c5f43SAlan Wright 
609148c5f43SAlan Wright 		ksid2 = &ksidlist->ksl_sids[i];
610148c5f43SAlan Wright 	} while (i++ < ksidlist->ksl_nsid);
611148c5f43SAlan Wright 
612148c5f43SAlan Wright 	ksid_rele(&ksid1);
613b819cea2SGordon Ross #endif	/* _KERNEL */
614148c5f43SAlan Wright 	return (rc);
615c8ec8eeaSjose borrego }
616c8ec8eeaSjose borrego 
6171fcced4cSJordan Brown /*
6181fcced4cSJordan Brown  * This function should be called with a hold on the user.
6191fcced4cSJordan Brown  */
6201fcced4cSJordan Brown boolean_t
6211fcced4cSJordan Brown smb_user_namecmp(smb_user_t *user, const char *name)
6221fcced4cSJordan Brown {
6231fcced4cSJordan Brown 	char		*fq_name;
6241fcced4cSJordan Brown 	boolean_t	match;
6251fcced4cSJordan Brown 
626bbf6f00cSJordan Brown 	if (smb_strcasecmp(name, user->u_name, 0) == 0)
6271fcced4cSJordan Brown 		return (B_TRUE);
6281fcced4cSJordan Brown 
6291fcced4cSJordan Brown 	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
6301fcced4cSJordan Brown 
6311fcced4cSJordan Brown 	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
6321fcced4cSJordan Brown 	    user->u_domain, user->u_name);
6331fcced4cSJordan Brown 
634bbf6f00cSJordan Brown 	match = (smb_strcasecmp(name, fq_name, 0) == 0);
6351fcced4cSJordan Brown 	if (!match) {
6361fcced4cSJordan Brown 		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
6371fcced4cSJordan Brown 		    user->u_name, user->u_domain);
6381fcced4cSJordan Brown 
639bbf6f00cSJordan Brown 		match = (smb_strcasecmp(name, fq_name, 0) == 0);
6401fcced4cSJordan Brown 	}
6411fcced4cSJordan Brown 
6421fcced4cSJordan Brown 	kmem_free(fq_name, MAXNAMELEN);
6431fcced4cSJordan Brown 	return (match);
6441fcced4cSJordan Brown }
6451fcced4cSJordan Brown 
6461fcced4cSJordan Brown /*
6471fcced4cSJordan Brown  * If the enumeration request is for user data, handle the request
6481fcced4cSJordan Brown  * here.  Otherwise, pass it on to the trees.
6491fcced4cSJordan Brown  *
6501fcced4cSJordan Brown  * This function should be called with a hold on the user.
6511fcced4cSJordan Brown  */
6521fcced4cSJordan Brown int
6531fcced4cSJordan Brown smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
6541fcced4cSJordan Brown {
6553b13a1efSThomas Keiser 	int		rc = 0;
6561fcced4cSJordan Brown 
6571fcced4cSJordan Brown 	ASSERT(user);
6581fcced4cSJordan Brown 	ASSERT(user->u_magic == SMB_USER_MAGIC);
6591fcced4cSJordan Brown 
6601fcced4cSJordan Brown 	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
6611fcced4cSJordan Brown 		return (smb_user_enum_private(user, svcenum));
6621fcced4cSJordan Brown 
6631fcced4cSJordan Brown 	return (rc);
6641fcced4cSJordan Brown }
6651fcced4cSJordan Brown 
6661baeef30SPrashanth Badari /*
6671baeef30SPrashanth Badari  * Count references by trees this user owns,
6681baeef30SPrashanth Badari  * and allow waiting for them to go away.
6691baeef30SPrashanth Badari  */
6701baeef30SPrashanth Badari void
6711baeef30SPrashanth Badari smb_user_inc_trees(smb_user_t *user)
6721baeef30SPrashanth Badari {
6731baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
6741baeef30SPrashanth Badari 	user->u_owned_tree_cnt++;
6751baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
6761baeef30SPrashanth Badari }
6771baeef30SPrashanth Badari 
6781baeef30SPrashanth Badari void
6791baeef30SPrashanth Badari smb_user_dec_trees(smb_user_t *user)
6801baeef30SPrashanth Badari {
6811baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
6821baeef30SPrashanth Badari 	user->u_owned_tree_cnt--;
6831baeef30SPrashanth Badari 	if (user->u_owned_tree_cnt == 0)
6841baeef30SPrashanth Badari 		cv_broadcast(&user->u_owned_tree_cv);
6851baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
6861baeef30SPrashanth Badari }
6871baeef30SPrashanth Badari 
6881baeef30SPrashanth Badari int smb_user_wait_tree_tmo = 30;
6891baeef30SPrashanth Badari 
6901baeef30SPrashanth Badari /*
6911baeef30SPrashanth Badari  * Wait (up to 30 sec.) for trees to go away.
6921baeef30SPrashanth Badari  * Should happen in less than a second.
6931baeef30SPrashanth Badari  */
6941baeef30SPrashanth Badari void
6951baeef30SPrashanth Badari smb_user_wait_trees(smb_user_t *user)
6961baeef30SPrashanth Badari {
6971baeef30SPrashanth Badari 	clock_t	time;
6981baeef30SPrashanth Badari 
6991baeef30SPrashanth Badari 	time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt();
7001baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
7011baeef30SPrashanth Badari 	while (user->u_owned_tree_cnt != 0) {
7021baeef30SPrashanth Badari 		if (cv_timedwait(&user->u_owned_tree_cv,
7031baeef30SPrashanth Badari 		    &user->u_mutex, time) < 0)
7041baeef30SPrashanth Badari 			break;
7051baeef30SPrashanth Badari 	}
7061baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
7071baeef30SPrashanth Badari #ifdef	DEBUG
7081baeef30SPrashanth Badari 	if (user->u_owned_tree_cnt != 0) {
7091baeef30SPrashanth Badari 		cmn_err(CE_NOTE, "smb_user_wait_trees failed");
7101baeef30SPrashanth Badari 		debug_enter("smb_user_wait_trees debug");
7111baeef30SPrashanth Badari 	}
7121baeef30SPrashanth Badari #endif
7131baeef30SPrashanth Badari }
7141baeef30SPrashanth Badari 
715da6c28aaSamw /* *************************** Static Functions ***************************** */
716da6c28aaSamw 
717da6c28aaSamw /*
7189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Delete a user.  The tree list should be empty.
7199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
7209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Remove the user from the session's user list before freeing resources
7219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * associated with the user.
722da6c28aaSamw  */
723811599a4SMatt Barden static void
7249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_delete(void *arg)
725da6c28aaSamw {
726da6c28aaSamw 	smb_session_t	*session;
7279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user = (smb_user_t *)arg;
728811599a4SMatt Barden 	uint32_t	ucount;
729da6c28aaSamw 
7309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_USER_VALID(user);
731da6c28aaSamw 	ASSERT(user->u_refcnt == 0);
732da6c28aaSamw 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
73312b65585SGordon Ross 	ASSERT(user->u_authsock == NULL);
7348f70e16bSGordon Ross 	ASSERT(user->u_auth_tmo == NULL);
735da6c28aaSamw 
736da6c28aaSamw 	session = user->u_session;
737811599a4SMatt Barden 
738811599a4SMatt Barden 	smb_server_dec_users(session->s_server);
739da6c28aaSamw 	smb_llist_enter(&session->s_user_list, RW_WRITER);
740da6c28aaSamw 	smb_llist_remove(&session->s_user_list, user);
7419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
742811599a4SMatt Barden 	ucount = smb_llist_get_count(&session->s_user_list);
743da6c28aaSamw 	smb_llist_exit(&session->s_user_list);
744da6c28aaSamw 
745817fa55fSGordon Ross 	/*
746817fa55fSGordon Ross 	 * When the last smb_user_t object goes away, schedule a timeout
747817fa55fSGordon Ross 	 * after which we'll terminate this session if the client hasn't
748817fa55fSGordon Ross 	 * authenticated another smb_user_t on this session by then.
749817fa55fSGordon Ross 	 */
750811599a4SMatt Barden 	if (ucount == 0) {
751811599a4SMatt Barden 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
752817fa55fSGordon Ross 		if (session->s_state == SMB_SESSION_STATE_NEGOTIATED &&
753817fa55fSGordon Ross 		    session->s_auth_tmo == NULL) {
754817fa55fSGordon Ross 			session->s_auth_tmo =
755817fa55fSGordon Ross 			    timeout((tmo_func_t)smb_session_disconnect,
756817fa55fSGordon Ross 			    session, SEC_TO_TICK(smb_session_auth_tmo));
757817fa55fSGordon Ross 		}
758811599a4SMatt Barden 		smb_rwx_cvbcast(&session->s_lock);
759811599a4SMatt Barden 		smb_rwx_rwexit(&session->s_lock);
760811599a4SMatt Barden 	}
761811599a4SMatt Barden 
762811599a4SMatt Barden 	/*
763811599a4SMatt Barden 	 * This user is no longer on s_user_list, however...
764811599a4SMatt Barden 	 *
765811599a4SMatt Barden 	 * This is called via smb_llist_post, which means it may run
766811599a4SMatt Barden 	 * BEFORE smb_user_release drops u_mutex (if another thread
767811599a4SMatt Barden 	 * flushes the delete queue before we do).  Synchronize.
768811599a4SMatt Barden 	 */
7699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&user->u_mutex);
7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&user->u_mutex);
7719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
772da6c28aaSamw 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
773da6c28aaSamw 	mutex_destroy(&user->u_mutex);
774148c5f43SAlan Wright 	if (user->u_cred)
775da6c28aaSamw 		crfree(user->u_cred);
776b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (user->u_privcred)
777b89a8333Snatalie li - Sun Microsystems - Irvine United States 		crfree(user->u_privcred);
7789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_mem_free(user->u_name);
7799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_mem_free(user->u_domain);
7808622ec45SGordon Ross 	kmem_cache_free(smb_cache_user, user);
781da6c28aaSamw }
782c8ec8eeaSjose borrego 
783b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
784b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getcred(smb_user_t *user)
785b89a8333Snatalie li - Sun Microsystems - Irvine United States {
786b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (user->u_cred);
787b89a8333Snatalie li - Sun Microsystems - Irvine United States }
788b89a8333Snatalie li - Sun Microsystems - Irvine United States 
789b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
790b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getprivcred(smb_user_t *user)
791b89a8333Snatalie li - Sun Microsystems - Irvine United States {
792b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
793b89a8333Snatalie li - Sun Microsystems - Irvine United States }
7941fcced4cSJordan Brown 
795b819cea2SGordon Ross #ifdef	_KERNEL
7961fcced4cSJordan Brown /*
797148c5f43SAlan Wright  * Assign the user cred and privileges.
798148c5f43SAlan Wright  *
799148c5f43SAlan Wright  * If the user has backup and/or restore privleges, dup the cred
800148c5f43SAlan Wright  * and add those privileges to this new privileged cred.
801148c5f43SAlan Wright  */
802b819cea2SGordon Ross void
803148c5f43SAlan Wright smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
804148c5f43SAlan Wright {
805148c5f43SAlan Wright 	cred_t *privcred = NULL;
806148c5f43SAlan Wright 
807148c5f43SAlan Wright 	ASSERT(cr);
808148c5f43SAlan Wright 	crhold(cr);
809148c5f43SAlan Wright 
8100292c176SMatt Barden 	/*
8110292c176SMatt Barden 	 * See smb.4 bypass_traverse_checking
8120292c176SMatt Barden 	 *
8130292c176SMatt Barden 	 * For historical reasons, the Windows privilege is named
8140292c176SMatt Barden 	 * SeChangeNotifyPrivilege, though the description is
8150292c176SMatt Barden 	 * "Bypass traverse checking".
8160292c176SMatt Barden 	 */
8170292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_CHANGE_NOTIFY) != 0) {
8180292c176SMatt Barden 		(void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL);
8190292c176SMatt Barden 	}
8200292c176SMatt Barden 
8210292c176SMatt Barden 	/*
8220292c176SMatt Barden 	 * Window's "take ownership privilege" is similar to our
8230292c176SMatt Barden 	 * PRIV_FILE_CHOWN privilege. It's normally given to members of the
8240292c176SMatt Barden 	 * "Administrators" group, which normally includes the the local
8250292c176SMatt Barden 	 * Administrator (like root) and when joined to a domain,
8260292c176SMatt Barden 	 * "Domain Admins".
8270292c176SMatt Barden 	 */
8280292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_TAKE_OWNERSHIP) != 0) {
8290292c176SMatt Barden 		(void) crsetpriv(cr,
8300292c176SMatt Barden 		    PRIV_FILE_CHOWN,
8310292c176SMatt Barden 		    PRIV_FILE_CHOWN_SELF,
8320292c176SMatt Barden 		    NULL);
8330292c176SMatt Barden 	}
8340292c176SMatt Barden 
8350292c176SMatt Barden 	/*
8360292c176SMatt Barden 	 * Bypass ACL for READ accesses.
8370292c176SMatt Barden 	 */
8380292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_READ_FILE) != 0) {
8390292c176SMatt Barden 		(void) crsetpriv(cr, PRIV_FILE_DAC_READ, NULL);
8400292c176SMatt Barden 	}
8410292c176SMatt Barden 
8420292c176SMatt Barden 	/*
8430292c176SMatt Barden 	 * Bypass ACL for WRITE accesses.
8440292c176SMatt Barden 	 * Include FILE_OWNER, as it covers WRITE_ACL and DELETE.
8450292c176SMatt Barden 	 */
8460292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_WRITE_FILE) != 0) {
8470292c176SMatt Barden 		(void) crsetpriv(cr,
8480292c176SMatt Barden 		    PRIV_FILE_DAC_WRITE,
8490292c176SMatt Barden 		    PRIV_FILE_OWNER,
8500292c176SMatt Barden 		    NULL);
8510292c176SMatt Barden 	}
8520292c176SMatt Barden 
8530292c176SMatt Barden 	/*
8540292c176SMatt Barden 	 * These privileges are used only when a file is opened with
8550292c176SMatt Barden 	 * 'backup intent'. These allow users to bypass certain access
8560292c176SMatt Barden 	 * controls. Administrators typically have these privileges,
8570292c176SMatt Barden 	 * and they are used during recursive take-ownership operations.
8580292c176SMatt Barden 	 * Some commonly used tools use 'backup intent' to administrate
8590292c176SMatt Barden 	 * files that do not grant explicit permissions to Administrators.
8600292c176SMatt Barden 	 */
861148c5f43SAlan Wright 	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
862148c5f43SAlan Wright 		privcred = crdup(cr);
863148c5f43SAlan Wright 
864148c5f43SAlan Wright 	if (privcred != NULL) {
865148c5f43SAlan Wright 		if (privileges & SMB_USER_PRIV_BACKUP) {
866148c5f43SAlan Wright 			(void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
867148c5f43SAlan Wright 			    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
868148c5f43SAlan Wright 		}
869148c5f43SAlan Wright 
870148c5f43SAlan Wright 		if (privileges & SMB_USER_PRIV_RESTORE) {
871148c5f43SAlan Wright 			(void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
872148c5f43SAlan Wright 			    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
873148c5f43SAlan Wright 			    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
874148c5f43SAlan Wright 			    PRIV_FILE_OWNER, PRIV_FILE_SETID,
875148c5f43SAlan Wright 			    PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
876148c5f43SAlan Wright 		}
877148c5f43SAlan Wright 	}
878148c5f43SAlan Wright 
879148c5f43SAlan Wright 	user->u_cred = cr;
880148c5f43SAlan Wright 	user->u_privcred = privcred;
881148c5f43SAlan Wright 	user->u_privileges = privileges;
882148c5f43SAlan Wright }
883b819cea2SGordon Ross #endif	/* _KERNEL */
884148c5f43SAlan Wright 
885148c5f43SAlan Wright /*
8869e3ab9e9SMatt Barden  * Determines whether a user can be granted ACCESS_SYSTEM_SECURITY
8879e3ab9e9SMatt Barden  */
8889e3ab9e9SMatt Barden boolean_t
8899e3ab9e9SMatt Barden smb_user_has_security_priv(smb_user_t *user, cred_t *cr)
8909e3ab9e9SMatt Barden {
8919e3ab9e9SMatt Barden 	/* Need SeSecurityPrivilege to get/set SACL */
8929e3ab9e9SMatt Barden 	if ((user->u_privileges & SMB_USER_PRIV_SECURITY) != 0)
8939e3ab9e9SMatt Barden 		return (B_TRUE);
8949e3ab9e9SMatt Barden 
8959e3ab9e9SMatt Barden #ifdef _KERNEL
8969e3ab9e9SMatt Barden 	/*
8979e3ab9e9SMatt Barden 	 * ACCESS_SYSTEM_SECURITY is also granted if the file is opened with
8989e3ab9e9SMatt Barden 	 * BACKUP/RESTORE intent by a user with BACKUP/RESTORE privilege,
8999e3ab9e9SMatt Barden 	 * which means we'll be using u_privcred.
9009e3ab9e9SMatt Barden 	 *
9019e3ab9e9SMatt Barden 	 * We translate BACKUP as DAC_READ and RESTORE as DAC_WRITE,
9029e3ab9e9SMatt Barden 	 * to account for our various SMB_USER_* privileges.
9039e3ab9e9SMatt Barden 	 */
9049e3ab9e9SMatt Barden 	if (PRIV_POLICY_ONLY(cr,
9059e3ab9e9SMatt Barden 	    priv_getbyname(PRIV_FILE_DAC_READ, 0), B_FALSE) ||
9069e3ab9e9SMatt Barden 	    PRIV_POLICY_ONLY(cr,
9079e3ab9e9SMatt Barden 	    priv_getbyname(PRIV_FILE_DAC_WRITE, 0), B_FALSE))
9089e3ab9e9SMatt Barden 		return (B_TRUE);
9099e3ab9e9SMatt Barden #else
9109e3ab9e9SMatt Barden 	/*
9119e3ab9e9SMatt Barden 	 * No "real" privileges in fksmbsrv, so use the SMB privs instead.
9129e3ab9e9SMatt Barden 	 */
9139e3ab9e9SMatt Barden 	if ((user->u_privileges &
9149e3ab9e9SMatt Barden 	    (SMB_USER_PRIV_BACKUP |
9159e3ab9e9SMatt Barden 	    SMB_USER_PRIV_RESTORE |
9169e3ab9e9SMatt Barden 	    SMB_USER_PRIV_READ_FILE |
9179e3ab9e9SMatt Barden 	    SMB_USER_PRIV_WRITE_FILE)) != 0)
9189e3ab9e9SMatt Barden 		return (B_TRUE);
9199e3ab9e9SMatt Barden #endif
9209e3ab9e9SMatt Barden 
9219e3ab9e9SMatt Barden 	return (B_FALSE);
9229e3ab9e9SMatt Barden }
9239e3ab9e9SMatt Barden 
9249e3ab9e9SMatt Barden /*
9251fcced4cSJordan Brown  * Private function to support smb_user_enum.
9261fcced4cSJordan Brown  */
9271fcced4cSJordan Brown static int
9281fcced4cSJordan Brown smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
9291fcced4cSJordan Brown {
9301fcced4cSJordan Brown 	uint8_t *pb;
9311fcced4cSJordan Brown 	uint_t nbytes;
9321fcced4cSJordan Brown 	int rc;
9331fcced4cSJordan Brown 
9341fcced4cSJordan Brown 	if (svcenum->se_nskip > 0) {
9351fcced4cSJordan Brown 		svcenum->se_nskip--;
9361fcced4cSJordan Brown 		return (0);
9371fcced4cSJordan Brown 	}
9381fcced4cSJordan Brown 
9391fcced4cSJordan Brown 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
9401fcced4cSJordan Brown 		svcenum->se_nitems = svcenum->se_nlimit;
9411fcced4cSJordan Brown 		return (0);
9421fcced4cSJordan Brown 	}
9431fcced4cSJordan Brown 
9441fcced4cSJordan Brown 	pb = &svcenum->se_buf[svcenum->se_bused];
9451fcced4cSJordan Brown 	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
9461fcced4cSJordan Brown 	if (rc == 0) {
9471fcced4cSJordan Brown 		svcenum->se_bavail -= nbytes;
9481fcced4cSJordan Brown 		svcenum->se_bused += nbytes;
9491fcced4cSJordan Brown 		svcenum->se_nitems++;
9501fcced4cSJordan Brown 	}
9511fcced4cSJordan Brown 
9521fcced4cSJordan Brown 	return (rc);
9531fcced4cSJordan Brown }
9541fcced4cSJordan Brown 
9551fcced4cSJordan Brown /*
9561fcced4cSJordan Brown  * Encode the NetInfo for a user into a buffer.  NetInfo contains
9571fcced4cSJordan Brown  * information that is often needed in user space to support RPC
9581fcced4cSJordan Brown  * requests.
9591fcced4cSJordan Brown  */
9601fcced4cSJordan Brown int
9611fcced4cSJordan Brown smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
9621fcced4cSJordan Brown     uint32_t *nbytes)
9631fcced4cSJordan Brown {
9641fcced4cSJordan Brown 	smb_netuserinfo_t	info;
9651fcced4cSJordan Brown 	int			rc;
9661fcced4cSJordan Brown 
9671fcced4cSJordan Brown 	smb_user_netinfo_init(user, &info);
9681fcced4cSJordan Brown 	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
9691fcced4cSJordan Brown 	smb_user_netinfo_fini(&info);
9701fcced4cSJordan Brown 
9711fcced4cSJordan Brown 	return (rc);
9721fcced4cSJordan Brown }
9731fcced4cSJordan Brown 
9741fcced4cSJordan Brown void
9751fcced4cSJordan Brown smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
9761fcced4cSJordan Brown {
9771fcced4cSJordan Brown 	smb_session_t	*session;
9781fcced4cSJordan Brown 	char		*buf;
9791fcced4cSJordan Brown 
9801fcced4cSJordan Brown 	ASSERT(user);
9811fcced4cSJordan Brown 	ASSERT(user->u_domain);
9821fcced4cSJordan Brown 	ASSERT(user->u_name);
9831fcced4cSJordan Brown 
9841fcced4cSJordan Brown 	session = user->u_session;
9851fcced4cSJordan Brown 	ASSERT(session);
9861fcced4cSJordan Brown 	ASSERT(session->workstation);
9871fcced4cSJordan Brown 
9881fcced4cSJordan Brown 	info->ui_session_id = session->s_kid;
9891fcced4cSJordan Brown 	info->ui_native_os = session->native_os;
9901fcced4cSJordan Brown 	info->ui_ipaddr = session->ipaddr;
9911fcced4cSJordan Brown 	info->ui_numopens = session->s_file_cnt;
9921fcced4cSJordan Brown 	info->ui_logon_time = user->u_logon_time;
9931fcced4cSJordan Brown 	info->ui_flags = user->u_flags;
994c5866007SKeyur Desai 	info->ui_posix_uid = crgetuid(user->u_cred);
9951fcced4cSJordan Brown 
9961fcced4cSJordan Brown 	info->ui_domain_len = user->u_domain_len;
9979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_domain = smb_mem_strdup(user->u_domain);
9981fcced4cSJordan Brown 
9991fcced4cSJordan Brown 	info->ui_account_len = user->u_name_len;
10009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_account = smb_mem_strdup(user->u_name);
10011fcced4cSJordan Brown 
10021fcced4cSJordan Brown 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
10031fcced4cSJordan Brown 	smb_session_getclient(session, buf, MAXNAMELEN);
10041fcced4cSJordan Brown 	info->ui_workstation_len = strlen(buf) + 1;
10059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_workstation = smb_mem_strdup(buf);
10061fcced4cSJordan Brown 	kmem_free(buf, MAXNAMELEN);
10071fcced4cSJordan Brown }
10081fcced4cSJordan Brown 
10091fcced4cSJordan Brown void
10101fcced4cSJordan Brown smb_user_netinfo_fini(smb_netuserinfo_t *info)
10111fcced4cSJordan Brown {
10121fcced4cSJordan Brown 	if (info == NULL)
10131fcced4cSJordan Brown 		return;
10141fcced4cSJordan Brown 
10151fcced4cSJordan Brown 	if (info->ui_domain)
10169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_domain);
10171fcced4cSJordan Brown 	if (info->ui_account)
10189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_account);
10191fcced4cSJordan Brown 	if (info->ui_workstation)
10209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_workstation);
10211fcced4cSJordan Brown 
10221fcced4cSJordan Brown 	bzero(info, sizeof (smb_netuserinfo_t));
10231fcced4cSJordan Brown }
10249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1025811599a4SMatt Barden /*
1026811599a4SMatt Barden  * Tell smbd this user is going away so it can clean up their
1027811599a4SMatt Barden  * audit session, autohome dir, etc.
1028811599a4SMatt Barden  *
1029811599a4SMatt Barden  * Note that when we're shutting down, smbd will already have set
1030811599a4SMatt Barden  * smbd.s_shutting_down and therefore will ignore door calls.
1031811599a4SMatt Barden  * Skip this during shutdown to reduce upcall noise.
1032811599a4SMatt Barden  */
10339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
10348622ec45SGordon Ross smb_user_auth_logoff(smb_user_t *user)
10359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
1036811599a4SMatt Barden 	smb_server_t *sv = user->u_server;
1037811599a4SMatt Barden 	uint32_t audit_sid;
10388622ec45SGordon Ross 
1039811599a4SMatt Barden 	if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
1040811599a4SMatt Barden 		return;
1041811599a4SMatt Barden 
1042811599a4SMatt Barden 	audit_sid = user->u_audit_sid;
1043811599a4SMatt Barden 	(void) smb_kdoor_upcall(sv, SMB_DR_USER_AUTH_LOGOFF,
10449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    &audit_sid, xdr_uint32_t, NULL, NULL);
10459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1046811599a4SMatt Barden 
1047811599a4SMatt Barden boolean_t
1048811599a4SMatt Barden smb_is_same_user(cred_t *cr1, cred_t *cr2)
1049811599a4SMatt Barden {
1050811599a4SMatt Barden 	ksid_t *ks1 = crgetsid(cr1, KSID_USER);
1051811599a4SMatt Barden 	ksid_t *ks2 = crgetsid(cr2, KSID_USER);
1052811599a4SMatt Barden 
1053bf996dbcSPrashanth Badari 	if (ks1 == NULL || ks2 == NULL) {
1054bf996dbcSPrashanth Badari 		return (B_FALSE);
1055bf996dbcSPrashanth Badari 	}
1056811599a4SMatt Barden 	return (ks1->ks_rid == ks2->ks_rid &&
1057811599a4SMatt Barden 	    strcmp(ks1->ks_domain->kd_name, ks2->ks_domain->kd_name) == 0);
1058811599a4SMatt Barden }
1059