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.
23f37b3cbbSMatt Barden  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
2586184067SGordon Ross  * Copyright 2022-2023 RackTop Systems, Inc.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * General Structures Layout
30da6c28aaSamw  * -------------------------
31da6c28aaSamw  *
32da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
33da6c28aaSamw  * main structures.
34da6c28aaSamw  *
35da6c28aaSamw  * +-------------------+
36da6c28aaSamw  * |     SMB_INFO      |
37da6c28aaSamw  * +-------------------+
38da6c28aaSamw  *          |
39da6c28aaSamw  *          |
40da6c28aaSamw  *          v
41da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
42da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
443b13a1efSThomas Keiser  *   |          |
453b13a1efSThomas Keiser  *   |          |
463b13a1efSThomas Keiser  *   |          v
473b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
483b13a1efSThomas Keiser  *   |  |       USER        |<--->|       USER        |...|       USER        |
493b13a1efSThomas Keiser  *   |  +-------------------+     +-------------------+   +-------------------+
503b13a1efSThomas Keiser  *   |
513b13a1efSThomas Keiser  *   |
523b13a1efSThomas Keiser  *   v
53da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
54da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
55da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
56da6c28aaSamw  *      |         |
57da6c28aaSamw  *      |         |
58da6c28aaSamw  *      |         v
59da6c28aaSamw  *      |     +-------+       +-------+      +-------+
60da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
61da6c28aaSamw  *      |     +-------+       +-------+      +-------+
62da6c28aaSamw  *      |
63da6c28aaSamw  *      |
64da6c28aaSamw  *      v
65da6c28aaSamw  *  +-------+       +------+      +------+
66da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
67da6c28aaSamw  *  +-------+       +------+      +------+
68da6c28aaSamw  *
69da6c28aaSamw  *
70da6c28aaSamw  * User State Machine
71da6c28aaSamw  * ------------------
72da6c28aaSamw  *
7312b65585SGordon Ross  *
7412b65585SGordon Ross  *		    | T0:  Creation/Allocation
7512b65585SGordon Ross  *		    |	   (1st session setup)
7612b65585SGordon Ross  *		    v
7712b65585SGordon Ross  *    +-----------------------------+
7812b65585SGordon Ross  *    |  SMB_USER_STATE_LOGGING_ON  |<----------+
7912b65585SGordon Ross  *    +-----------------------------+	 addl. session setup
8012b65585SGordon Ross  *		    |		|	(more proc. required)
8112b65585SGordon Ross  *		    | T2	|		^
8212b65585SGordon Ross  *		    |		|		| T1: (cont.)
8312b65585SGordon Ross  *		    |		+------->-------?
8412b65585SGordon Ross  *		    v				| T3: (fail)
8512b65585SGordon Ross  *    +-----------------------------+		v
8612b65585SGordon Ross  *    |  SMB_USER_STATE_LOGGED_ON   |	    (logged off)
87da6c28aaSamw  *    +-----------------------------+
88da6c28aaSamw  *		    |
8912b65585SGordon Ross  *		    | T4
90da6c28aaSamw  *		    |
91da6c28aaSamw  *		    v
92da6c28aaSamw  *    +-----------------------------+
93da6c28aaSamw  *    |  SMB_USER_STATE_LOGGING_OFF |
94da6c28aaSamw  *    +-----------------------------+
95da6c28aaSamw  *		    |
9612b65585SGordon Ross  *		    | T5
97da6c28aaSamw  *		    |
98da6c28aaSamw  *		    v
9912b65585SGordon Ross  *    +-----------------------------+    T6
100da6c28aaSamw  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
101da6c28aaSamw  *    +-----------------------------+
102da6c28aaSamw  *
10312b65585SGordon Ross  * SMB_USER_STATE_LOGGING_ON
104da6c28aaSamw  *
105da6c28aaSamw  *    While in this state:
10648bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
10712b65585SGordon Ross  *      - References will be given out ONLY for session setup.
10812b65585SGordon Ross  *      - This user can not access anything yet.
10912b65585SGordon Ross  *
11012b65585SGordon Ross  * SMB_USER_STATE_LOGGED_ON
11112b65585SGordon Ross  *
11212b65585SGordon Ross  *    While in this state:
11348bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
114da6c28aaSamw  *      - References will be given out if the user is looked up.
115da6c28aaSamw  *      - The user can access files and pipes.
116da6c28aaSamw  *
117da6c28aaSamw  * SMB_USER_STATE_LOGGING_OFF
118da6c28aaSamw  *
119da6c28aaSamw  *    While in this state:
12048bbca81SDaniel Hoffman  *      - The user is in the list of users for their session.
121da6c28aaSamw  *      - References will not be given out if the user is looked up.
122da6c28aaSamw  *      - The trees the user connected are being disconnected.
123da6c28aaSamw  *      - The resources associated with the user remain.
124da6c28aaSamw  *
12512b65585SGordon Ross  * SMB_USER_STATE_LOGGED_OFF
126da6c28aaSamw  *
127da6c28aaSamw  *    While in this state:
12848bbca81SDaniel Hoffman  *      - The user is queued in the list of users of their session.
129da6c28aaSamw  *      - References will not be given out if the user is looked up.
130da6c28aaSamw  *      - The user has no more trees connected.
131da6c28aaSamw  *      - The resources associated with the user remain.
132da6c28aaSamw  *
133da6c28aaSamw  * Transition T0
134da6c28aaSamw  *
13512b65585SGordon Ross  *    First request in an SMB Session Setup sequence creates a
13612b65585SGordon Ross  *    new user object and adds it to the list of users for
13712b65585SGordon Ross  *    this session.  User UID is assigned and returned.
138da6c28aaSamw  *
139da6c28aaSamw  * Transition T1
140da6c28aaSamw  *
14112b65585SGordon Ross  *    Subsequent SMB Session Setup requests (on the same UID
14212b65585SGordon Ross  *    assigned in T0) update the state of this user object,
14312b65585SGordon Ross  *    communicating with smbd for the crypto work.
144da6c28aaSamw  *
145da6c28aaSamw  * Transition T2
146da6c28aaSamw  *
14712b65585SGordon Ross  *    If the SMB Session Setup sequence is successful, T2
14812b65585SGordon Ross  *    makes the new user object available for requests.
14912b65585SGordon Ross  *
15012b65585SGordon Ross  * Transition T3
15112b65585SGordon Ross  *
15212b65585SGordon Ross  *    If an Session Setup request gets an error other than
15312b65585SGordon Ross  *    the expected "more processing required", then T3
15412b65585SGordon Ross  *    leads to state "LOGGED_OFF" and then tear-down of the
15512b65585SGordon Ross  *    partially constructed user.
15612b65585SGordon Ross  *
15712b65585SGordon Ross  * Transition T4
15812b65585SGordon Ross  *
15912b65585SGordon Ross  *    Normal SMB User Logoff request, or session tear-down.
16012b65585SGordon Ross  *
16112b65585SGordon Ross  * Transition T5
16212b65585SGordon Ross  *
163da6c28aaSamw  *    This transition occurs in smb_user_release(). The resources associated
164da6c28aaSamw  *    with the user are deleted as well as the user. For the transition to
165da6c28aaSamw  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
166da6c28aaSamw  *    reference count be zero.
167da6c28aaSamw  *
168da6c28aaSamw  * Comments
169da6c28aaSamw  * --------
170da6c28aaSamw  *
171da6c28aaSamw  *    The state machine of the user structures is controlled by 3 elements:
17248bbca81SDaniel Hoffman  *      - The list of users of the session they belong to.
173da6c28aaSamw  *      - The mutex embedded in the structure itself.
174da6c28aaSamw  *      - The reference count.
175da6c28aaSamw  *
176da6c28aaSamw  *    There's a mutex embedded in the user structure used to protect its fields
177da6c28aaSamw  *    and there's a lock embedded in the list of users of a session. To
178da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
179da6c28aaSamw  *    To insert the user into the list of users of the session and to remove
180da6c28aaSamw  *    the user from it, the lock must be entered in RW_WRITER mode.
181da6c28aaSamw  *
182da6c28aaSamw  *    Rules of access to a user structure:
183da6c28aaSamw  *
184da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
185811599a4SMatt Barden  *       list) have to be entered, the lock must be entered first. Additionally,
186811599a4SMatt Barden  *       one may NOT flush the deleteq of either the tree list or the ofile list
187811599a4SMatt Barden  *       while the user mutex is held.
188da6c28aaSamw  *
189da6c28aaSamw  *    2) All actions applied to a user require a reference count.
190da6c28aaSamw  *
191da6c28aaSamw  *    3) There are 2 ways of getting a reference count. One is when the user
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *       logs in. The other when the user is looked up.
193da6c28aaSamw  *
194da6c28aaSamw  *    It should be noted that the reference count of a user registers the
195da6c28aaSamw  *    number of references to the user in other structures (such as an smb
196da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
197da6c28aaSamw  *
19848bbca81SDaniel Hoffman  *    1) The user is logged in. An user is anchored by their state. If there's
199da6c28aaSamw  *       no activity involving a user currently logged in, the reference
200da6c28aaSamw  *       count of that user is zero.
201da6c28aaSamw  *
202da6c28aaSamw  *    2) The user is queued in the list of users of the session. The fact of
203da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
204da6c28aaSamw  *       reference count.
205da6c28aaSamw  */
206148c5f43SAlan Wright #include <sys/types.h>
207148c5f43SAlan Wright #include <sys/sid.h>
208148c5f43SAlan Wright #include <sys/priv_names.h>
2099e3ab9e9SMatt Barden #include <sys/priv.h>
2109e3ab9e9SMatt Barden #include <sys/policy.h>
211bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
2129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h>
213da6c28aaSamw 
214c8ec8eeaSjose borrego #define	ADMINISTRATORS_SID	"S-1-5-32-544"
215c8ec8eeaSjose borrego 
216811599a4SMatt Barden /* Don't leak object addresses */
217811599a4SMatt Barden #define	SMB_USER_SSNID(u) \
218811599a4SMatt Barden 	((uintptr_t)&smb_cache_user ^ (uintptr_t)(u))
219811599a4SMatt Barden 
220811599a4SMatt Barden static void smb_user_delete(void *);
2211fcced4cSJordan Brown static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
2228622ec45SGordon Ross static void smb_user_auth_logoff(smb_user_t *);
2238f70e16bSGordon Ross static void smb_user_logoff_tq(void *);
224c8ec8eeaSjose borrego 
225da6c28aaSamw /*
226148c5f43SAlan Wright  * Create a new user.
227811599a4SMatt Barden  *
228811599a4SMatt Barden  * For SMB2 and later, session IDs (u_ssnid) need to be unique among all
229811599a4SMatt Barden  * current and "recent" sessions.  The session ID is derived from the
230811599a4SMatt Barden  * address of the smb_user object (obscured by XOR with a constant).
231811599a4SMatt Barden  * This adds a 3-bit generation number in the low bits, incremented
232811599a4SMatt Barden  * when we allocate an smb_user_t from its kmem cache, so it can't
233811599a4SMatt Barden  * be confused with a (recent) previous incarnation of this object.
234da6c28aaSamw  */
235da6c28aaSamw smb_user_t *
smb_user_new(smb_session_t * session)23612b65585SGordon Ross smb_user_new(smb_session_t *session)
237da6c28aaSamw {
238da6c28aaSamw 	smb_user_t	*user;
239811599a4SMatt Barden 	uint_t		gen;	// generation (low 3 bits of ssnid)
240817fa55fSGordon Ross 	uint32_t	ucount;
241da6c28aaSamw 
242da6c28aaSamw 	ASSERT(session);
243da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
244da6c28aaSamw 
2458622ec45SGordon Ross 	user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
246811599a4SMatt Barden 	gen = (user->u_ssnid + 1) & 7;
247da6c28aaSamw 	bzero(user, sizeof (smb_user_t));
24812b65585SGordon Ross 
249da6c28aaSamw 	user->u_refcnt = 1;
250da6c28aaSamw 	user->u_session = session;
251faa1795aSjb 	user->u_server = session->s_server;
252da6c28aaSamw 	user->u_logon_time = gethrestime_sec();
253da6c28aaSamw 
25412b65585SGordon Ross 	if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
25512b65585SGordon Ross 		goto errout;
256811599a4SMatt Barden 	user->u_ssnid = SMB_USER_SSNID(user) + gen;
25712b65585SGordon Ross 
25812b65585SGordon Ross 	mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
25912b65585SGordon Ross 	user->u_state = SMB_USER_STATE_LOGGING_ON;
26012b65585SGordon Ross 	user->u_magic = SMB_USER_MAGIC;
26112b65585SGordon Ross 
26212b65585SGordon Ross 	smb_llist_enter(&session->s_user_list, RW_WRITER);
263817fa55fSGordon Ross 	ucount = smb_llist_get_count(&session->s_user_list);
26412b65585SGordon Ross 	smb_llist_insert_tail(&session->s_user_list, user);
26512b65585SGordon Ross 	smb_llist_exit(&session->s_user_list);
26612b65585SGordon Ross 	smb_server_inc_users(session->s_server);
26712b65585SGordon Ross 
268817fa55fSGordon Ross 	/*
269817fa55fSGordon Ross 	 * If we added the first user to the session, cancel the
270817fa55fSGordon Ross 	 * timeout that was started in smb_session_receiver().
271817fa55fSGordon Ross 	 */
272817fa55fSGordon Ross 	if (ucount == 0) {
273817fa55fSGordon Ross 		timeout_id_t tmo = NULL;
274817fa55fSGordon Ross 
275817fa55fSGordon Ross 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
276817fa55fSGordon Ross 		tmo = session->s_auth_tmo;
277817fa55fSGordon Ross 		session->s_auth_tmo = NULL;
278817fa55fSGordon Ross 		smb_rwx_rwexit(&session->s_lock);
279817fa55fSGordon Ross 
280817fa55fSGordon Ross 		if (tmo != NULL)
281817fa55fSGordon Ross 			(void) untimeout(tmo);
282817fa55fSGordon Ross 	}
283817fa55fSGordon Ross 
28412b65585SGordon Ross 	return (user);
28512b65585SGordon Ross 
28612b65585SGordon Ross errout:
28712b65585SGordon Ross 	if (user->u_uid != 0)
28812b65585SGordon Ross 		smb_idpool_free(&session->s_uid_pool, user->u_uid);
2898622ec45SGordon Ross 	kmem_cache_free(smb_cache_user, user);
290da6c28aaSamw 	return (NULL);
291da6c28aaSamw }
292da6c28aaSamw 
293da6c28aaSamw /*
29412b65585SGordon Ross  * Fill in the details of a user, meaning a transition
29512b65585SGordon Ross  * from state LOGGING_ON to state LOGGED_ON.
296da6c28aaSamw  */
29712b65585SGordon Ross int
smb_user_logon(smb_user_t * user,cred_t * cr,char * domain_name,char * account_name,uint32_t flags,uint32_t privileges,uint32_t audit_sid)29812b65585SGordon Ross smb_user_logon(
29912b65585SGordon Ross     smb_user_t		*user,
30012b65585SGordon Ross     cred_t		*cr,
30112b65585SGordon Ross     char		*domain_name,
30212b65585SGordon Ross     char		*account_name,
30312b65585SGordon Ross     uint32_t		flags,
30412b65585SGordon Ross     uint32_t		privileges,
30512b65585SGordon Ross     uint32_t		audit_sid)
306da6c28aaSamw {
307b210fedeSGordon Ross 	ksocket_t authsock = NULL;
3088f70e16bSGordon Ross 	timeout_id_t tmo = NULL;
309da6c28aaSamw 
31012b65585SGordon Ross 	ASSERT(user->u_magic == SMB_USER_MAGIC);
31112b65585SGordon Ross 	ASSERT(cr);
31212b65585SGordon Ross 	ASSERT(account_name);
31312b65585SGordon Ross 	ASSERT(domain_name);
314da6c28aaSamw 
31512b65585SGordon Ross 	mutex_enter(&user->u_mutex);
316da6c28aaSamw 
31712b65585SGordon Ross 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
31812b65585SGordon Ross 		mutex_exit(&user->u_mutex);
31912b65585SGordon Ross 		return (-1);
32012b65585SGordon Ross 	}
321da6c28aaSamw 
322b210fedeSGordon Ross 	/*
323b210fedeSGordon Ross 	 * In the transition from LOGGING_ON to LOGGED_ON,
324b210fedeSGordon Ross 	 * we always have an auth. socket to close.
325b210fedeSGordon Ross 	 */
326b210fedeSGordon Ross 	authsock = user->u_authsock;
327b210fedeSGordon Ross 	user->u_authsock = NULL;
3288f70e16bSGordon Ross 	tmo = user->u_auth_tmo;
3298f70e16bSGordon Ross 	user->u_auth_tmo = NULL;
33012b65585SGordon Ross 
33112b65585SGordon Ross 	user->u_state = SMB_USER_STATE_LOGGED_ON;
33212b65585SGordon Ross 	user->u_flags = flags;
33312b65585SGordon Ross 	user->u_name_len = strlen(account_name) + 1;
33412b65585SGordon Ross 	user->u_domain_len = strlen(domain_name) + 1;
33512b65585SGordon Ross 	user->u_name = smb_mem_strdup(account_name);
33612b65585SGordon Ross 	user->u_domain = smb_mem_strdup(domain_name);
33712b65585SGordon Ross 	user->u_audit_sid = audit_sid;
33812b65585SGordon Ross 
33912b65585SGordon Ross 	smb_user_setcred(user, cr, privileges);
34012b65585SGordon Ross 
34112b65585SGordon Ross 	mutex_exit(&user->u_mutex);
34212b65585SGordon Ross 
3438f70e16bSGordon Ross 	/* Timeout callback takes u_mutex. See untimeout(9f) */
3448f70e16bSGordon Ross 	if (tmo != NULL)
3458f70e16bSGordon Ross 		(void) untimeout(tmo);
3468f70e16bSGordon Ross 
347b210fedeSGordon Ross 	/* This close can block, so not under the mutex. */
3488d94f651SGordon Ross 	if (authsock != NULL)
3498d94f651SGordon Ross 		smb_authsock_close(user, authsock);
350b210fedeSGordon Ross 
35112b65585SGordon Ross 	return (0);
352da6c28aaSamw }
353da6c28aaSamw 
354da6c28aaSamw /*
355da6c28aaSamw  * smb_user_logoff
356da6c28aaSamw  *
357811599a4SMatt Barden  * Change the user state to "logging off" and disconnect trees.
3581fcced4cSJordan Brown  * The user list must not be entered or modified here.
359811599a4SMatt Barden  *
360811599a4SMatt Barden  * We remain in state "logging off" until the last ref. is gone,
361811599a4SMatt Barden  * then smb_user_release takes us to state "logged off".
362da6c28aaSamw  */
363da6c28aaSamw void
smb_user_logoff(smb_user_t * user)364da6c28aaSamw smb_user_logoff(
365da6c28aaSamw     smb_user_t		*user)
366da6c28aaSamw {
367b210fedeSGordon Ross 	ksocket_t authsock = NULL;
3688f70e16bSGordon Ross 	timeout_id_t tmo = NULL;
369b210fedeSGordon Ross 
370da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
371da6c28aaSamw 
372da6c28aaSamw 	mutex_enter(&user->u_mutex);
373da6c28aaSamw 	ASSERT(user->u_refcnt);
374da6c28aaSamw 	switch (user->u_state) {
375b210fedeSGordon Ross 	case SMB_USER_STATE_LOGGING_ON:
376b210fedeSGordon Ross 		authsock = user->u_authsock;
377b210fedeSGordon Ross 		user->u_authsock = NULL;
3788f70e16bSGordon Ross 		tmo = user->u_auth_tmo;
3798f70e16bSGordon Ross 		user->u_auth_tmo = NULL;
380811599a4SMatt Barden 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
381811599a4SMatt Barden 		mutex_exit(&user->u_mutex);
382811599a4SMatt Barden 
383811599a4SMatt Barden 		/* Timeout callback takes u_mutex. See untimeout(9f) */
384811599a4SMatt Barden 		if (tmo != NULL)
385811599a4SMatt Barden 			(void) untimeout(tmo);
386811599a4SMatt Barden 		/* This close can block, so not under the mutex. */
387811599a4SMatt Barden 		if (authsock != NULL)
388811599a4SMatt Barden 			smb_authsock_close(user, authsock);
38912b65585SGordon Ross 		break;
39012b65585SGordon Ross 
391b210fedeSGordon Ross 	case SMB_USER_STATE_LOGGED_ON:
392da6c28aaSamw 		/*
393da6c28aaSamw 		 * The user is moved into a state indicating that the log off
394da6c28aaSamw 		 * process has started.
395da6c28aaSamw 		 */
396da6c28aaSamw 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
397da6c28aaSamw 		mutex_exit(&user->u_mutex);
3983b13a1efSThomas Keiser 		smb_session_disconnect_owned_trees(user->u_session, user);
3998622ec45SGordon Ross 		smb_user_auth_logoff(user);
400da6c28aaSamw 		break;
401b210fedeSGordon Ross 
402da6c28aaSamw 	case SMB_USER_STATE_LOGGED_OFF:
403da6c28aaSamw 	case SMB_USER_STATE_LOGGING_OFF:
404811599a4SMatt Barden 		mutex_exit(&user->u_mutex);
405da6c28aaSamw 		break;
406da6c28aaSamw 
407da6c28aaSamw 	default:
408da6c28aaSamw 		ASSERT(0);
409811599a4SMatt Barden 		mutex_exit(&user->u_mutex);
410da6c28aaSamw 		break;
411da6c28aaSamw 	}
412da6c28aaSamw }
413da6c28aaSamw 
4141fcced4cSJordan Brown /*
4153b13a1efSThomas Keiser  * Take a reference on a user.  Do not return a reference unless the user is in
4163b13a1efSThomas Keiser  * the logged-in state.
4171fcced4cSJordan Brown  */
4181fcced4cSJordan Brown boolean_t
smb_user_hold(smb_user_t * user)4191fcced4cSJordan Brown smb_user_hold(smb_user_t *user)
4201fcced4cSJordan Brown {
4213b13a1efSThomas Keiser 	SMB_USER_VALID(user);
4221fcced4cSJordan Brown 
4231fcced4cSJordan Brown 	mutex_enter(&user->u_mutex);
4241fcced4cSJordan Brown 
42512b65585SGordon Ross 	if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
4261fcced4cSJordan Brown 		user->u_refcnt++;
4271fcced4cSJordan Brown 		mutex_exit(&user->u_mutex);
4281fcced4cSJordan Brown 		return (B_TRUE);
4291fcced4cSJordan Brown 	}
4301fcced4cSJordan Brown 
4311fcced4cSJordan Brown 	mutex_exit(&user->u_mutex);
4321fcced4cSJordan Brown 	return (B_FALSE);
4331fcced4cSJordan Brown }
4341fcced4cSJordan Brown 
4353b13a1efSThomas Keiser /*
4363b13a1efSThomas Keiser  * Unconditionally take a reference on a user.
4373b13a1efSThomas Keiser  */
4383b13a1efSThomas Keiser void
smb_user_hold_internal(smb_user_t * user)4393b13a1efSThomas Keiser smb_user_hold_internal(smb_user_t *user)
4403b13a1efSThomas Keiser {
4413b13a1efSThomas Keiser 	SMB_USER_VALID(user);
4423b13a1efSThomas Keiser 
4433b13a1efSThomas Keiser 	mutex_enter(&user->u_mutex);
4443b13a1efSThomas Keiser 	user->u_refcnt++;
4453b13a1efSThomas Keiser 	mutex_exit(&user->u_mutex);
4463b13a1efSThomas Keiser }
4473b13a1efSThomas Keiser 
448da6c28aaSamw /*
4499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Release a reference on a user.  If the reference count falls to
4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * zero and the user has logged off, post the object for deletion.
4519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Object deletion is deferred to avoid modifying a list while an
4529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * iteration may be in progress.
453da6c28aaSamw  */
454da6c28aaSamw void
smb_user_release(smb_user_t * user)455da6c28aaSamw smb_user_release(
456da6c28aaSamw     smb_user_t		*user)
457da6c28aaSamw {
458811599a4SMatt Barden 	smb_session_t *ssn = user->u_session;
459811599a4SMatt Barden 
460811599a4SMatt Barden 	SMB_USER_VALID(user);
461811599a4SMatt Barden 
462811599a4SMatt Barden 	/* flush the tree list delete queue */
463811599a4SMatt Barden 	smb_llist_flush(&ssn->s_tree_list);
464da6c28aaSamw 
465da6c28aaSamw 	mutex_enter(&user->u_mutex);
466da6c28aaSamw 	ASSERT(user->u_refcnt);
467da6c28aaSamw 	user->u_refcnt--;
468c5866007SKeyur Desai 
469da6c28aaSamw 	switch (user->u_state) {
470811599a4SMatt Barden 	case SMB_USER_STATE_LOGGING_OFF:
471811599a4SMatt Barden 		if (user->u_refcnt == 0) {
472811599a4SMatt Barden 			smb_session_t *ssn = user->u_session;
473811599a4SMatt Barden 			user->u_state = SMB_USER_STATE_LOGGED_OFF;
474811599a4SMatt Barden 			smb_llist_post(&ssn->s_user_list, user,
475811599a4SMatt Barden 			    smb_user_delete);
476811599a4SMatt Barden 		}
477da6c28aaSamw 		break;
478da6c28aaSamw 
47912b65585SGordon Ross 	case SMB_USER_STATE_LOGGING_ON:
48012b65585SGordon Ross 	case SMB_USER_STATE_LOGGED_ON:
481da6c28aaSamw 		break;
482da6c28aaSamw 
483811599a4SMatt Barden 	case SMB_USER_STATE_LOGGED_OFF:
484da6c28aaSamw 	default:
485da6c28aaSamw 		ASSERT(0);
486da6c28aaSamw 		break;
487da6c28aaSamw 	}
488da6c28aaSamw 	mutex_exit(&user->u_mutex);
489da6c28aaSamw }
490da6c28aaSamw 
4918f70e16bSGordon Ross /*
4928f70e16bSGordon Ross  * Timeout handler for user logons that stay too long in
4938f70e16bSGordon Ross  * state SMB_USER_STATE_LOGGING_ON.  This is setup by a
4948f70e16bSGordon Ross  * timeout call in smb_authsock_open, and called in a
4958f70e16bSGordon Ross  * callout thread, so schedule a taskq job to do the
4968f70e16bSGordon Ross  * real work of logging off this user.
4978f70e16bSGordon Ross  */
4988f70e16bSGordon Ross void
smb_user_auth_tmo(void * arg)4998f70e16bSGordon Ross smb_user_auth_tmo(void *arg)
5008f70e16bSGordon Ross {
5018f70e16bSGordon Ross 	smb_user_t *user = arg;
5028f70e16bSGordon Ross 	smb_request_t *sr;
5039788d6deSGordon Ross 	taskqid_t tqid;
5048f70e16bSGordon Ross 
5058f70e16bSGordon Ross 	SMB_USER_VALID(user);
5068f70e16bSGordon Ross 
5078f70e16bSGordon Ross 	/*
5088f70e16bSGordon Ross 	 * If we can't allocate a request, it means the
5098f70e16bSGordon Ross 	 * session is being torn down, so nothing to do.
5108f70e16bSGordon Ross 	 */
5118f70e16bSGordon Ross 	sr = smb_request_alloc(user->u_session, 0);
5128f70e16bSGordon Ross 	if (sr == NULL)
5138f70e16bSGordon Ross 		return;
5148f70e16bSGordon Ross 
5158f70e16bSGordon Ross 	/*
5168f70e16bSGordon Ross 	 * Check user state, and take a hold if it's
5178f70e16bSGordon Ross 	 * still logging on.  If not, we're done.
5188f70e16bSGordon Ross 	 */
5198f70e16bSGordon Ross 	mutex_enter(&user->u_mutex);
5208f70e16bSGordon Ross 	if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
5218f70e16bSGordon Ross 		mutex_exit(&user->u_mutex);
5228f70e16bSGordon Ross 		smb_request_free(sr);
5238f70e16bSGordon Ross 		return;
5248f70e16bSGordon Ross 	}
5258f70e16bSGordon Ross 	/* smb_user_hold_internal */
5268f70e16bSGordon Ross 	user->u_refcnt++;
5278f70e16bSGordon Ross 	mutex_exit(&user->u_mutex);
5288f70e16bSGordon Ross 
5298f70e16bSGordon Ross 	/*
5308f70e16bSGordon Ross 	 * The user hold is given to the SR, and released in
5318f70e16bSGordon Ross 	 * smb_user_logoff_tq / smb_request_free
5328f70e16bSGordon Ross 	 */
5338f70e16bSGordon Ross 	sr->uid_user = user;
5348f70e16bSGordon Ross 	sr->user_cr = user->u_cred;
5358f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
5369788d6deSGordon Ross 	tqid = taskq_dispatch(
5378f70e16bSGordon Ross 	    user->u_server->sv_worker_pool,
5388f70e16bSGordon Ross 	    smb_user_logoff_tq, sr, TQ_SLEEP);
5399788d6deSGordon Ross 	VERIFY(tqid != TASKQID_INVALID);
5408f70e16bSGordon Ross }
5418f70e16bSGordon Ross 
5428f70e16bSGordon Ross /*
5438f70e16bSGordon Ross  * Helper for smb_user_auth_tmo()
5448f70e16bSGordon Ross  */
5458f70e16bSGordon Ross static void
smb_user_logoff_tq(void * arg)5468f70e16bSGordon Ross smb_user_logoff_tq(void *arg)
5478f70e16bSGordon Ross {
5488f70e16bSGordon Ross 	smb_request_t	*sr = arg;
5498f70e16bSGordon Ross 
5508f70e16bSGordon Ross 	SMB_REQ_VALID(sr);
5518f70e16bSGordon Ross 
5528f70e16bSGordon Ross 	mutex_enter(&sr->sr_mutex);
5538f70e16bSGordon Ross 	sr->sr_worker = curthread;
5548f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_ACTIVE;
5558f70e16bSGordon Ross 	mutex_exit(&sr->sr_mutex);
5568f70e16bSGordon Ross 
5578f70e16bSGordon Ross 	smb_user_logoff(sr->uid_user);
5588f70e16bSGordon Ross 
5598f70e16bSGordon Ross 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
5608f70e16bSGordon Ross 	smb_request_free(sr);
5618f70e16bSGordon Ross }
5628f70e16bSGordon Ross 
563c8ec8eeaSjose borrego /*
564c8ec8eeaSjose borrego  * Determine whether or not the user is an administrator.
565c8ec8eeaSjose borrego  * Members of the administrators group have administrative rights.
566c8ec8eeaSjose borrego  */
567c8ec8eeaSjose borrego boolean_t
smb_user_is_admin(smb_user_t * user)568148c5f43SAlan Wright smb_user_is_admin(smb_user_t *user)
569c8ec8eeaSjose borrego {
570b819cea2SGordon Ross #ifdef	_KERNEL
571148c5f43SAlan Wright 	char		sidstr[SMB_SID_STRSZ];
572148c5f43SAlan Wright 	ksidlist_t	*ksidlist;
573f37b3cbbSMatt Barden 	ksid_t		*ksid;
574f37b3cbbSMatt Barden 	uint32_t	rid;
575f37b3cbbSMatt Barden 	int		ret;
576b819cea2SGordon Ross #endif	/* _KERNEL */
577b819cea2SGordon Ross 	boolean_t	rc = B_FALSE;
578c8ec8eeaSjose borrego 
579c8ec8eeaSjose borrego 	ASSERT(user);
580148c5f43SAlan Wright 	ASSERT(user->u_cred);
581c8ec8eeaSjose borrego 
582148c5f43SAlan Wright 	if (SMB_USER_IS_ADMIN(user))
583c8ec8eeaSjose borrego 		return (B_TRUE);
584c8ec8eeaSjose borrego 
585b819cea2SGordon Ross #ifdef	_KERNEL
586148c5f43SAlan Wright 	(void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
587f37b3cbbSMatt Barden 	ret = smb_sid_splitstr(sidstr, &rid);
588f37b3cbbSMatt Barden 	ASSERT3S(ret, ==, 0);
589148c5f43SAlan Wright 
590148c5f43SAlan Wright 	ksidlist = crgetsidlist(user->u_cred);
591148c5f43SAlan Wright 	ASSERT(ksidlist);
592148c5f43SAlan Wright 
593f37b3cbbSMatt Barden 	ksid = crgetsid(user->u_cred, KSID_USER);
594f37b3cbbSMatt Barden 	ASSERT(ksid != NULL);
595f37b3cbbSMatt Barden 	ASSERT(ksid->ks_domain != NULL);
596f37b3cbbSMatt Barden 	ASSERT(ksid->ks_domain->kd_name != NULL);
597f37b3cbbSMatt Barden 
598f37b3cbbSMatt Barden 	if ((rid == ksid->ks_rid &&
599f37b3cbbSMatt Barden 	    strcmp(sidstr, ksid_getdomain(ksid)) == 0) ||
600f37b3cbbSMatt Barden 	    ksidlist_has_sid(ksidlist, sidstr, rid)) {
601f37b3cbbSMatt Barden 		user->u_flags |= SMB_USER_FLAG_ADMIN;
602f37b3cbbSMatt Barden 		rc = B_TRUE;
603f37b3cbbSMatt Barden 	}
604148c5f43SAlan Wright 
605b819cea2SGordon Ross #endif	/* _KERNEL */
606148c5f43SAlan Wright 	return (rc);
607c8ec8eeaSjose borrego }
608c8ec8eeaSjose borrego 
6091fcced4cSJordan Brown /*
6101fcced4cSJordan Brown  * This function should be called with a hold on the user.
6111fcced4cSJordan Brown  */
6121fcced4cSJordan Brown boolean_t
smb_user_namecmp(smb_user_t * user,const char * name)6131fcced4cSJordan Brown smb_user_namecmp(smb_user_t *user, const char *name)
6141fcced4cSJordan Brown {
6151fcced4cSJordan Brown 	char		*fq_name;
6161fcced4cSJordan Brown 	boolean_t	match;
6171fcced4cSJordan Brown 
618bbf6f00cSJordan Brown 	if (smb_strcasecmp(name, user->u_name, 0) == 0)
6191fcced4cSJordan Brown 		return (B_TRUE);
6201fcced4cSJordan Brown 
6211fcced4cSJordan Brown 	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
6221fcced4cSJordan Brown 
6231fcced4cSJordan Brown 	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
6241fcced4cSJordan Brown 	    user->u_domain, user->u_name);
6251fcced4cSJordan Brown 
626bbf6f00cSJordan Brown 	match = (smb_strcasecmp(name, fq_name, 0) == 0);
6271fcced4cSJordan Brown 	if (!match) {
6281fcced4cSJordan Brown 		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
6291fcced4cSJordan Brown 		    user->u_name, user->u_domain);
6301fcced4cSJordan Brown 
631bbf6f00cSJordan Brown 		match = (smb_strcasecmp(name, fq_name, 0) == 0);
6321fcced4cSJordan Brown 	}
6331fcced4cSJordan Brown 
6341fcced4cSJordan Brown 	kmem_free(fq_name, MAXNAMELEN);
6351fcced4cSJordan Brown 	return (match);
6361fcced4cSJordan Brown }
6371fcced4cSJordan Brown 
6381fcced4cSJordan Brown /*
6391fcced4cSJordan Brown  * If the enumeration request is for user data, handle the request
6401fcced4cSJordan Brown  * here.  Otherwise, pass it on to the trees.
6411fcced4cSJordan Brown  *
6421fcced4cSJordan Brown  * This function should be called with a hold on the user.
6431fcced4cSJordan Brown  */
6441fcced4cSJordan Brown int
smb_user_enum(smb_user_t * user,smb_svcenum_t * svcenum)6451fcced4cSJordan Brown smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
6461fcced4cSJordan Brown {
6473b13a1efSThomas Keiser 	int		rc = 0;
6481fcced4cSJordan Brown 
6491fcced4cSJordan Brown 	ASSERT(user);
6501fcced4cSJordan Brown 	ASSERT(user->u_magic == SMB_USER_MAGIC);
6511fcced4cSJordan Brown 
6521fcced4cSJordan Brown 	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
6531fcced4cSJordan Brown 		return (smb_user_enum_private(user, svcenum));
6541fcced4cSJordan Brown 
6551fcced4cSJordan Brown 	return (rc);
6561fcced4cSJordan Brown }
6571fcced4cSJordan Brown 
6581baeef30SPrashanth Badari /*
6591baeef30SPrashanth Badari  * Count references by trees this user owns,
6601baeef30SPrashanth Badari  * and allow waiting for them to go away.
6611baeef30SPrashanth Badari  */
6621baeef30SPrashanth Badari void
smb_user_inc_trees(smb_user_t * user)6631baeef30SPrashanth Badari smb_user_inc_trees(smb_user_t *user)
6641baeef30SPrashanth Badari {
6651baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
6661baeef30SPrashanth Badari 	user->u_owned_tree_cnt++;
6671baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
6681baeef30SPrashanth Badari }
6691baeef30SPrashanth Badari 
6701baeef30SPrashanth Badari void
smb_user_dec_trees(smb_user_t * user)6711baeef30SPrashanth Badari smb_user_dec_trees(smb_user_t *user)
6721baeef30SPrashanth Badari {
6731baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
6741baeef30SPrashanth Badari 	user->u_owned_tree_cnt--;
6751baeef30SPrashanth Badari 	if (user->u_owned_tree_cnt == 0)
6761baeef30SPrashanth Badari 		cv_broadcast(&user->u_owned_tree_cv);
6771baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
6781baeef30SPrashanth Badari }
6791baeef30SPrashanth Badari 
6801baeef30SPrashanth Badari int smb_user_wait_tree_tmo = 30;
6811baeef30SPrashanth Badari 
6821baeef30SPrashanth Badari /*
6831baeef30SPrashanth Badari  * Wait (up to 30 sec.) for trees to go away.
6841baeef30SPrashanth Badari  * Should happen in less than a second.
6851baeef30SPrashanth Badari  */
6861baeef30SPrashanth Badari void
smb_user_wait_trees(smb_user_t * user)6871baeef30SPrashanth Badari smb_user_wait_trees(smb_user_t *user)
6881baeef30SPrashanth Badari {
6891baeef30SPrashanth Badari 	clock_t	time;
6901baeef30SPrashanth Badari 
6911baeef30SPrashanth Badari 	time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt();
6921baeef30SPrashanth Badari 	mutex_enter(&user->u_mutex);
6931baeef30SPrashanth Badari 	while (user->u_owned_tree_cnt != 0) {
6941baeef30SPrashanth Badari 		if (cv_timedwait(&user->u_owned_tree_cv,
6951baeef30SPrashanth Badari 		    &user->u_mutex, time) < 0)
6961baeef30SPrashanth Badari 			break;
6971baeef30SPrashanth Badari 	}
6981baeef30SPrashanth Badari 	mutex_exit(&user->u_mutex);
6991baeef30SPrashanth Badari 	if (user->u_owned_tree_cnt != 0) {
70086184067SGordon Ross #ifdef	DEBUG
70186184067SGordon Ross 		cmn_err(CE_NOTE, "!smb_user_wait_trees failed");
7021baeef30SPrashanth Badari #endif
70386184067SGordon Ross 		DTRACE_PROBE1(max__wait, smb_user_t *, user);
70486184067SGordon Ross 	}
7051baeef30SPrashanth Badari }
7061baeef30SPrashanth Badari 
707da6c28aaSamw /* *************************** Static Functions ***************************** */
708da6c28aaSamw 
709da6c28aaSamw /*
7109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Delete a user.  The tree list should be empty.
7119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  *
7129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Remove the user from the session's user list before freeing resources
7139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * associated with the user.
714da6c28aaSamw  */
715811599a4SMatt Barden static void
smb_user_delete(void * arg)7169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_delete(void *arg)
717da6c28aaSamw {
718da6c28aaSamw 	smb_session_t	*session;
7199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_user_t	*user = (smb_user_t *)arg;
720811599a4SMatt Barden 	uint32_t	ucount;
721da6c28aaSamw 
7229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_USER_VALID(user);
723da6c28aaSamw 	ASSERT(user->u_refcnt == 0);
724da6c28aaSamw 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
72512b65585SGordon Ross 	ASSERT(user->u_authsock == NULL);
7268f70e16bSGordon Ross 	ASSERT(user->u_auth_tmo == NULL);
727da6c28aaSamw 
728da6c28aaSamw 	session = user->u_session;
729811599a4SMatt Barden 
730811599a4SMatt Barden 	smb_server_dec_users(session->s_server);
731da6c28aaSamw 	smb_llist_enter(&session->s_user_list, RW_WRITER);
732da6c28aaSamw 	smb_llist_remove(&session->s_user_list, user);
7339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
734811599a4SMatt Barden 	ucount = smb_llist_get_count(&session->s_user_list);
735da6c28aaSamw 	smb_llist_exit(&session->s_user_list);
736da6c28aaSamw 
737817fa55fSGordon Ross 	/*
738817fa55fSGordon Ross 	 * When the last smb_user_t object goes away, schedule a timeout
739817fa55fSGordon Ross 	 * after which we'll terminate this session if the client hasn't
740817fa55fSGordon Ross 	 * authenticated another smb_user_t on this session by then.
741817fa55fSGordon Ross 	 */
742811599a4SMatt Barden 	if (ucount == 0) {
743811599a4SMatt Barden 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
744817fa55fSGordon Ross 		if (session->s_state == SMB_SESSION_STATE_NEGOTIATED &&
745817fa55fSGordon Ross 		    session->s_auth_tmo == NULL) {
746817fa55fSGordon Ross 			session->s_auth_tmo =
747817fa55fSGordon Ross 			    timeout((tmo_func_t)smb_session_disconnect,
748817fa55fSGordon Ross 			    session, SEC_TO_TICK(smb_session_auth_tmo));
749817fa55fSGordon Ross 		}
750811599a4SMatt Barden 		smb_rwx_cvbcast(&session->s_lock);
751811599a4SMatt Barden 		smb_rwx_rwexit(&session->s_lock);
752811599a4SMatt Barden 	}
753811599a4SMatt Barden 
754811599a4SMatt Barden 	/*
755811599a4SMatt Barden 	 * This user is no longer on s_user_list, however...
756811599a4SMatt Barden 	 *
757811599a4SMatt Barden 	 * This is called via smb_llist_post, which means it may run
758811599a4SMatt Barden 	 * BEFORE smb_user_release drops u_mutex (if another thread
759811599a4SMatt Barden 	 * flushes the delete queue before we do).  Synchronize.
760811599a4SMatt Barden 	 */
7619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&user->u_mutex);
7629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&user->u_mutex);
7639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
764da6c28aaSamw 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
765da6c28aaSamw 	mutex_destroy(&user->u_mutex);
766148c5f43SAlan Wright 	if (user->u_cred)
767148c5f43SAlan Wright 		crfree(user->u_cred);
768b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (user->u_privcred)
769b89a8333Snatalie li - Sun Microsystems - Irvine United States 		crfree(user->u_privcred);
7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_mem_free(user->u_name);
7719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_mem_free(user->u_domain);
7728622ec45SGordon Ross 	kmem_cache_free(smb_cache_user, user);
773da6c28aaSamw }
774c8ec8eeaSjose borrego 
775b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
smb_user_getcred(smb_user_t * user)776b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getcred(smb_user_t *user)
777b89a8333Snatalie li - Sun Microsystems - Irvine United States {
778b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (user->u_cred);
779b89a8333Snatalie li - Sun Microsystems - Irvine United States }
780b89a8333Snatalie li - Sun Microsystems - Irvine United States 
781b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
smb_user_getprivcred(smb_user_t * user)782b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getprivcred(smb_user_t *user)
783b89a8333Snatalie li - Sun Microsystems - Irvine United States {
784b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
785b89a8333Snatalie li - Sun Microsystems - Irvine United States }
7861fcced4cSJordan Brown 
787b819cea2SGordon Ross #ifdef	_KERNEL
788148c5f43SAlan Wright /*
789148c5f43SAlan Wright  * Assign the user cred and privileges.
790148c5f43SAlan Wright  *
791148c5f43SAlan Wright  * If the user has backup and/or restore privleges, dup the cred
792148c5f43SAlan Wright  * and add those privileges to this new privileged cred.
793148c5f43SAlan Wright  */
794b819cea2SGordon Ross void
smb_user_setcred(smb_user_t * user,cred_t * cr,uint32_t privileges)795148c5f43SAlan Wright smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
796148c5f43SAlan Wright {
797148c5f43SAlan Wright 	cred_t *privcred = NULL;
798148c5f43SAlan Wright 
799148c5f43SAlan Wright 	ASSERT(cr);
800148c5f43SAlan Wright 	crhold(cr);
801148c5f43SAlan Wright 
8020292c176SMatt Barden 	/*
8030292c176SMatt Barden 	 * See smb.4 bypass_traverse_checking
8040292c176SMatt Barden 	 *
8050292c176SMatt Barden 	 * For historical reasons, the Windows privilege is named
8060292c176SMatt Barden 	 * SeChangeNotifyPrivilege, though the description is
8070292c176SMatt Barden 	 * "Bypass traverse checking".
8080292c176SMatt Barden 	 */
8090292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_CHANGE_NOTIFY) != 0) {
8100292c176SMatt Barden 		(void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL);
8110292c176SMatt Barden 	}
8120292c176SMatt Barden 
8130292c176SMatt Barden 	/*
8140292c176SMatt Barden 	 * Window's "take ownership privilege" is similar to our
8150292c176SMatt Barden 	 * PRIV_FILE_CHOWN privilege. It's normally given to members of the
8160292c176SMatt Barden 	 * "Administrators" group, which normally includes the the local
8170292c176SMatt Barden 	 * Administrator (like root) and when joined to a domain,
8180292c176SMatt Barden 	 * "Domain Admins".
8190292c176SMatt Barden 	 */
8200292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_TAKE_OWNERSHIP) != 0) {
8210292c176SMatt Barden 		(void) crsetpriv(cr,
8220292c176SMatt Barden 		    PRIV_FILE_CHOWN,
8230292c176SMatt Barden 		    PRIV_FILE_CHOWN_SELF,
8240292c176SMatt Barden 		    NULL);
8250292c176SMatt Barden 	}
8260292c176SMatt Barden 
8270292c176SMatt Barden 	/*
8280292c176SMatt Barden 	 * Bypass ACL for READ accesses.
8290292c176SMatt Barden 	 */
8300292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_READ_FILE) != 0) {
8310292c176SMatt Barden 		(void) crsetpriv(cr, PRIV_FILE_DAC_READ, NULL);
8320292c176SMatt Barden 	}
8330292c176SMatt Barden 
8340292c176SMatt Barden 	/*
8350292c176SMatt Barden 	 * Bypass ACL for WRITE accesses.
8360292c176SMatt Barden 	 * Include FILE_OWNER, as it covers WRITE_ACL and DELETE.
8370292c176SMatt Barden 	 */
8380292c176SMatt Barden 	if ((privileges & SMB_USER_PRIV_WRITE_FILE) != 0) {
8390292c176SMatt Barden 		(void) crsetpriv(cr,
8400292c176SMatt Barden 		    PRIV_FILE_DAC_WRITE,
8410292c176SMatt Barden 		    PRIV_FILE_OWNER,
8420292c176SMatt Barden 		    NULL);
8430292c176SMatt Barden 	}
8440292c176SMatt Barden 
8450292c176SMatt Barden 	/*
8460292c176SMatt Barden 	 * These privileges are used only when a file is opened with
8470292c176SMatt Barden 	 * 'backup intent'. These allow users to bypass certain access
8480292c176SMatt Barden 	 * controls. Administrators typically have these privileges,
8490292c176SMatt Barden 	 * and they are used during recursive take-ownership operations.
8500292c176SMatt Barden 	 * Some commonly used tools use 'backup intent' to administrate
8510292c176SMatt Barden 	 * files that do not grant explicit permissions to Administrators.
8520292c176SMatt Barden 	 */
853148c5f43SAlan Wright 	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
854148c5f43SAlan Wright 		privcred = crdup(cr);
855148c5f43SAlan Wright 
856148c5f43SAlan Wright 	if (privcred != NULL) {
857148c5f43SAlan Wright 		if (privileges & SMB_USER_PRIV_BACKUP) {
858148c5f43SAlan Wright 			(void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
859148c5f43SAlan Wright 			    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
860148c5f43SAlan Wright 		}
861148c5f43SAlan Wright 
862148c5f43SAlan Wright 		if (privileges & SMB_USER_PRIV_RESTORE) {
863148c5f43SAlan Wright 			(void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
864148c5f43SAlan Wright 			    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
865148c5f43SAlan Wright 			    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
866148c5f43SAlan Wright 			    PRIV_FILE_OWNER, PRIV_FILE_SETID,
867148c5f43SAlan Wright 			    PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
868148c5f43SAlan Wright 		}
869148c5f43SAlan Wright 	}
870148c5f43SAlan Wright 
871148c5f43SAlan Wright 	user->u_cred = cr;
872148c5f43SAlan Wright 	user->u_privcred = privcred;
873148c5f43SAlan Wright 	user->u_privileges = privileges;
874148c5f43SAlan Wright }
875b819cea2SGordon Ross #endif	/* _KERNEL */
876148c5f43SAlan Wright 
8779e3ab9e9SMatt Barden /*
8789e3ab9e9SMatt Barden  * Determines whether a user can be granted ACCESS_SYSTEM_SECURITY
8799e3ab9e9SMatt Barden  */
8809e3ab9e9SMatt Barden boolean_t
smb_user_has_security_priv(smb_user_t * user,cred_t * cr)8819e3ab9e9SMatt Barden smb_user_has_security_priv(smb_user_t *user, cred_t *cr)
8829e3ab9e9SMatt Barden {
8839e3ab9e9SMatt Barden 	/* Need SeSecurityPrivilege to get/set SACL */
8849e3ab9e9SMatt Barden 	if ((user->u_privileges & SMB_USER_PRIV_SECURITY) != 0)
8859e3ab9e9SMatt Barden 		return (B_TRUE);
8869e3ab9e9SMatt Barden 
8879e3ab9e9SMatt Barden #ifdef _KERNEL
8889e3ab9e9SMatt Barden 	/*
8899e3ab9e9SMatt Barden 	 * ACCESS_SYSTEM_SECURITY is also granted if the file is opened with
8909e3ab9e9SMatt Barden 	 * BACKUP/RESTORE intent by a user with BACKUP/RESTORE privilege,
8919e3ab9e9SMatt Barden 	 * which means we'll be using u_privcred.
8929e3ab9e9SMatt Barden 	 *
8939e3ab9e9SMatt Barden 	 * We translate BACKUP as DAC_READ and RESTORE as DAC_WRITE,
8949e3ab9e9SMatt Barden 	 * to account for our various SMB_USER_* privileges.
8959e3ab9e9SMatt Barden 	 */
8969e3ab9e9SMatt Barden 	if (PRIV_POLICY_ONLY(cr,
8979e3ab9e9SMatt Barden 	    priv_getbyname(PRIV_FILE_DAC_READ, 0), B_FALSE) ||
8989e3ab9e9SMatt Barden 	    PRIV_POLICY_ONLY(cr,
8999e3ab9e9SMatt Barden 	    priv_getbyname(PRIV_FILE_DAC_WRITE, 0), B_FALSE))
9009e3ab9e9SMatt Barden 		return (B_TRUE);
9019e3ab9e9SMatt Barden #else
9029e3ab9e9SMatt Barden 	/*
9039e3ab9e9SMatt Barden 	 * No "real" privileges in fksmbsrv, so use the SMB privs instead.
9049e3ab9e9SMatt Barden 	 */
9059e3ab9e9SMatt Barden 	if ((user->u_privileges &
9069e3ab9e9SMatt Barden 	    (SMB_USER_PRIV_BACKUP |
9079e3ab9e9SMatt Barden 	    SMB_USER_PRIV_RESTORE |
9089e3ab9e9SMatt Barden 	    SMB_USER_PRIV_READ_FILE |
9099e3ab9e9SMatt Barden 	    SMB_USER_PRIV_WRITE_FILE)) != 0)
9109e3ab9e9SMatt Barden 		return (B_TRUE);
9119e3ab9e9SMatt Barden #endif
9129e3ab9e9SMatt Barden 
9139e3ab9e9SMatt Barden 	return (B_FALSE);
9149e3ab9e9SMatt Barden }
9159e3ab9e9SMatt Barden 
9161fcced4cSJordan Brown /*
9171fcced4cSJordan Brown  * Private function to support smb_user_enum.
9181fcced4cSJordan Brown  */
9191fcced4cSJordan Brown static int
smb_user_enum_private(smb_user_t * user,smb_svcenum_t * svcenum)9201fcced4cSJordan Brown smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
9211fcced4cSJordan Brown {
9221fcced4cSJordan Brown 	uint8_t *pb;
9231fcced4cSJordan Brown 	uint_t nbytes;
9241fcced4cSJordan Brown 	int rc;
9251fcced4cSJordan Brown 
9261fcced4cSJordan Brown 	if (svcenum->se_nskip > 0) {
9271fcced4cSJordan Brown 		svcenum->se_nskip--;
9281fcced4cSJordan Brown 		return (0);
9291fcced4cSJordan Brown 	}
9301fcced4cSJordan Brown 
9311fcced4cSJordan Brown 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
9321fcced4cSJordan Brown 		svcenum->se_nitems = svcenum->se_nlimit;
9331fcced4cSJordan Brown 		return (0);
9341fcced4cSJordan Brown 	}
9351fcced4cSJordan Brown 
9361fcced4cSJordan Brown 	pb = &svcenum->se_buf[svcenum->se_bused];
9371fcced4cSJordan Brown 	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
9381fcced4cSJordan Brown 	if (rc == 0) {
9391fcced4cSJordan Brown 		svcenum->se_bavail -= nbytes;
9401fcced4cSJordan Brown 		svcenum->se_bused += nbytes;
9411fcced4cSJordan Brown 		svcenum->se_nitems++;
9421fcced4cSJordan Brown 	}
9431fcced4cSJordan Brown 
9441fcced4cSJordan Brown 	return (rc);
9451fcced4cSJordan Brown }
9461fcced4cSJordan Brown 
9471fcced4cSJordan Brown /*
9481fcced4cSJordan Brown  * Encode the NetInfo for a user into a buffer.  NetInfo contains
9491fcced4cSJordan Brown  * information that is often needed in user space to support RPC
9501fcced4cSJordan Brown  * requests.
9511fcced4cSJordan Brown  */
9521fcced4cSJordan Brown int
smb_user_netinfo_encode(smb_user_t * user,uint8_t * buf,size_t buflen,uint32_t * nbytes)9531fcced4cSJordan Brown smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
9541fcced4cSJordan Brown     uint32_t *nbytes)
9551fcced4cSJordan Brown {
9561fcced4cSJordan Brown 	smb_netuserinfo_t	info;
9571fcced4cSJordan Brown 	int			rc;
9581fcced4cSJordan Brown 
9591fcced4cSJordan Brown 	smb_user_netinfo_init(user, &info);
9601fcced4cSJordan Brown 	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
9611fcced4cSJordan Brown 	smb_user_netinfo_fini(&info);
9621fcced4cSJordan Brown 
9631fcced4cSJordan Brown 	return (rc);
9641fcced4cSJordan Brown }
9651fcced4cSJordan Brown 
9661fcced4cSJordan Brown void
smb_user_netinfo_init(smb_user_t * user,smb_netuserinfo_t * info)9671fcced4cSJordan Brown smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
9681fcced4cSJordan Brown {
9691fcced4cSJordan Brown 	smb_session_t	*session;
9701fcced4cSJordan Brown 	char		*buf;
9711fcced4cSJordan Brown 
9721fcced4cSJordan Brown 	ASSERT(user);
9731fcced4cSJordan Brown 	ASSERT(user->u_domain);
9741fcced4cSJordan Brown 	ASSERT(user->u_name);
9751fcced4cSJordan Brown 
9761fcced4cSJordan Brown 	session = user->u_session;
9771fcced4cSJordan Brown 	ASSERT(session);
9781fcced4cSJordan Brown 	ASSERT(session->workstation);
9791fcced4cSJordan Brown 
9801fcced4cSJordan Brown 	info->ui_session_id = session->s_kid;
98197264293SGordon Ross 	info->ui_user_id = user->u_ssnid;
9821fcced4cSJordan Brown 	info->ui_native_os = session->native_os;
9831fcced4cSJordan Brown 	info->ui_ipaddr = session->ipaddr;
9841fcced4cSJordan Brown 	info->ui_numopens = session->s_file_cnt;
9851fcced4cSJordan Brown 	info->ui_logon_time = user->u_logon_time;
9861fcced4cSJordan Brown 	info->ui_flags = user->u_flags;
987c5866007SKeyur Desai 	info->ui_posix_uid = crgetuid(user->u_cred);
9881fcced4cSJordan Brown 
9891fcced4cSJordan Brown 	info->ui_domain_len = user->u_domain_len;
9909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_domain = smb_mem_strdup(user->u_domain);
9911fcced4cSJordan Brown 
9921fcced4cSJordan Brown 	info->ui_account_len = user->u_name_len;
9939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_account = smb_mem_strdup(user->u_name);
9941fcced4cSJordan Brown 
9951fcced4cSJordan Brown 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
9961fcced4cSJordan Brown 	smb_session_getclient(session, buf, MAXNAMELEN);
9971fcced4cSJordan Brown 	info->ui_workstation_len = strlen(buf) + 1;
9989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	info->ui_workstation = smb_mem_strdup(buf);
9991fcced4cSJordan Brown 	kmem_free(buf, MAXNAMELEN);
10001fcced4cSJordan Brown }
10011fcced4cSJordan Brown 
10021fcced4cSJordan Brown void
smb_user_netinfo_fini(smb_netuserinfo_t * info)10031fcced4cSJordan Brown smb_user_netinfo_fini(smb_netuserinfo_t *info)
10041fcced4cSJordan Brown {
10051fcced4cSJordan Brown 	if (info == NULL)
10061fcced4cSJordan Brown 		return;
10071fcced4cSJordan Brown 
10081fcced4cSJordan Brown 	if (info->ui_domain)
10099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_domain);
10101fcced4cSJordan Brown 	if (info->ui_account)
10119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_account);
10121fcced4cSJordan Brown 	if (info->ui_workstation)
10139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_mem_free(info->ui_workstation);
10141fcced4cSJordan Brown 
10151fcced4cSJordan Brown 	bzero(info, sizeof (smb_netuserinfo_t));
10161fcced4cSJordan Brown }
10179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1018*a9609934SGordon Ross uint64_t smb_user_auth_logoff_failures;
1019*a9609934SGordon Ross 
1020811599a4SMatt Barden /*
1021811599a4SMatt Barden  * Tell smbd this user is going away so it can clean up their
1022811599a4SMatt Barden  * audit session, autohome dir, etc.
1023811599a4SMatt Barden  *
1024811599a4SMatt Barden  * Note that when we're shutting down, smbd will already have set
1025811599a4SMatt Barden  * smbd.s_shutting_down and therefore will ignore door calls.
1026811599a4SMatt Barden  * Skip this during shutdown to reduce upcall noise.
1027811599a4SMatt Barden  */
10289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_user_auth_logoff(smb_user_t * user)10298622ec45SGordon Ross smb_user_auth_logoff(smb_user_t *user)
10309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
1031811599a4SMatt Barden 	smb_server_t *sv = user->u_server;
1032811599a4SMatt Barden 	uint32_t audit_sid;
1033811599a4SMatt Barden 
1034811599a4SMatt Barden 	if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
1035811599a4SMatt Barden 		return;
10368622ec45SGordon Ross 
1037*a9609934SGordon Ross 	if (smb_threshold_enter(&sv->sv_logoff_ct) != 0) {
1038*a9609934SGordon Ross 		smb_user_auth_logoff_failures++;
1039*a9609934SGordon Ross 		return;
1040*a9609934SGordon Ross 	}
1041*a9609934SGordon Ross 
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);
1045*a9609934SGordon Ross 
1046*a9609934SGordon Ross 	smb_threshold_exit(&sv->sv_logoff_ct);
10479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1048811599a4SMatt Barden 
1049811599a4SMatt Barden boolean_t
smb_is_same_user(cred_t * cr1,cred_t * cr2)1050811599a4SMatt Barden smb_is_same_user(cred_t *cr1, cred_t *cr2)
1051811599a4SMatt Barden {
1052811599a4SMatt Barden 	ksid_t *ks1 = crgetsid(cr1, KSID_USER);
1053811599a4SMatt Barden 	ksid_t *ks2 = crgetsid(cr2, KSID_USER);
1054811599a4SMatt Barden 
1055bf996dbcSPrashanth Badari 	if (ks1 == NULL || ks2 == NULL) {
1056bf996dbcSPrashanth Badari 		return (B_FALSE);
1057bf996dbcSPrashanth Badari 	}
1058811599a4SMatt Barden 	return (ks1->ks_rid == ks2->ks_rid &&
1059811599a4SMatt Barden 	    strcmp(ks1->ks_domain->kd_name, ks2->ks_domain->kd_name) == 0);
1060811599a4SMatt Barden }
1061