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