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