xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_user.c (revision c586600796766c83eb9485c446886fd9ed2359a9)
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * General Structures Layout
27  * -------------------------
28  *
29  * This is a simplified diagram showing the relationship between most of the
30  * main structures.
31  *
32  * +-------------------+
33  * |     SMB_INFO      |
34  * +-------------------+
35  *          |
36  *          |
37  *          v
38  * +-------------------+       +-------------------+      +-------------------+
39  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
40  * +-------------------+       +-------------------+      +-------------------+
41  *          |
42  *          |
43  *          v
44  * +-------------------+       +-------------------+      +-------------------+
45  * |       USER        |<----->|       USER        |......|       USER        |
46  * +-------------------+       +-------------------+      +-------------------+
47  *          |
48  *          |
49  *          v
50  * +-------------------+       +-------------------+      +-------------------+
51  * |       TREE        |<----->|       TREE        |......|       TREE        |
52  * +-------------------+       +-------------------+      +-------------------+
53  *      |         |
54  *      |         |
55  *      |         v
56  *      |     +-------+       +-------+      +-------+
57  *      |     | OFILE |<----->| OFILE |......| OFILE |
58  *      |     +-------+       +-------+      +-------+
59  *      |
60  *      |
61  *      v
62  *  +-------+       +------+      +------+
63  *  | ODIR  |<----->| ODIR |......| ODIR |
64  *  +-------+       +------+      +------+
65  *
66  *
67  * User State Machine
68  * ------------------
69  *
70  *    +-----------------------------+	 T0
71  *    |  SMB_USER_STATE_LOGGED_IN   |<----------- Creation/Allocation
72  *    +-----------------------------+
73  *		    |
74  *		    | T1
75  *		    |
76  *		    v
77  *    +-----------------------------+
78  *    |  SMB_USER_STATE_LOGGING_OFF |
79  *    +-----------------------------+
80  *		    |
81  *		    | T2
82  *		    |
83  *		    v
84  *    +-----------------------------+    T3
85  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
86  *    +-----------------------------+
87  *
88  * SMB_USER_STATE_LOGGED_IN
89  *
90  *    While in this state:
91  *      - The user is queued in the list of users of his session.
92  *      - References will be given out if the user is looked up.
93  *      - The user can access files and pipes.
94  *
95  * SMB_USER_STATE_LOGGING_OFF
96  *
97  *    While in this state:
98  *      - The user is queued in the list of users of his session.
99  *      - References will not be given out if the user is looked up.
100  *      - The trees the user connected are being disconnected.
101  *      - The resources associated with the user remain.
102  *
103  * SMB_USER_STATE_LOGGING_OFF
104  *
105  *    While in this state:
106  *      - The user is queued in the list of users of his session.
107  *      - References will not be given out if the user is looked up.
108  *      - The user has no more trees connected.
109  *      - The resources associated with the user remain.
110  *
111  * Transition T0
112  *
113  *    This transition occurs in smb_user_login(). A new user is created and
114  *    added to the list of users of a session.
115  *
116  * Transition T1
117  *
118  *    This transition occurs in smb_user_logoff().
119  *
120  * Transition T2
121  *
122  *    This transition occurs in smb_user_release(). The resources associated
123  *    with the user are deleted as well as the user. For the transition to
124  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
125  *    reference count be zero.
126  *
127  * Comments
128  * --------
129  *
130  *    The state machine of the user structures is controlled by 3 elements:
131  *      - The list of users of the session he belongs to.
132  *      - The mutex embedded in the structure itself.
133  *      - The reference count.
134  *
135  *    There's a mutex embedded in the user structure used to protect its fields
136  *    and there's a lock embedded in the list of users of a session. To
137  *    increment or to decrement the reference count the mutex must be entered.
138  *    To insert the user into the list of users of the session and to remove
139  *    the user from it, the lock must be entered in RW_WRITER mode.
140  *
141  *    Rules of access to a user structure:
142  *
143  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
144  *       list) have to be entered, the lock must be entered first.
145  *
146  *    2) All actions applied to a user require a reference count.
147  *
148  *    3) There are 2 ways of getting a reference count. One is when the user
149  *       logs in. The other when the user is looked up.
150  *
151  *    It should be noted that the reference count of a user registers the
152  *    number of references to the user in other structures (such as an smb
153  *    request). The reference count is not incremented in these 2 instances:
154  *
155  *    1) The user is logged in. An user is anchored by his state. If there's
156  *       no activity involving a user currently logged in, the reference
157  *       count of that user is zero.
158  *
159  *    2) The user is queued in the list of users of the session. The fact of
160  *       being queued in that list is NOT registered by incrementing the
161  *       reference count.
162  */
163 #include <smbsrv/smb_kproto.h>
164 #include <smbsrv/smb_door.h>
165 
166 
167 #define	ADMINISTRATORS_SID	"S-1-5-32-544"
168 
169 static smb_sid_t *smb_admins_sid = NULL;
170 
171 static boolean_t smb_user_is_logged_in(smb_user_t *);
172 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
173 static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *);
174 static void smb_user_nonauth_logon(uint32_t);
175 static void smb_user_auth_logoff(uint32_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_mem_strdup(account_name);
232 	user->u_domain = smb_mem_strdup(domain_name);
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 	smb_mem_free(user->u_name);
256 	smb_mem_free(user->u_domain);
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  * Change the user state and disconnect trees.
291  * The user list must not be entered or modified here.
292  */
293 void
294 smb_user_logoff(
295     smb_user_t		*user)
296 {
297 	ASSERT(user->u_magic == SMB_USER_MAGIC);
298 
299 	mutex_enter(&user->u_mutex);
300 	ASSERT(user->u_refcnt);
301 	switch (user->u_state) {
302 	case SMB_USER_STATE_LOGGED_IN: {
303 		/*
304 		 * The user is moved into a state indicating that the log off
305 		 * process has started.
306 		 */
307 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
308 		mutex_exit(&user->u_mutex);
309 		atomic_dec_32(&user->u_server->sv_open_users);
310 		/*
311 		 * All the trees hanging off of this user are disconnected.
312 		 */
313 		smb_user_disconnect_trees(user);
314 		smb_user_auth_logoff(user->u_audit_sid);
315 		mutex_enter(&user->u_mutex);
316 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
317 		break;
318 	}
319 	case SMB_USER_STATE_LOGGED_OFF:
320 	case SMB_USER_STATE_LOGGING_OFF:
321 		break;
322 
323 	default:
324 		ASSERT(0);
325 		break;
326 	}
327 	mutex_exit(&user->u_mutex);
328 }
329 
330 /*
331  * Take a reference on a user.
332  */
333 boolean_t
334 smb_user_hold(smb_user_t *user)
335 {
336 	ASSERT(user);
337 	ASSERT(user->u_magic == SMB_USER_MAGIC);
338 
339 	mutex_enter(&user->u_mutex);
340 
341 	if (smb_user_is_logged_in(user)) {
342 		user->u_refcnt++;
343 		mutex_exit(&user->u_mutex);
344 		return (B_TRUE);
345 	}
346 
347 	mutex_exit(&user->u_mutex);
348 	return (B_FALSE);
349 }
350 
351 /*
352  * Release a reference on a user.  If the reference count falls to
353  * zero and the user has logged off, post the object for deletion.
354  * Object deletion is deferred to avoid modifying a list while an
355  * iteration may be in progress.
356  */
357 void
358 smb_user_release(
359     smb_user_t		*user)
360 {
361 	ASSERT(user->u_magic == SMB_USER_MAGIC);
362 
363 	mutex_enter(&user->u_mutex);
364 	ASSERT(user->u_refcnt);
365 	user->u_refcnt--;
366 
367 	/* flush the tree list's delete queue */
368 	smb_llist_flush(&user->u_tree_list);
369 
370 	switch (user->u_state) {
371 	case SMB_USER_STATE_LOGGED_OFF:
372 		if (user->u_refcnt == 0)
373 			smb_session_post_user(user->u_session, user);
374 		break;
375 
376 	case SMB_USER_STATE_LOGGED_IN:
377 	case SMB_USER_STATE_LOGGING_OFF:
378 		break;
379 
380 	default:
381 		ASSERT(0);
382 		break;
383 	}
384 	mutex_exit(&user->u_mutex);
385 }
386 
387 void
388 smb_user_post_tree(smb_user_t *user, smb_tree_t *tree)
389 {
390 	SMB_USER_VALID(user);
391 	SMB_TREE_VALID(tree);
392 	ASSERT(tree->t_refcnt == 0);
393 	ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
394 	ASSERT(tree->t_user == user);
395 
396 	smb_llist_post(&user->u_tree_list, tree, smb_tree_dealloc);
397 }
398 
399 
400 /*
401  * Find a tree by tree-id.
402  */
403 smb_tree_t *
404 smb_user_lookup_tree(
405     smb_user_t		*user,
406     uint16_t		tid)
407 
408 {
409 	smb_tree_t	*tree;
410 
411 	ASSERT(user);
412 	ASSERT(user->u_magic == SMB_USER_MAGIC);
413 
414 	smb_llist_enter(&user->u_tree_list, RW_READER);
415 	tree = smb_llist_head(&user->u_tree_list);
416 
417 	while (tree) {
418 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
419 		ASSERT(tree->t_user == user);
420 
421 		if (tree->t_tid == tid) {
422 			if (smb_tree_hold(tree)) {
423 				smb_llist_exit(&user->u_tree_list);
424 				return (tree);
425 			} else {
426 				smb_llist_exit(&user->u_tree_list);
427 				return (NULL);
428 			}
429 		}
430 
431 		tree = smb_llist_next(&user->u_tree_list, tree);
432 	}
433 
434 	smb_llist_exit(&user->u_tree_list);
435 	return (NULL);
436 }
437 
438 /*
439  * Find the first connected tree that matches the specified sharename.
440  * If the specified tree is NULL the search starts from the beginning of
441  * the user's tree list.  If a tree is provided the search starts just
442  * after that tree.
443  */
444 smb_tree_t *
445 smb_user_lookup_share(
446     smb_user_t		*user,
447     const char		*sharename,
448     smb_tree_t		*tree)
449 {
450 	ASSERT(user);
451 	ASSERT(user->u_magic == SMB_USER_MAGIC);
452 	ASSERT(sharename);
453 
454 	smb_llist_enter(&user->u_tree_list, RW_READER);
455 
456 	if (tree) {
457 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
458 		ASSERT(tree->t_user == user);
459 		tree = smb_llist_next(&user->u_tree_list, tree);
460 	} else {
461 		tree = smb_llist_head(&user->u_tree_list);
462 	}
463 
464 	while (tree) {
465 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
466 		ASSERT(tree->t_user == user);
467 		if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
468 			if (smb_tree_hold(tree)) {
469 				smb_llist_exit(&user->u_tree_list);
470 				return (tree);
471 			}
472 		}
473 		tree = smb_llist_next(&user->u_tree_list, tree);
474 	}
475 
476 	smb_llist_exit(&user->u_tree_list);
477 	return (NULL);
478 }
479 
480 /*
481  * Find the first connected tree that matches the specified volume name.
482  * If the specified tree is NULL the search starts from the beginning of
483  * the user's tree list.  If a tree is provided the search starts just
484  * after that tree.
485  */
486 smb_tree_t *
487 smb_user_lookup_volume(
488     smb_user_t		*user,
489     const char		*name,
490     smb_tree_t		*tree)
491 {
492 	ASSERT(user);
493 	ASSERT(user->u_magic == SMB_USER_MAGIC);
494 	ASSERT(name);
495 
496 	smb_llist_enter(&user->u_tree_list, RW_READER);
497 
498 	if (tree) {
499 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
500 		ASSERT(tree->t_user == user);
501 		tree = smb_llist_next(&user->u_tree_list, tree);
502 	} else {
503 		tree = smb_llist_head(&user->u_tree_list);
504 	}
505 
506 	while (tree) {
507 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
508 		ASSERT(tree->t_user == user);
509 
510 		if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
511 			if (smb_tree_hold(tree)) {
512 				smb_llist_exit(&user->u_tree_list);
513 				return (tree);
514 			}
515 		}
516 
517 		tree = smb_llist_next(&user->u_tree_list, tree);
518 	}
519 
520 	smb_llist_exit(&user->u_tree_list);
521 	return (NULL);
522 }
523 
524 /*
525  * Disconnect all trees that match the specified client process-id.
526  */
527 void
528 smb_user_close_pid(
529     smb_user_t		*user,
530     uint16_t		pid)
531 {
532 	smb_tree_t	*tree;
533 
534 	ASSERT(user);
535 	ASSERT(user->u_magic == SMB_USER_MAGIC);
536 
537 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
538 	while (tree) {
539 		smb_tree_t *next;
540 		ASSERT(tree->t_user == user);
541 		smb_tree_close_pid(tree, pid);
542 		next = smb_user_get_tree(&user->u_tree_list, tree);
543 		smb_tree_release(tree);
544 		tree = next;
545 	}
546 }
547 
548 /*
549  * Disconnect all trees that this user has connected.
550  */
551 void
552 smb_user_disconnect_trees(
553     smb_user_t		*user)
554 {
555 	smb_tree_t	*tree;
556 
557 	ASSERT(user);
558 	ASSERT(user->u_magic == SMB_USER_MAGIC);
559 
560 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
561 	while (tree) {
562 		ASSERT(tree->t_user == user);
563 		smb_tree_disconnect(tree, B_TRUE);
564 		smb_tree_release(tree);
565 		tree = smb_user_get_tree(&user->u_tree_list, NULL);
566 	}
567 }
568 
569 /*
570  * Disconnect all trees that match the specified share name.
571  */
572 void
573 smb_user_disconnect_share(
574     smb_user_t		*user,
575     const char		*sharename)
576 {
577 	smb_tree_t	*tree;
578 	smb_tree_t	*next;
579 
580 	ASSERT(user);
581 	ASSERT(user->u_magic == SMB_USER_MAGIC);
582 	ASSERT(user->u_refcnt);
583 
584 	tree = smb_user_lookup_share(user, sharename, NULL);
585 	while (tree) {
586 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
587 		smb_session_cancel_requests(user->u_session, tree, NULL);
588 		smb_tree_disconnect(tree, B_TRUE);
589 		next = smb_user_lookup_share(user, sharename, tree);
590 		smb_tree_release(tree);
591 		tree = next;
592 	}
593 }
594 
595 /*
596  * Close a file by its unique id.
597  */
598 int
599 smb_user_fclose(smb_user_t *user, uint32_t uniqid)
600 {
601 	smb_llist_t	*tree_list;
602 	smb_tree_t	*tree;
603 	int		rc = ENOENT;
604 
605 	ASSERT(user);
606 	ASSERT(user->u_magic == SMB_USER_MAGIC);
607 
608 	tree_list = &user->u_tree_list;
609 	ASSERT(tree_list);
610 
611 	smb_llist_enter(tree_list, RW_READER);
612 	tree = smb_llist_head(tree_list);
613 
614 	while ((tree != NULL) && (rc == ENOENT)) {
615 		ASSERT(tree->t_user == user);
616 
617 		if (smb_tree_hold(tree)) {
618 			rc = smb_tree_fclose(tree, uniqid);
619 			smb_tree_release(tree);
620 		}
621 
622 		tree = smb_llist_next(tree_list, tree);
623 	}
624 
625 	smb_llist_exit(tree_list);
626 	return (rc);
627 }
628 
629 /*
630  * Determine whether or not the user is an administrator.
631  * Members of the administrators group have administrative rights.
632  */
633 boolean_t
634 smb_user_is_admin(
635     smb_user_t		*user)
636 {
637 	cred_t		*u_cred;
638 
639 	ASSERT(user);
640 	u_cred = user->u_cred;
641 	ASSERT(u_cred);
642 
643 	if (smb_admins_sid == NULL)
644 		return (B_FALSE);
645 
646 	if (smb_cred_is_member(u_cred, smb_admins_sid))
647 		return (B_TRUE);
648 
649 	return (B_FALSE);
650 }
651 
652 /*
653  * This function should be called with a hold on the user.
654  */
655 boolean_t
656 smb_user_namecmp(smb_user_t *user, const char *name)
657 {
658 	char		*fq_name;
659 	boolean_t	match;
660 
661 	if (smb_strcasecmp(name, user->u_name, 0) == 0)
662 		return (B_TRUE);
663 
664 	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
665 
666 	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
667 	    user->u_domain, user->u_name);
668 
669 	match = (smb_strcasecmp(name, fq_name, 0) == 0);
670 	if (!match) {
671 		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
672 		    user->u_name, user->u_domain);
673 
674 		match = (smb_strcasecmp(name, fq_name, 0) == 0);
675 	}
676 
677 	kmem_free(fq_name, MAXNAMELEN);
678 	return (match);
679 }
680 
681 /*
682  * If the enumeration request is for user data, handle the request
683  * here.  Otherwise, pass it on to the trees.
684  *
685  * This function should be called with a hold on the user.
686  */
687 int
688 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
689 {
690 	smb_tree_t	*tree;
691 	smb_tree_t	*next;
692 	int		rc;
693 
694 	ASSERT(user);
695 	ASSERT(user->u_magic == SMB_USER_MAGIC);
696 
697 	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
698 		return (smb_user_enum_private(user, svcenum));
699 
700 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
701 	while (tree) {
702 		ASSERT(tree->t_user == user);
703 
704 		rc = smb_tree_enum(tree, svcenum);
705 		if (rc != 0) {
706 			smb_tree_release(tree);
707 			break;
708 		}
709 
710 		next = smb_user_get_tree(&user->u_tree_list, tree);
711 		smb_tree_release(tree);
712 		tree = next;
713 	}
714 
715 	return (rc);
716 }
717 
718 /* *************************** Static Functions ***************************** */
719 
720 /*
721  * Determine whether or not a user is logged in.
722  * Typically, a reference can only be taken on a logged-in user.
723  *
724  * This is a private function and must be called with the user
725  * mutex held.
726  */
727 static boolean_t
728 smb_user_is_logged_in(smb_user_t *user)
729 {
730 	switch (user->u_state) {
731 	case SMB_USER_STATE_LOGGED_IN:
732 		return (B_TRUE);
733 
734 	case SMB_USER_STATE_LOGGING_OFF:
735 	case SMB_USER_STATE_LOGGED_OFF:
736 		return (B_FALSE);
737 
738 	default:
739 		ASSERT(0);
740 		return (B_FALSE);
741 	}
742 }
743 
744 /*
745  * Delete a user.  The tree list should be empty.
746  *
747  * Remove the user from the session's user list before freeing resources
748  * associated with the user.
749  */
750 void
751 smb_user_delete(void *arg)
752 {
753 	smb_session_t	*session;
754 	smb_user_t	*user = (smb_user_t *)arg;
755 
756 	SMB_USER_VALID(user);
757 	ASSERT(user->u_refcnt == 0);
758 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
759 
760 	session = user->u_session;
761 	smb_llist_enter(&session->s_user_list, RW_WRITER);
762 	smb_llist_remove(&session->s_user_list, user);
763 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
764 	smb_llist_exit(&session->s_user_list);
765 
766 	mutex_enter(&user->u_mutex);
767 	mutex_exit(&user->u_mutex);
768 
769 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
770 	mutex_destroy(&user->u_mutex);
771 	smb_llist_destructor(&user->u_tree_list);
772 	smb_idpool_destructor(&user->u_tid_pool);
773 	crfree(user->u_cred);
774 	if (user->u_privcred)
775 		crfree(user->u_privcred);
776 	smb_mem_free(user->u_name);
777 	smb_mem_free(user->u_domain);
778 	kmem_cache_free(user->u_server->si_cache_user, user);
779 }
780 
781 /*
782  * Get the next connected tree in the list.  A reference is taken on
783  * the tree, which can be released later with smb_tree_release().
784  *
785  * If the specified tree is NULL the search starts from the beginning of
786  * the tree list.  If a tree is provided the search starts just after
787  * that tree.
788  *
789  * Returns NULL if there are no connected trees in the list.
790  */
791 static smb_tree_t *
792 smb_user_get_tree(
793     smb_llist_t		*tree_list,
794     smb_tree_t		*tree)
795 {
796 	ASSERT(tree_list);
797 
798 	smb_llist_enter(tree_list, RW_READER);
799 
800 	if (tree) {
801 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
802 		tree = smb_llist_next(tree_list, tree);
803 	} else {
804 		tree = smb_llist_head(tree_list);
805 	}
806 
807 	while (tree) {
808 		if (smb_tree_hold(tree))
809 			break;
810 
811 		tree = smb_llist_next(tree_list, tree);
812 	}
813 
814 	smb_llist_exit(tree_list);
815 	return (tree);
816 }
817 
818 cred_t *
819 smb_user_getcred(smb_user_t *user)
820 {
821 	return (user->u_cred);
822 }
823 
824 cred_t *
825 smb_user_getprivcred(smb_user_t *user)
826 {
827 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
828 }
829 
830 /*
831  * Private function to support smb_user_enum.
832  */
833 static int
834 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
835 {
836 	uint8_t *pb;
837 	uint_t nbytes;
838 	int rc;
839 
840 	if (svcenum->se_nskip > 0) {
841 		svcenum->se_nskip--;
842 		return (0);
843 	}
844 
845 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
846 		svcenum->se_nitems = svcenum->se_nlimit;
847 		return (0);
848 	}
849 
850 	pb = &svcenum->se_buf[svcenum->se_bused];
851 	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
852 	if (rc == 0) {
853 		svcenum->se_bavail -= nbytes;
854 		svcenum->se_bused += nbytes;
855 		svcenum->se_nitems++;
856 	}
857 
858 	return (rc);
859 }
860 
861 /*
862  * Encode the NetInfo for a user into a buffer.  NetInfo contains
863  * information that is often needed in user space to support RPC
864  * requests.
865  */
866 int
867 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
868     uint32_t *nbytes)
869 {
870 	smb_netuserinfo_t	info;
871 	int			rc;
872 
873 	smb_user_netinfo_init(user, &info);
874 	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
875 	smb_user_netinfo_fini(&info);
876 
877 	return (rc);
878 }
879 
880 void
881 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
882 {
883 	smb_session_t	*session;
884 	char		*buf;
885 
886 	ASSERT(user);
887 	ASSERT(user->u_domain);
888 	ASSERT(user->u_name);
889 
890 	session = user->u_session;
891 	ASSERT(session);
892 	ASSERT(session->workstation);
893 
894 	info->ui_session_id = session->s_kid;
895 	info->ui_native_os = session->native_os;
896 	info->ui_ipaddr = session->ipaddr;
897 	info->ui_numopens = session->s_file_cnt;
898 	info->ui_smb_uid = user->u_uid;
899 	info->ui_logon_time = user->u_logon_time;
900 	info->ui_flags = user->u_flags;
901 	info->ui_posix_uid = crgetuid(user->u_cred);
902 
903 	info->ui_domain_len = user->u_domain_len;
904 	info->ui_domain = smb_mem_strdup(user->u_domain);
905 
906 	info->ui_account_len = user->u_name_len;
907 	info->ui_account = smb_mem_strdup(user->u_name);
908 
909 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
910 	smb_session_getclient(session, buf, MAXNAMELEN);
911 	info->ui_workstation_len = strlen(buf) + 1;
912 	info->ui_workstation = smb_mem_strdup(buf);
913 	kmem_free(buf, MAXNAMELEN);
914 }
915 
916 void
917 smb_user_netinfo_fini(smb_netuserinfo_t *info)
918 {
919 	if (info == NULL)
920 		return;
921 
922 	if (info->ui_domain)
923 		smb_mem_free(info->ui_domain);
924 	if (info->ui_account)
925 		smb_mem_free(info->ui_account);
926 	if (info->ui_workstation)
927 		smb_mem_free(info->ui_workstation);
928 
929 	bzero(info, sizeof (smb_netuserinfo_t));
930 }
931 
932 static void
933 smb_user_nonauth_logon(uint32_t audit_sid)
934 {
935 	(void) smb_kdoor_upcall(SMB_DR_USER_NONAUTH_LOGON,
936 	    &audit_sid, xdr_uint32_t, NULL, NULL);
937 }
938 
939 static void
940 smb_user_auth_logoff(uint32_t audit_sid)
941 {
942 	(void) smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGOFF,
943 	    &audit_sid, xdr_uint32_t, NULL, NULL);
944 }
945 
946 smb_token_t *
947 smb_get_token(smb_logon_t *user_info)
948 {
949 	smb_token_t	*token;
950 	int		rc;
951 
952 	token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
953 
954 	rc = smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGON,
955 	    user_info, smb_logon_xdr, token, smb_token_xdr);
956 
957 	if (rc != 0) {
958 		kmem_free(token, sizeof (smb_token_t));
959 		return (NULL);
960 	}
961 
962 	if (!smb_token_valid(token)) {
963 		smb_token_free(token);
964 		return (NULL);
965 	}
966 
967 	return (token);
968 }
969