xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_user.c (revision 91760536453132b0d3369ad5543622a5478007e6)
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_privcred = smb_cred_create_privs(cr, privileges);
235 	user->u_audit_sid = audit_sid;
236 
237 	if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
238 		if (!smb_idpool_constructor(&user->u_tid_pool)) {
239 			smb_llist_constructor(&user->u_tree_list,
240 			    sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
241 			mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
242 			crhold(user->u_cred);
243 			if (user->u_privcred)
244 				crhold(user->u_privcred);
245 			user->u_state = SMB_USER_STATE_LOGGED_IN;
246 			user->u_magic = SMB_USER_MAGIC;
247 			smb_llist_enter(&session->s_user_list, RW_WRITER);
248 			smb_llist_insert_tail(&session->s_user_list, user);
249 			smb_llist_exit(&session->s_user_list);
250 			atomic_inc_32(&session->s_server->sv_open_users);
251 			return (user);
252 		}
253 		smb_idpool_free(&session->s_uid_pool, user->u_uid);
254 	}
255 	kmem_free(user->u_name, (size_t)user->u_name_len);
256 	kmem_free(user->u_domain, (size_t)user->u_domain_len);
257 	kmem_cache_free(session->s_server->si_cache_user, user);
258 	return (NULL);
259 }
260 
261 /*
262  * Create a new user based on an existing user, used to support
263  * additional SessionSetupX requests for a user on a session.
264  *
265  * Assumes the caller has a reference on the original user from
266  * a user_lookup_by_x call.
267  */
268 smb_user_t *
269 smb_user_dup(
270     smb_user_t		*orig_user)
271 {
272 	smb_user_t	*user;
273 
274 	ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
275 	ASSERT(orig_user->u_refcnt);
276 
277 	user = smb_user_login(orig_user->u_session, orig_user->u_cred,
278 	    orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
279 	    orig_user->u_privileges, orig_user->u_audit_sid);
280 
281 	if (user)
282 		smb_user_nonauth_logon(orig_user->u_audit_sid);
283 
284 	return (user);
285 }
286 
287 /*
288  * smb_user_logoff
289  *
290  *
291  */
292 void
293 smb_user_logoff(
294     smb_user_t		*user)
295 {
296 	ASSERT(user->u_magic == SMB_USER_MAGIC);
297 
298 	mutex_enter(&user->u_mutex);
299 	ASSERT(user->u_refcnt);
300 	switch (user->u_state) {
301 	case SMB_USER_STATE_LOGGED_IN: {
302 		/*
303 		 * The user is moved into a state indicating that the log off
304 		 * process has started.
305 		 */
306 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
307 		mutex_exit(&user->u_mutex);
308 		atomic_dec_32(&user->u_server->sv_open_users);
309 		/*
310 		 * All the trees hanging off of this user are disconnected.
311 		 */
312 		smb_user_disconnect_trees(user);
313 		smb_user_auth_logoff(user->u_audit_sid);
314 		mutex_enter(&user->u_mutex);
315 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
316 		break;
317 	}
318 	case SMB_USER_STATE_LOGGED_OFF:
319 	case SMB_USER_STATE_LOGGING_OFF:
320 		break;
321 
322 	default:
323 		ASSERT(0);
324 		break;
325 	}
326 	mutex_exit(&user->u_mutex);
327 }
328 
329 /*
330  * smb_user_logoff_all
331  *
332  *
333  */
334 void
335 smb_user_logoff_all(
336     smb_session_t	*session)
337 {
338 	smb_user_t	*user;
339 
340 	ASSERT(session);
341 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
342 
343 	smb_llist_enter(&session->s_user_list, RW_READER);
344 	user = smb_llist_head(&session->s_user_list);
345 	while (user) {
346 		ASSERT(user->u_magic == SMB_USER_MAGIC);
347 		ASSERT(user->u_session == session);
348 		mutex_enter(&user->u_mutex);
349 		switch (user->u_state) {
350 		case SMB_USER_STATE_LOGGED_IN:
351 			/* The user is still logged in. */
352 			user->u_refcnt++;
353 			mutex_exit(&user->u_mutex);
354 			smb_llist_exit(&session->s_user_list);
355 			smb_user_logoff(user);
356 			smb_user_release(user);
357 			smb_llist_enter(&session->s_user_list, RW_READER);
358 			user = smb_llist_head(&session->s_user_list);
359 			break;
360 		case SMB_USER_STATE_LOGGING_OFF:
361 		case SMB_USER_STATE_LOGGED_OFF:
362 			/*
363 			 * The user is logged off or logging off.
364 			 */
365 			mutex_exit(&user->u_mutex);
366 			user = smb_llist_next(&session->s_user_list, user);
367 			break;
368 		default:
369 			ASSERT(0);
370 			mutex_exit(&user->u_mutex);
371 			user = smb_llist_next(&session->s_user_list, user);
372 			break;
373 		}
374 	}
375 	smb_llist_exit(&session->s_user_list);
376 }
377 
378 /*
379  * smb_user_release
380  *
381  *
382  */
383 void
384 smb_user_release(
385     smb_user_t		*user)
386 {
387 	ASSERT(user->u_magic == SMB_USER_MAGIC);
388 
389 	mutex_enter(&user->u_mutex);
390 	ASSERT(user->u_refcnt);
391 	user->u_refcnt--;
392 	switch (user->u_state) {
393 	case SMB_USER_STATE_LOGGED_OFF:
394 		if (user->u_refcnt == 0) {
395 			mutex_exit(&user->u_mutex);
396 			smb_user_delete(user);
397 			return;
398 		}
399 		break;
400 
401 	case SMB_USER_STATE_LOGGED_IN:
402 	case SMB_USER_STATE_LOGGING_OFF:
403 		break;
404 
405 	default:
406 		ASSERT(0);
407 		break;
408 	}
409 	mutex_exit(&user->u_mutex);
410 }
411 
412 /*
413  * smb_user_lookup_by_uid
414  *
415  * Find the appropriate user for this request. The request credentials
416  * set here may be overridden by the tree credentials. In domain mode,
417  * the user and tree credentials should be the same. In share mode, the
418  * tree credentials (defined in the share definition) should override
419  * the user credentials.
420  */
421 smb_user_t *
422 smb_user_lookup_by_uid(
423     smb_session_t	*session,
424     uint16_t		uid)
425 {
426 	smb_user_t	*user;
427 
428 	ASSERT(session);
429 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
430 
431 	smb_llist_enter(&session->s_user_list, RW_READER);
432 	user = smb_llist_head(&session->s_user_list);
433 	while (user) {
434 		ASSERT(user->u_magic == SMB_USER_MAGIC);
435 		ASSERT(user->u_session == session);
436 		if (user->u_uid == uid) {
437 			mutex_enter(&user->u_mutex);
438 			switch (user->u_state) {
439 
440 			case SMB_USER_STATE_LOGGED_IN:
441 				/* The user exists and is still logged in. */
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_state
472  *
473  * This function returns the first user in the logged in state. If the user
474  * provided is NULL the search starts from the beginning of the list passed
475  * in. It a user is provided the search starts just after that user.
476  */
477 smb_user_t *
478 smb_user_lookup_by_state(
479     smb_session_t	*session,
480     smb_user_t		*user)
481 {
482 	smb_llist_t	*lst;
483 	smb_user_t	*next;
484 
485 	ASSERT(session);
486 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
487 
488 	lst = &session->s_user_list;
489 
490 	smb_llist_enter(lst, RW_READER);
491 	if (user) {
492 		ASSERT(user);
493 		ASSERT(user->u_magic == SMB_USER_MAGIC);
494 		ASSERT(user->u_refcnt);
495 		next = smb_llist_next(lst, user);
496 	} else {
497 		next = smb_llist_head(lst);
498 	}
499 	while (next) {
500 		ASSERT(next->u_magic == SMB_USER_MAGIC);
501 		ASSERT(next->u_session == session);
502 		mutex_enter(&next->u_mutex);
503 		if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
504 			next->u_refcnt++;
505 			mutex_exit(&next->u_mutex);
506 			break;
507 		} else {
508 			ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
509 			    (next->u_state == SMB_USER_STATE_LOGGED_OFF));
510 			mutex_exit(&next->u_mutex);
511 			next = smb_llist_next(lst, next);
512 		}
513 	}
514 	smb_llist_exit(lst);
515 
516 	return (next);
517 }
518 
519 /*
520  * Find a tree by tree-id.
521  */
522 smb_tree_t *
523 smb_user_lookup_tree(
524     smb_user_t		*user,
525     uint16_t		tid)
526 
527 {
528 	smb_tree_t	*tree;
529 
530 	ASSERT(user);
531 	ASSERT(user->u_magic == SMB_USER_MAGIC);
532 
533 	smb_llist_enter(&user->u_tree_list, RW_READER);
534 	tree = smb_llist_head(&user->u_tree_list);
535 
536 	while (tree) {
537 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
538 		ASSERT(tree->t_user == user);
539 
540 		if (tree->t_tid == tid) {
541 			if (smb_tree_hold(tree)) {
542 				smb_llist_exit(&user->u_tree_list);
543 				return (tree);
544 			} else {
545 				smb_llist_exit(&user->u_tree_list);
546 				return (NULL);
547 			}
548 		}
549 
550 		tree = smb_llist_next(&user->u_tree_list, tree);
551 	}
552 
553 	smb_llist_exit(&user->u_tree_list);
554 	return (NULL);
555 }
556 
557 /*
558  * Find the first connected tree that matches the specified sharename.
559  * If the specified tree is NULL the search starts from the beginning of
560  * the user's tree list.  If a tree is provided the search starts just
561  * after that tree.
562  */
563 smb_tree_t *
564 smb_user_lookup_share(
565     smb_user_t		*user,
566     const char		*sharename,
567     smb_tree_t		*tree)
568 {
569 	ASSERT(user);
570 	ASSERT(user->u_magic == SMB_USER_MAGIC);
571 	ASSERT(sharename);
572 
573 	smb_llist_enter(&user->u_tree_list, RW_READER);
574 
575 	if (tree) {
576 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
577 		ASSERT(tree->t_user == user);
578 		tree = smb_llist_next(&user->u_tree_list, tree);
579 	} else {
580 		tree = smb_llist_head(&user->u_tree_list);
581 	}
582 
583 	while (tree) {
584 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
585 		ASSERT(tree->t_user == user);
586 		if (utf8_strcasecmp(tree->t_sharename, sharename) == 0) {
587 			if (smb_tree_hold(tree)) {
588 				smb_llist_exit(&user->u_tree_list);
589 				return (tree);
590 			}
591 		}
592 		tree = smb_llist_next(&user->u_tree_list, tree);
593 	}
594 
595 	smb_llist_exit(&user->u_tree_list);
596 	return (NULL);
597 }
598 
599 /*
600  * Find the first connected tree that matches the specified volume name.
601  * If the specified tree is NULL the search starts from the beginning of
602  * the user's tree list.  If a tree is provided the search starts just
603  * after that tree.
604  */
605 smb_tree_t *
606 smb_user_lookup_volume(
607     smb_user_t		*user,
608     const char		*name,
609     smb_tree_t		*tree)
610 {
611 	ASSERT(user);
612 	ASSERT(user->u_magic == SMB_USER_MAGIC);
613 	ASSERT(name);
614 
615 	smb_llist_enter(&user->u_tree_list, RW_READER);
616 
617 	if (tree) {
618 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
619 		ASSERT(tree->t_user == user);
620 		tree = smb_llist_next(&user->u_tree_list, tree);
621 	} else {
622 		tree = smb_llist_head(&user->u_tree_list);
623 	}
624 
625 	while (tree) {
626 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
627 		ASSERT(tree->t_user == user);
628 
629 		if (utf8_strcasecmp(tree->t_volume, name) == 0) {
630 			if (smb_tree_hold(tree)) {
631 				smb_llist_exit(&user->u_tree_list);
632 				return (tree);
633 			}
634 		}
635 
636 		tree = smb_llist_next(&user->u_tree_list, tree);
637 	}
638 
639 	smb_llist_exit(&user->u_tree_list);
640 	return (NULL);
641 }
642 
643 /*
644  * Disconnect all trees that match the specified client process-id.
645  */
646 void
647 smb_user_close_pid(
648     smb_user_t		*user,
649     uint16_t		pid)
650 {
651 	smb_tree_t	*tree;
652 
653 	ASSERT(user);
654 	ASSERT(user->u_magic == SMB_USER_MAGIC);
655 
656 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
657 	while (tree) {
658 		smb_tree_t *next;
659 		ASSERT(tree->t_user == user);
660 		smb_tree_close_pid(tree, pid);
661 		next = smb_user_get_tree(&user->u_tree_list, tree);
662 		smb_tree_release(tree);
663 		tree = next;
664 	}
665 }
666 
667 /*
668  * Disconnect all trees that this user has connected.
669  */
670 void
671 smb_user_disconnect_trees(
672     smb_user_t		*user)
673 {
674 	smb_tree_t	*tree;
675 
676 	ASSERT(user);
677 	ASSERT(user->u_magic == SMB_USER_MAGIC);
678 
679 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
680 	while (tree) {
681 		ASSERT(tree->t_user == user);
682 		smb_tree_disconnect(tree);
683 		smb_tree_release(tree);
684 		tree = smb_user_get_tree(&user->u_tree_list, NULL);
685 	}
686 }
687 
688 /*
689  * Disconnect all trees that match the specified share name.
690  */
691 void
692 smb_user_disconnect_share(
693     smb_user_t		*user,
694     const char		*sharename)
695 {
696 	smb_tree_t	*tree;
697 	smb_tree_t	*next;
698 
699 	ASSERT(user);
700 	ASSERT(user->u_magic == SMB_USER_MAGIC);
701 	ASSERT(user->u_refcnt);
702 
703 	tree = smb_user_lookup_share(user, sharename, NULL);
704 	while (tree) {
705 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
706 		smb_session_cancel_requests(user->u_session, tree, NULL);
707 		smb_tree_disconnect(tree);
708 		next = smb_user_lookup_share(user, sharename, tree);
709 		smb_tree_release(tree);
710 		tree = next;
711 	}
712 }
713 
714 /*
715  * Determine whether or not the user is an administrator.
716  * Members of the administrators group have administrative rights.
717  */
718 boolean_t
719 smb_user_is_admin(
720     smb_user_t		*user)
721 {
722 	cred_t		*u_cred;
723 
724 	ASSERT(user);
725 	u_cred = user->u_cred;
726 	ASSERT(u_cred);
727 
728 	if (smb_admins_sid == NULL)
729 		return (B_FALSE);
730 
731 	if (smb_cred_is_member(u_cred, smb_admins_sid))
732 		return (B_TRUE);
733 
734 	return (B_FALSE);
735 }
736 
737 /* *************************** Static Functions ***************************** */
738 
739 /*
740  * smb_user_delete
741  */
742 static void
743 smb_user_delete(
744     smb_user_t		*user)
745 {
746 	smb_session_t	*session;
747 
748 	ASSERT(user);
749 	ASSERT(user->u_magic == SMB_USER_MAGIC);
750 	ASSERT(user->u_refcnt == 0);
751 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
752 
753 	session = user->u_session;
754 	/*
755 	 * Let's remove the user from the list of users of the session. This
756 	 * has to be done before any resources associated with the user are
757 	 * deleted.
758 	 */
759 	smb_llist_enter(&session->s_user_list, RW_WRITER);
760 	smb_llist_remove(&session->s_user_list, user);
761 	smb_llist_exit(&session->s_user_list);
762 
763 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
764 	mutex_destroy(&user->u_mutex);
765 	smb_llist_destructor(&user->u_tree_list);
766 	smb_idpool_destructor(&user->u_tid_pool);
767 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
768 	crfree(user->u_cred);
769 	if (user->u_privcred)
770 		crfree(user->u_privcred);
771 	kmem_free(user->u_name, (size_t)user->u_name_len);
772 	kmem_free(user->u_domain, (size_t)user->u_domain_len);
773 	kmem_cache_free(user->u_server->si_cache_user, user);
774 }
775 
776 /*
777  * Get the next connected tree in the list.  A reference is taken on
778  * the tree, which can be released later with smb_tree_release().
779  *
780  * If the specified tree is NULL the search starts from the beginning of
781  * the tree list.  If a tree is provided the search starts just after
782  * that tree.
783  *
784  * Returns NULL if there are no connected trees in the list.
785  */
786 static smb_tree_t *
787 smb_user_get_tree(
788     smb_llist_t		*tree_list,
789     smb_tree_t		*tree)
790 {
791 	ASSERT(tree_list);
792 
793 	smb_llist_enter(tree_list, RW_READER);
794 
795 	if (tree) {
796 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
797 		tree = smb_llist_next(tree_list, tree);
798 	} else {
799 		tree = smb_llist_head(tree_list);
800 	}
801 
802 	while (tree) {
803 		if (smb_tree_hold(tree))
804 			break;
805 
806 		tree = smb_llist_next(tree_list, tree);
807 	}
808 
809 	smb_llist_exit(tree_list);
810 	return (tree);
811 }
812 
813 cred_t *
814 smb_user_getcred(smb_user_t *user)
815 {
816 	return (user->u_cred);
817 }
818 
819 cred_t *
820 smb_user_getprivcred(smb_user_t *user)
821 {
822 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
823 }
824