xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_user.c (revision b89a8333f5e1f75ec0c269b22524bd2eccb972ba)
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 /*
22faa1795aSjb150015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * General Structures Layout
28da6c28aaSamw  * -------------------------
29da6c28aaSamw  *
30da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
31da6c28aaSamw  * main structures.
32da6c28aaSamw  *
33da6c28aaSamw  * +-------------------+
34da6c28aaSamw  * |     SMB_INFO      |
35da6c28aaSamw  * +-------------------+
36da6c28aaSamw  *          |
37da6c28aaSamw  *          |
38da6c28aaSamw  *          v
39da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
40da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
41da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
42da6c28aaSamw  *          |
43da6c28aaSamw  *          |
44da6c28aaSamw  *          v
45da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
46da6c28aaSamw  * |       USER        |<----->|       USER        |......|       USER        |
47da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
48da6c28aaSamw  *          |
49da6c28aaSamw  *          |
50da6c28aaSamw  *          v
51da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
52da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
53da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
54da6c28aaSamw  *      |         |
55da6c28aaSamw  *      |         |
56da6c28aaSamw  *      |         v
57da6c28aaSamw  *      |     +-------+       +-------+      +-------+
58da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
59da6c28aaSamw  *      |     +-------+       +-------+      +-------+
60da6c28aaSamw  *      |
61da6c28aaSamw  *      |
62da6c28aaSamw  *      v
63da6c28aaSamw  *  +-------+       +------+      +------+
64da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
65da6c28aaSamw  *  +-------+       +------+      +------+
66da6c28aaSamw  *
67da6c28aaSamw  *
68da6c28aaSamw  * User State Machine
69da6c28aaSamw  * ------------------
70da6c28aaSamw  *
71da6c28aaSamw  *    +-----------------------------+	 T0
72da6c28aaSamw  *    |  SMB_USER_STATE_LOGGED_IN   |<----------- Creation/Allocation
73da6c28aaSamw  *    +-----------------------------+
74da6c28aaSamw  *		    |
75da6c28aaSamw  *		    | T1
76da6c28aaSamw  *		    |
77da6c28aaSamw  *		    v
78da6c28aaSamw  *    +-----------------------------+
79da6c28aaSamw  *    |  SMB_USER_STATE_LOGGING_OFF |
80da6c28aaSamw  *    +-----------------------------+
81da6c28aaSamw  *		    |
82da6c28aaSamw  *		    | T2
83da6c28aaSamw  *		    |
84da6c28aaSamw  *		    v
85da6c28aaSamw  *    +-----------------------------+    T3
86da6c28aaSamw  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
87da6c28aaSamw  *    +-----------------------------+
88da6c28aaSamw  *
89da6c28aaSamw  * SMB_USER_STATE_LOGGED_IN
90da6c28aaSamw  *
91da6c28aaSamw  *    While in this state:
92da6c28aaSamw  *      - The user is queued in the list of users of his session.
93da6c28aaSamw  *      - References will be given out if the user is looked up.
94da6c28aaSamw  *      - The user can access files and pipes.
95da6c28aaSamw  *
96da6c28aaSamw  * SMB_USER_STATE_LOGGING_OFF
97da6c28aaSamw  *
98da6c28aaSamw  *    While in this state:
99da6c28aaSamw  *      - The user is queued in the list of users of his session.
100da6c28aaSamw  *      - References will not be given out if the user is looked up.
101da6c28aaSamw  *      - The trees the user connected are being disconnected.
102da6c28aaSamw  *      - The resources associated with the user remain.
103da6c28aaSamw  *
104da6c28aaSamw  * SMB_USER_STATE_LOGGING_OFF
105da6c28aaSamw  *
106da6c28aaSamw  *    While in this state:
107da6c28aaSamw  *      - The user is queued in the list of users of his session.
108da6c28aaSamw  *      - References will not be given out if the user is looked up.
109da6c28aaSamw  *      - The user has no more trees connected.
110da6c28aaSamw  *      - The resources associated with the user remain.
111da6c28aaSamw  *
112da6c28aaSamw  * Transition T0
113da6c28aaSamw  *
114da6c28aaSamw  *    This transition occurs in smb_user_login(). A new user is created and
115da6c28aaSamw  *    added to the list of users of a session.
116da6c28aaSamw  *
117da6c28aaSamw  * Transition T1
118da6c28aaSamw  *
119da6c28aaSamw  *    This transition occurs in smb_user_logoff().
120da6c28aaSamw  *
121da6c28aaSamw  * Transition T2
122da6c28aaSamw  *
123da6c28aaSamw  *    This transition occurs in smb_user_release(). The resources associated
124da6c28aaSamw  *    with the user are deleted as well as the user. For the transition to
125da6c28aaSamw  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
126da6c28aaSamw  *    reference count be zero.
127da6c28aaSamw  *
128da6c28aaSamw  * Comments
129da6c28aaSamw  * --------
130da6c28aaSamw  *
131da6c28aaSamw  *    The state machine of the user structures is controlled by 3 elements:
132da6c28aaSamw  *      - The list of users of the session he belongs to.
133da6c28aaSamw  *      - The mutex embedded in the structure itself.
134da6c28aaSamw  *      - The reference count.
135da6c28aaSamw  *
136da6c28aaSamw  *    There's a mutex embedded in the user structure used to protect its fields
137da6c28aaSamw  *    and there's a lock embedded in the list of users of a session. To
138da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
139da6c28aaSamw  *    To insert the user into the list of users of the session and to remove
140da6c28aaSamw  *    the user from it, the lock must be entered in RW_WRITER mode.
141da6c28aaSamw  *
142da6c28aaSamw  *    Rules of access to a user structure:
143da6c28aaSamw  *
144da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
145da6c28aaSamw  *       list) have to be entered, the lock must be entered first.
146da6c28aaSamw  *
147da6c28aaSamw  *    2) All actions applied to a user require a reference count.
148da6c28aaSamw  *
149da6c28aaSamw  *    3) There are 2 ways of getting a reference count. One is when the user
150da6c28aaSamw  *       logs in. The other when the user is looked up. This translates into
151da6c28aaSamw  *       3 functions: smb_user_login(), smb_user_lookup_by_uid() and
152da6c28aaSamw  *       smb_user_lookup_by_credentials.
153da6c28aaSamw  *
154da6c28aaSamw  *    It should be noted that the reference count of a user registers the
155da6c28aaSamw  *    number of references to the user in other structures (such as an smb
156da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
157da6c28aaSamw  *
158da6c28aaSamw  *    1) The user is logged in. An user is anchored by his state. If there's
159da6c28aaSamw  *       no activity involving a user currently logged in, the reference
160da6c28aaSamw  *       count of that user is zero.
161da6c28aaSamw  *
162da6c28aaSamw  *    2) The user is queued in the list of users of the session. The fact of
163da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
164da6c28aaSamw  *       reference count.
165da6c28aaSamw  */
166da6c28aaSamw #include <smbsrv/smb_incl.h>
167da6c28aaSamw #include <smbsrv/smb_door_svc.h>
168da6c28aaSamw 
169c8ec8eeaSjose borrego 
170c8ec8eeaSjose borrego #define	ADMINISTRATORS_SID	"S-1-5-32-544"
171c8ec8eeaSjose borrego 
172c8ec8eeaSjose borrego static smb_sid_t *smb_admins_sid = NULL;
173c8ec8eeaSjose borrego 
174da6c28aaSamw static void smb_user_delete(smb_user_t *user);
175c8ec8eeaSjose borrego static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *);
176c8ec8eeaSjose borrego 
177c8ec8eeaSjose borrego int
178c8ec8eeaSjose borrego smb_user_init(void)
179c8ec8eeaSjose borrego {
180c8ec8eeaSjose borrego 	if (smb_admins_sid != NULL)
181c8ec8eeaSjose borrego 		return (0);
182c8ec8eeaSjose borrego 
183c8ec8eeaSjose borrego 	if ((smb_admins_sid = smb_sid_fromstr(ADMINISTRATORS_SID)) == NULL)
184c8ec8eeaSjose borrego 		return (-1);
185c8ec8eeaSjose borrego 
186c8ec8eeaSjose borrego 	return (0);
187c8ec8eeaSjose borrego }
188c8ec8eeaSjose borrego 
189c8ec8eeaSjose borrego void
190c8ec8eeaSjose borrego smb_user_fini(void)
191c8ec8eeaSjose borrego {
192c8ec8eeaSjose borrego 	if (smb_admins_sid != NULL) {
193c8ec8eeaSjose borrego 		smb_sid_free(smb_admins_sid);
194c8ec8eeaSjose borrego 		smb_admins_sid = NULL;
195c8ec8eeaSjose borrego 	}
196c8ec8eeaSjose borrego }
197da6c28aaSamw 
198da6c28aaSamw /*
199da6c28aaSamw  * smb_user_login
200da6c28aaSamw  *
201da6c28aaSamw  *
202da6c28aaSamw  */
203da6c28aaSamw smb_user_t *
204da6c28aaSamw smb_user_login(
205da6c28aaSamw     smb_session_t	*session,
206da6c28aaSamw     cred_t		*cr,
207da6c28aaSamw     char		*domain_name,
208da6c28aaSamw     char		*account_name,
209da6c28aaSamw     uint32_t		flags,
210da6c28aaSamw     uint32_t		privileges,
211da6c28aaSamw     uint32_t		audit_sid)
212da6c28aaSamw {
213da6c28aaSamw 	smb_user_t	*user;
214da6c28aaSamw 
215da6c28aaSamw 	ASSERT(session);
216da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
217da6c28aaSamw 	ASSERT(cr);
218da6c28aaSamw 	ASSERT(account_name);
219da6c28aaSamw 	ASSERT(domain_name);
220da6c28aaSamw 
221faa1795aSjb150015 	user = kmem_cache_alloc(session->s_server->si_cache_user, KM_SLEEP);
222da6c28aaSamw 	bzero(user, sizeof (smb_user_t));
223da6c28aaSamw 	user->u_refcnt = 1;
224da6c28aaSamw 	user->u_session = session;
225faa1795aSjb150015 	user->u_server = session->s_server;
226da6c28aaSamw 	user->u_logon_time = gethrestime_sec();
227da6c28aaSamw 	user->u_flags = flags;
228da6c28aaSamw 	user->u_privileges = privileges;
229da6c28aaSamw 	user->u_name_len = strlen(account_name) + 1;
230da6c28aaSamw 	user->u_domain_len = strlen(domain_name) + 1;
231da6c28aaSamw 	user->u_name = smb_kstrdup(account_name, user->u_name_len);
232da6c28aaSamw 	user->u_domain = smb_kstrdup(domain_name, user->u_domain_len);
233da6c28aaSamw 	user->u_cred = cr;
234*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	user->u_privcred = smb_cred_create_privs(cr, privileges);
235da6c28aaSamw 	user->u_audit_sid = audit_sid;
236da6c28aaSamw 
237da6c28aaSamw 	if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
238da6c28aaSamw 		if (!smb_idpool_constructor(&user->u_tid_pool)) {
239da6c28aaSamw 			smb_llist_constructor(&user->u_tree_list,
240da6c28aaSamw 			    sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
241da6c28aaSamw 			mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
242*b89a8333Snatalie li - Sun Microsystems - Irvine United States 			crhold(user->u_cred);
243*b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if (user->u_privcred)
244*b89a8333Snatalie li - Sun Microsystems - Irvine United States 				crhold(user->u_privcred);
245da6c28aaSamw 			user->u_state = SMB_USER_STATE_LOGGED_IN;
246da6c28aaSamw 			user->u_magic = SMB_USER_MAGIC;
247da6c28aaSamw 			smb_llist_enter(&session->s_user_list, RW_WRITER);
248da6c28aaSamw 			smb_llist_insert_tail(&session->s_user_list, user);
249da6c28aaSamw 			smb_llist_exit(&session->s_user_list);
250faa1795aSjb150015 			atomic_inc_32(&session->s_server->sv_open_users);
251da6c28aaSamw 			return (user);
252da6c28aaSamw 		}
253da6c28aaSamw 		smb_idpool_free(&session->s_uid_pool, user->u_uid);
254da6c28aaSamw 	}
255da6c28aaSamw 	kmem_free(user->u_name, (size_t)user->u_name_len);
256da6c28aaSamw 	kmem_free(user->u_domain, (size_t)user->u_domain_len);
257faa1795aSjb150015 	kmem_cache_free(session->s_server->si_cache_user, user);
258da6c28aaSamw 	return (NULL);
259da6c28aaSamw }
260da6c28aaSamw 
261da6c28aaSamw /*
262da6c28aaSamw  * Create a new user based on an existing user, used to support
263da6c28aaSamw  * additional SessionSetupX requests for a user on a session.
264da6c28aaSamw  *
265da6c28aaSamw  * Assumes the caller has a reference on the original user from
266da6c28aaSamw  * a user_lookup_by_x call.
267da6c28aaSamw  */
268da6c28aaSamw smb_user_t *
269da6c28aaSamw smb_user_dup(
270da6c28aaSamw     smb_user_t		*orig_user)
271da6c28aaSamw {
272da6c28aaSamw 	smb_user_t	*user;
273da6c28aaSamw 
274da6c28aaSamw 	ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
275da6c28aaSamw 	ASSERT(orig_user->u_refcnt);
276da6c28aaSamw 
277da6c28aaSamw 	user = smb_user_login(orig_user->u_session, orig_user->u_cred,
278da6c28aaSamw 	    orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
279da6c28aaSamw 	    orig_user->u_privileges, orig_user->u_audit_sid);
280da6c28aaSamw 
281da6c28aaSamw 	if (user)
282da6c28aaSamw 		smb_user_nonauth_logon(orig_user->u_audit_sid);
283da6c28aaSamw 
284da6c28aaSamw 	return (user);
285da6c28aaSamw }
286da6c28aaSamw 
287da6c28aaSamw /*
288da6c28aaSamw  * smb_user_logoff
289da6c28aaSamw  *
290da6c28aaSamw  *
291da6c28aaSamw  */
292da6c28aaSamw void
293da6c28aaSamw smb_user_logoff(
294da6c28aaSamw     smb_user_t		*user)
295da6c28aaSamw {
296da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
297da6c28aaSamw 
298da6c28aaSamw 	mutex_enter(&user->u_mutex);
299da6c28aaSamw 	ASSERT(user->u_refcnt);
300da6c28aaSamw 	switch (user->u_state) {
301da6c28aaSamw 	case SMB_USER_STATE_LOGGED_IN: {
302da6c28aaSamw 		/*
303da6c28aaSamw 		 * The user is moved into a state indicating that the log off
304da6c28aaSamw 		 * process has started.
305da6c28aaSamw 		 */
306da6c28aaSamw 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
307da6c28aaSamw 		mutex_exit(&user->u_mutex);
308faa1795aSjb150015 		atomic_dec_32(&user->u_server->sv_open_users);
309da6c28aaSamw 		/*
310da6c28aaSamw 		 * All the trees hanging off of this user are disconnected.
311da6c28aaSamw 		 */
312c8ec8eeaSjose borrego 		smb_user_disconnect_trees(user);
313da6c28aaSamw 		smb_user_auth_logoff(user->u_audit_sid);
314da6c28aaSamw 		mutex_enter(&user->u_mutex);
315da6c28aaSamw 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
316da6c28aaSamw 		break;
317da6c28aaSamw 	}
318da6c28aaSamw 	case SMB_USER_STATE_LOGGED_OFF:
319da6c28aaSamw 	case SMB_USER_STATE_LOGGING_OFF:
320da6c28aaSamw 		break;
321da6c28aaSamw 
322da6c28aaSamw 	default:
323da6c28aaSamw 		ASSERT(0);
324da6c28aaSamw 		break;
325da6c28aaSamw 	}
326da6c28aaSamw 	mutex_exit(&user->u_mutex);
327da6c28aaSamw }
328da6c28aaSamw 
329da6c28aaSamw /*
330da6c28aaSamw  * smb_user_logoff_all
331da6c28aaSamw  *
332da6c28aaSamw  *
333da6c28aaSamw  */
334da6c28aaSamw void
335da6c28aaSamw smb_user_logoff_all(
336da6c28aaSamw     smb_session_t	*session)
337da6c28aaSamw {
338da6c28aaSamw 	smb_user_t	*user;
339da6c28aaSamw 
340da6c28aaSamw 	ASSERT(session);
341da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
342da6c28aaSamw 
343da6c28aaSamw 	smb_llist_enter(&session->s_user_list, RW_READER);
344da6c28aaSamw 	user = smb_llist_head(&session->s_user_list);
345da6c28aaSamw 	while (user) {
346da6c28aaSamw 		ASSERT(user->u_magic == SMB_USER_MAGIC);
347da6c28aaSamw 		ASSERT(user->u_session == session);
348da6c28aaSamw 		mutex_enter(&user->u_mutex);
349da6c28aaSamw 		switch (user->u_state) {
350da6c28aaSamw 		case SMB_USER_STATE_LOGGED_IN:
351da6c28aaSamw 			/* The user is still logged in. */
352da6c28aaSamw 			user->u_refcnt++;
353da6c28aaSamw 			mutex_exit(&user->u_mutex);
354da6c28aaSamw 			smb_llist_exit(&session->s_user_list);
355da6c28aaSamw 			smb_user_logoff(user);
356da6c28aaSamw 			smb_user_release(user);
357da6c28aaSamw 			smb_llist_enter(&session->s_user_list, RW_READER);
358da6c28aaSamw 			user = smb_llist_head(&session->s_user_list);
359da6c28aaSamw 			break;
360da6c28aaSamw 		case SMB_USER_STATE_LOGGING_OFF:
361da6c28aaSamw 		case SMB_USER_STATE_LOGGED_OFF:
362da6c28aaSamw 			/*
363da6c28aaSamw 			 * The user is logged off or logging off.
364da6c28aaSamw 			 */
365da6c28aaSamw 			mutex_exit(&user->u_mutex);
366da6c28aaSamw 			user = smb_llist_next(&session->s_user_list, user);
367da6c28aaSamw 			break;
368da6c28aaSamw 		default:
369da6c28aaSamw 			ASSERT(0);
370da6c28aaSamw 			mutex_exit(&user->u_mutex);
371da6c28aaSamw 			user = smb_llist_next(&session->s_user_list, user);
372da6c28aaSamw 			break;
373da6c28aaSamw 		}
374da6c28aaSamw 	}
375da6c28aaSamw 	smb_llist_exit(&session->s_user_list);
376da6c28aaSamw }
377da6c28aaSamw 
378da6c28aaSamw /*
379da6c28aaSamw  * smb_user_release
380da6c28aaSamw  *
381da6c28aaSamw  *
382da6c28aaSamw  */
383da6c28aaSamw void
384da6c28aaSamw smb_user_release(
385da6c28aaSamw     smb_user_t		*user)
386da6c28aaSamw {
387da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
388da6c28aaSamw 
389da6c28aaSamw 	mutex_enter(&user->u_mutex);
390da6c28aaSamw 	ASSERT(user->u_refcnt);
391da6c28aaSamw 	user->u_refcnt--;
392da6c28aaSamw 	switch (user->u_state) {
393da6c28aaSamw 	case SMB_USER_STATE_LOGGED_OFF:
394da6c28aaSamw 		if (user->u_refcnt == 0) {
395da6c28aaSamw 			mutex_exit(&user->u_mutex);
396da6c28aaSamw 			smb_user_delete(user);
397da6c28aaSamw 			return;
398da6c28aaSamw 		}
399da6c28aaSamw 		break;
400da6c28aaSamw 
401da6c28aaSamw 	case SMB_USER_STATE_LOGGED_IN:
402da6c28aaSamw 	case SMB_USER_STATE_LOGGING_OFF:
403da6c28aaSamw 		break;
404da6c28aaSamw 
405da6c28aaSamw 	default:
406da6c28aaSamw 		ASSERT(0);
407da6c28aaSamw 		break;
408da6c28aaSamw 	}
409da6c28aaSamw 	mutex_exit(&user->u_mutex);
410da6c28aaSamw }
411da6c28aaSamw 
412da6c28aaSamw /*
413da6c28aaSamw  * smb_user_lookup_by_uid
414da6c28aaSamw  *
415da6c28aaSamw  * Find the appropriate user for this request. The request credentials
416da6c28aaSamw  * set here may be overridden by the tree credentials. In domain mode,
417da6c28aaSamw  * the user and tree credentials should be the same. In share mode, the
418da6c28aaSamw  * tree credentials (defined in the share definition) should override
419da6c28aaSamw  * the user credentials.
420da6c28aaSamw  */
421da6c28aaSamw smb_user_t *
422da6c28aaSamw smb_user_lookup_by_uid(
423da6c28aaSamw     smb_session_t	*session,
424da6c28aaSamw     uint16_t		uid)
425da6c28aaSamw {
426da6c28aaSamw 	smb_user_t	*user;
427da6c28aaSamw 
428da6c28aaSamw 	ASSERT(session);
429da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
430da6c28aaSamw 
431da6c28aaSamw 	smb_llist_enter(&session->s_user_list, RW_READER);
432da6c28aaSamw 	user = smb_llist_head(&session->s_user_list);
433da6c28aaSamw 	while (user) {
434da6c28aaSamw 		ASSERT(user->u_magic == SMB_USER_MAGIC);
435da6c28aaSamw 		ASSERT(user->u_session == session);
436da6c28aaSamw 		if (user->u_uid == uid) {
437da6c28aaSamw 			mutex_enter(&user->u_mutex);
438da6c28aaSamw 			switch (user->u_state) {
439da6c28aaSamw 
440da6c28aaSamw 			case SMB_USER_STATE_LOGGED_IN:
441da6c28aaSamw 				/* The user exists and is still logged in. */
442da6c28aaSamw 				user->u_refcnt++;
443da6c28aaSamw 				mutex_exit(&user->u_mutex);
444da6c28aaSamw 				smb_llist_exit(&session->s_user_list);
445da6c28aaSamw 				return (user);
446da6c28aaSamw 
447da6c28aaSamw 			case SMB_USER_STATE_LOGGING_OFF:
448da6c28aaSamw 			case SMB_USER_STATE_LOGGED_OFF:
449da6c28aaSamw 				/*
450da6c28aaSamw 				 * The user exists but has logged off or is in
451da6c28aaSamw 				 * the process of logging off.
452da6c28aaSamw 				 */
453da6c28aaSamw 				mutex_exit(&user->u_mutex);
454da6c28aaSamw 				smb_llist_exit(&session->s_user_list);
455da6c28aaSamw 				return (NULL);
456da6c28aaSamw 
457da6c28aaSamw 			default:
458da6c28aaSamw 				ASSERT(0);
459da6c28aaSamw 				mutex_exit(&user->u_mutex);
460da6c28aaSamw 				smb_llist_exit(&session->s_user_list);
461da6c28aaSamw 				return (NULL);
462da6c28aaSamw 			}
463da6c28aaSamw 		}
464da6c28aaSamw 		user = smb_llist_next(&session->s_user_list, user);
465da6c28aaSamw 	}
466da6c28aaSamw 	smb_llist_exit(&session->s_user_list);
467da6c28aaSamw 	return (NULL);
468da6c28aaSamw }
469da6c28aaSamw 
470da6c28aaSamw /*
471da6c28aaSamw  * smb_user_lookup_by_state
472da6c28aaSamw  *
473da6c28aaSamw  * This function returns the first user in the logged in state. If the user
474da6c28aaSamw  * provided is NULL the search starts from the beginning of the list passed
475da6c28aaSamw  * in. It a user is provided the search starts just after that user.
476da6c28aaSamw  */
477da6c28aaSamw smb_user_t *
478da6c28aaSamw smb_user_lookup_by_state(
479da6c28aaSamw     smb_session_t	*session,
480da6c28aaSamw     smb_user_t		*user)
481da6c28aaSamw {
482da6c28aaSamw 	smb_llist_t	*lst;
483da6c28aaSamw 	smb_user_t	*next;
484da6c28aaSamw 
485da6c28aaSamw 	ASSERT(session);
486da6c28aaSamw 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
487da6c28aaSamw 
488da6c28aaSamw 	lst = &session->s_user_list;
489da6c28aaSamw 
490da6c28aaSamw 	smb_llist_enter(lst, RW_READER);
491da6c28aaSamw 	if (user) {
492da6c28aaSamw 		ASSERT(user);
493da6c28aaSamw 		ASSERT(user->u_magic == SMB_USER_MAGIC);
494da6c28aaSamw 		ASSERT(user->u_refcnt);
495da6c28aaSamw 		next = smb_llist_next(lst, user);
496da6c28aaSamw 	} else {
497da6c28aaSamw 		next = smb_llist_head(lst);
498da6c28aaSamw 	}
499da6c28aaSamw 	while (next) {
500da6c28aaSamw 		ASSERT(next->u_magic == SMB_USER_MAGIC);
501da6c28aaSamw 		ASSERT(next->u_session == session);
502da6c28aaSamw 		mutex_enter(&next->u_mutex);
503da6c28aaSamw 		if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
504da6c28aaSamw 			next->u_refcnt++;
505da6c28aaSamw 			mutex_exit(&next->u_mutex);
506da6c28aaSamw 			break;
507da6c28aaSamw 		} else {
508da6c28aaSamw 			ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
509da6c28aaSamw 			    (next->u_state == SMB_USER_STATE_LOGGED_OFF));
510da6c28aaSamw 			mutex_exit(&next->u_mutex);
511da6c28aaSamw 			next = smb_llist_next(lst, next);
512da6c28aaSamw 		}
513da6c28aaSamw 	}
514da6c28aaSamw 	smb_llist_exit(lst);
515da6c28aaSamw 
516da6c28aaSamw 	return (next);
517da6c28aaSamw }
518da6c28aaSamw 
519da6c28aaSamw /*
520c8ec8eeaSjose borrego  * Find a tree by tree-id.
521da6c28aaSamw  */
522c8ec8eeaSjose borrego smb_tree_t *
523c8ec8eeaSjose borrego smb_user_lookup_tree(
524da6c28aaSamw     smb_user_t		*user,
525c8ec8eeaSjose borrego     uint16_t		tid)
526c8ec8eeaSjose borrego 
527da6c28aaSamw {
528da6c28aaSamw 	smb_tree_t	*tree;
529da6c28aaSamw 
530da6c28aaSamw 	ASSERT(user);
531da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
532da6c28aaSamw 
533c8ec8eeaSjose borrego 	smb_llist_enter(&user->u_tree_list, RW_READER);
534c8ec8eeaSjose borrego 	tree = smb_llist_head(&user->u_tree_list);
535c8ec8eeaSjose borrego 
536da6c28aaSamw 	while (tree) {
537da6c28aaSamw 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
538c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
539c8ec8eeaSjose borrego 
540c8ec8eeaSjose borrego 		if (tree->t_tid == tid) {
541c8ec8eeaSjose borrego 			if (smb_tree_hold(tree)) {
542c8ec8eeaSjose borrego 				smb_llist_exit(&user->u_tree_list);
543c8ec8eeaSjose borrego 				return (tree);
544c8ec8eeaSjose borrego 			} else {
545c8ec8eeaSjose borrego 				smb_llist_exit(&user->u_tree_list);
546c8ec8eeaSjose borrego 				return (NULL);
547c8ec8eeaSjose borrego 			}
548c8ec8eeaSjose borrego 		}
549c8ec8eeaSjose borrego 
550c8ec8eeaSjose borrego 		tree = smb_llist_next(&user->u_tree_list, tree);
551c8ec8eeaSjose borrego 	}
552c8ec8eeaSjose borrego 
553c8ec8eeaSjose borrego 	smb_llist_exit(&user->u_tree_list);
554c8ec8eeaSjose borrego 	return (NULL);
555c8ec8eeaSjose borrego }
556c8ec8eeaSjose borrego 
557c8ec8eeaSjose borrego /*
558c8ec8eeaSjose borrego  * Find the first connected tree that matches the specified sharename.
559c8ec8eeaSjose borrego  * If the specified tree is NULL the search starts from the beginning of
560c8ec8eeaSjose borrego  * the user's tree list.  If a tree is provided the search starts just
561c8ec8eeaSjose borrego  * after that tree.
562c8ec8eeaSjose borrego  */
563c8ec8eeaSjose borrego smb_tree_t *
564c8ec8eeaSjose borrego smb_user_lookup_share(
565c8ec8eeaSjose borrego     smb_user_t		*user,
566c8ec8eeaSjose borrego     const char		*sharename,
567c8ec8eeaSjose borrego     smb_tree_t		*tree)
568c8ec8eeaSjose borrego {
569c8ec8eeaSjose borrego 	ASSERT(user);
570c8ec8eeaSjose borrego 	ASSERT(user->u_magic == SMB_USER_MAGIC);
571c8ec8eeaSjose borrego 	ASSERT(sharename);
572c8ec8eeaSjose borrego 
573c8ec8eeaSjose borrego 	smb_llist_enter(&user->u_tree_list, RW_READER);
574c8ec8eeaSjose borrego 
575c8ec8eeaSjose borrego 	if (tree) {
576c8ec8eeaSjose borrego 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
577c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
578c8ec8eeaSjose borrego 		tree = smb_llist_next(&user->u_tree_list, tree);
579c8ec8eeaSjose borrego 	} else {
580c8ec8eeaSjose borrego 		tree = smb_llist_head(&user->u_tree_list);
581c8ec8eeaSjose borrego 	}
582c8ec8eeaSjose borrego 
583c8ec8eeaSjose borrego 	while (tree) {
584c8ec8eeaSjose borrego 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
585c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
586c8ec8eeaSjose borrego 		if (utf8_strcasecmp(tree->t_sharename, sharename) == 0) {
587c8ec8eeaSjose borrego 			if (smb_tree_hold(tree)) {
588c8ec8eeaSjose borrego 				smb_llist_exit(&user->u_tree_list);
589c8ec8eeaSjose borrego 				return (tree);
590c8ec8eeaSjose borrego 			}
591c8ec8eeaSjose borrego 		}
592c8ec8eeaSjose borrego 		tree = smb_llist_next(&user->u_tree_list, tree);
593c8ec8eeaSjose borrego 	}
594c8ec8eeaSjose borrego 
595c8ec8eeaSjose borrego 	smb_llist_exit(&user->u_tree_list);
596c8ec8eeaSjose borrego 	return (NULL);
597c8ec8eeaSjose borrego }
598c8ec8eeaSjose borrego 
599c8ec8eeaSjose borrego /*
600c8ec8eeaSjose borrego  * Find the first connected tree that matches the specified volume name.
601c8ec8eeaSjose borrego  * If the specified tree is NULL the search starts from the beginning of
602c8ec8eeaSjose borrego  * the user's tree list.  If a tree is provided the search starts just
603c8ec8eeaSjose borrego  * after that tree.
604c8ec8eeaSjose borrego  */
605c8ec8eeaSjose borrego smb_tree_t *
606c8ec8eeaSjose borrego smb_user_lookup_volume(
607c8ec8eeaSjose borrego     smb_user_t		*user,
608c8ec8eeaSjose borrego     const char		*name,
609c8ec8eeaSjose borrego     smb_tree_t		*tree)
610c8ec8eeaSjose borrego {
611c8ec8eeaSjose borrego 	ASSERT(user);
612c8ec8eeaSjose borrego 	ASSERT(user->u_magic == SMB_USER_MAGIC);
613c8ec8eeaSjose borrego 	ASSERT(name);
614c8ec8eeaSjose borrego 
615c8ec8eeaSjose borrego 	smb_llist_enter(&user->u_tree_list, RW_READER);
616c8ec8eeaSjose borrego 
617c8ec8eeaSjose borrego 	if (tree) {
618c8ec8eeaSjose borrego 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
619c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
620c8ec8eeaSjose borrego 		tree = smb_llist_next(&user->u_tree_list, tree);
621c8ec8eeaSjose borrego 	} else {
622c8ec8eeaSjose borrego 		tree = smb_llist_head(&user->u_tree_list);
623c8ec8eeaSjose borrego 	}
624c8ec8eeaSjose borrego 
625c8ec8eeaSjose borrego 	while (tree) {
626c8ec8eeaSjose borrego 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
627c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
628c8ec8eeaSjose borrego 
629c8ec8eeaSjose borrego 		if (utf8_strcasecmp(tree->t_volume, name) == 0) {
630c8ec8eeaSjose borrego 			if (smb_tree_hold(tree)) {
631c8ec8eeaSjose borrego 				smb_llist_exit(&user->u_tree_list);
632c8ec8eeaSjose borrego 				return (tree);
633c8ec8eeaSjose borrego 			}
634c8ec8eeaSjose borrego 		}
635c8ec8eeaSjose borrego 
636c8ec8eeaSjose borrego 		tree = smb_llist_next(&user->u_tree_list, tree);
637c8ec8eeaSjose borrego 	}
638c8ec8eeaSjose borrego 
639c8ec8eeaSjose borrego 	smb_llist_exit(&user->u_tree_list);
640c8ec8eeaSjose borrego 	return (NULL);
641c8ec8eeaSjose borrego }
642c8ec8eeaSjose borrego 
643c8ec8eeaSjose borrego /*
644c8ec8eeaSjose borrego  * Disconnect all trees that match the specified client process-id.
645c8ec8eeaSjose borrego  */
646c8ec8eeaSjose borrego void
647c8ec8eeaSjose borrego smb_user_close_pid(
648c8ec8eeaSjose borrego     smb_user_t		*user,
649c8ec8eeaSjose borrego     uint16_t		pid)
650c8ec8eeaSjose borrego {
651c8ec8eeaSjose borrego 	smb_tree_t	*tree;
652c8ec8eeaSjose borrego 
653c8ec8eeaSjose borrego 	ASSERT(user);
654c8ec8eeaSjose borrego 	ASSERT(user->u_magic == SMB_USER_MAGIC);
655c8ec8eeaSjose borrego 
656c8ec8eeaSjose borrego 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
657c8ec8eeaSjose borrego 	while (tree) {
658c8ec8eeaSjose borrego 		smb_tree_t *next;
659c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
660c8ec8eeaSjose borrego 		smb_tree_close_pid(tree, pid);
661c8ec8eeaSjose borrego 		next = smb_user_get_tree(&user->u_tree_list, tree);
662da6c28aaSamw 		smb_tree_release(tree);
663da6c28aaSamw 		tree = next;
664da6c28aaSamw 	}
665da6c28aaSamw }
666da6c28aaSamw 
667da6c28aaSamw /*
668c8ec8eeaSjose borrego  * Disconnect all trees that this user has connected.
669da6c28aaSamw  */
670da6c28aaSamw void
671c8ec8eeaSjose borrego smb_user_disconnect_trees(
672c8ec8eeaSjose borrego     smb_user_t		*user)
673c8ec8eeaSjose borrego {
674c8ec8eeaSjose borrego 	smb_tree_t	*tree;
675c8ec8eeaSjose borrego 
676c8ec8eeaSjose borrego 	ASSERT(user);
677c8ec8eeaSjose borrego 	ASSERT(user->u_magic == SMB_USER_MAGIC);
678c8ec8eeaSjose borrego 
679c8ec8eeaSjose borrego 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
680c8ec8eeaSjose borrego 	while (tree) {
681c8ec8eeaSjose borrego 		ASSERT(tree->t_user == user);
682c8ec8eeaSjose borrego 		smb_tree_disconnect(tree);
683c8ec8eeaSjose borrego 		smb_tree_release(tree);
684c8ec8eeaSjose borrego 		tree = smb_user_get_tree(&user->u_tree_list, NULL);
685c8ec8eeaSjose borrego 	}
686c8ec8eeaSjose borrego }
687c8ec8eeaSjose borrego 
688c8ec8eeaSjose borrego /*
689c8ec8eeaSjose borrego  * Disconnect all trees that match the specified share name.
690c8ec8eeaSjose borrego  */
691c8ec8eeaSjose borrego void
692c8ec8eeaSjose borrego smb_user_disconnect_share(
693da6c28aaSamw     smb_user_t		*user,
694c8ec8eeaSjose borrego     const char		*sharename)
695da6c28aaSamw {
696da6c28aaSamw 	smb_tree_t	*tree;
697da6c28aaSamw 	smb_tree_t	*next;
698da6c28aaSamw 
699da6c28aaSamw 	ASSERT(user);
700da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
701da6c28aaSamw 	ASSERT(user->u_refcnt);
702da6c28aaSamw 
703c8ec8eeaSjose borrego 	tree = smb_user_lookup_share(user, sharename, NULL);
704da6c28aaSamw 	while (tree) {
705da6c28aaSamw 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
706c8ec8eeaSjose borrego 		smb_session_cancel_requests(user->u_session, tree, NULL);
707da6c28aaSamw 		smb_tree_disconnect(tree);
708c8ec8eeaSjose borrego 		next = smb_user_lookup_share(user, sharename, tree);
709da6c28aaSamw 		smb_tree_release(tree);
710da6c28aaSamw 		tree = next;
711da6c28aaSamw 	}
712da6c28aaSamw }
713da6c28aaSamw 
714c8ec8eeaSjose borrego /*
715c8ec8eeaSjose borrego  * Determine whether or not the user is an administrator.
716c8ec8eeaSjose borrego  * Members of the administrators group have administrative rights.
717c8ec8eeaSjose borrego  */
718c8ec8eeaSjose borrego boolean_t
719c8ec8eeaSjose borrego smb_user_is_admin(
720c8ec8eeaSjose borrego     smb_user_t		*user)
721c8ec8eeaSjose borrego {
722c8ec8eeaSjose borrego 	cred_t		*u_cred;
723c8ec8eeaSjose borrego 
724c8ec8eeaSjose borrego 	ASSERT(user);
725c8ec8eeaSjose borrego 	u_cred = user->u_cred;
726c8ec8eeaSjose borrego 	ASSERT(u_cred);
727c8ec8eeaSjose borrego 
728c8ec8eeaSjose borrego 	if (smb_admins_sid == NULL)
729c8ec8eeaSjose borrego 		return (B_FALSE);
730c8ec8eeaSjose borrego 
731c8ec8eeaSjose borrego 	if (smb_cred_is_member(u_cred, smb_admins_sid))
732c8ec8eeaSjose borrego 		return (B_TRUE);
733c8ec8eeaSjose borrego 
734c8ec8eeaSjose borrego 	return (B_FALSE);
735c8ec8eeaSjose borrego }
736c8ec8eeaSjose borrego 
737da6c28aaSamw /* *************************** Static Functions ***************************** */
738da6c28aaSamw 
739da6c28aaSamw /*
740da6c28aaSamw  * smb_user_delete
741da6c28aaSamw  */
742da6c28aaSamw static void
743da6c28aaSamw smb_user_delete(
744da6c28aaSamw     smb_user_t		*user)
745da6c28aaSamw {
746da6c28aaSamw 	smb_session_t	*session;
747da6c28aaSamw 
748da6c28aaSamw 	ASSERT(user);
749da6c28aaSamw 	ASSERT(user->u_magic == SMB_USER_MAGIC);
750da6c28aaSamw 	ASSERT(user->u_refcnt == 0);
751da6c28aaSamw 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
752da6c28aaSamw 
753da6c28aaSamw 	session = user->u_session;
754da6c28aaSamw 	/*
755da6c28aaSamw 	 * Let's remove the user from the list of users of the session. This
756da6c28aaSamw 	 * has to be done before any resources associated with the user are
757da6c28aaSamw 	 * deleted.
758da6c28aaSamw 	 */
759da6c28aaSamw 	smb_llist_enter(&session->s_user_list, RW_WRITER);
760da6c28aaSamw 	smb_llist_remove(&session->s_user_list, user);
761da6c28aaSamw 	smb_llist_exit(&session->s_user_list);
762da6c28aaSamw 
763da6c28aaSamw 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
764da6c28aaSamw 	mutex_destroy(&user->u_mutex);
765da6c28aaSamw 	smb_llist_destructor(&user->u_tree_list);
766da6c28aaSamw 	smb_idpool_destructor(&user->u_tid_pool);
767da6c28aaSamw 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
768da6c28aaSamw 	crfree(user->u_cred);
769*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (user->u_privcred)
770*b89a8333Snatalie li - Sun Microsystems - Irvine United States 		crfree(user->u_privcred);
771da6c28aaSamw 	kmem_free(user->u_name, (size_t)user->u_name_len);
772da6c28aaSamw 	kmem_free(user->u_domain, (size_t)user->u_domain_len);
773faa1795aSjb150015 	kmem_cache_free(user->u_server->si_cache_user, user);
774da6c28aaSamw }
775c8ec8eeaSjose borrego 
776c8ec8eeaSjose borrego /*
777c8ec8eeaSjose borrego  * Get the next connected tree in the list.  A reference is taken on
778c8ec8eeaSjose borrego  * the tree, which can be released later with smb_tree_release().
779c8ec8eeaSjose borrego  *
780c8ec8eeaSjose borrego  * If the specified tree is NULL the search starts from the beginning of
781c8ec8eeaSjose borrego  * the tree list.  If a tree is provided the search starts just after
782c8ec8eeaSjose borrego  * that tree.
783c8ec8eeaSjose borrego  *
784c8ec8eeaSjose borrego  * Returns NULL if there are no connected trees in the list.
785c8ec8eeaSjose borrego  */
786c8ec8eeaSjose borrego static smb_tree_t *
787c8ec8eeaSjose borrego smb_user_get_tree(
788c8ec8eeaSjose borrego     smb_llist_t		*tree_list,
789c8ec8eeaSjose borrego     smb_tree_t		*tree)
790c8ec8eeaSjose borrego {
791c8ec8eeaSjose borrego 	ASSERT(tree_list);
792c8ec8eeaSjose borrego 
793c8ec8eeaSjose borrego 	smb_llist_enter(tree_list, RW_READER);
794c8ec8eeaSjose borrego 
795c8ec8eeaSjose borrego 	if (tree) {
796c8ec8eeaSjose borrego 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
797c8ec8eeaSjose borrego 		tree = smb_llist_next(tree_list, tree);
798c8ec8eeaSjose borrego 	} else {
799c8ec8eeaSjose borrego 		tree = smb_llist_head(tree_list);
800c8ec8eeaSjose borrego 	}
801c8ec8eeaSjose borrego 
802c8ec8eeaSjose borrego 	while (tree) {
803c8ec8eeaSjose borrego 		if (smb_tree_hold(tree))
804c8ec8eeaSjose borrego 			break;
805c8ec8eeaSjose borrego 
806c8ec8eeaSjose borrego 		tree = smb_llist_next(tree_list, tree);
807c8ec8eeaSjose borrego 	}
808c8ec8eeaSjose borrego 
809c8ec8eeaSjose borrego 	smb_llist_exit(tree_list);
810c8ec8eeaSjose borrego 	return (tree);
811c8ec8eeaSjose borrego }
812*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
813*b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
814*b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getcred(smb_user_t *user)
815*b89a8333Snatalie li - Sun Microsystems - Irvine United States {
816*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (user->u_cred);
817*b89a8333Snatalie li - Sun Microsystems - Irvine United States }
818*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
819*b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
820*b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getprivcred(smb_user_t *user)
821*b89a8333Snatalie li - Sun Microsystems - Irvine United States {
822*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
823*b89a8333Snatalie li - Sun Microsystems - Irvine United States }
824