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 <sys/types.h>
164 #include <sys/sid.h>
165 #include <sys/priv_names.h>
166 #include <smbsrv/smb_kproto.h>
167 #include <smbsrv/smb_door.h>
168
169 #define ADMINISTRATORS_SID "S-1-5-32-544"
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_setcred(smb_user_t *, cred_t *, uint32_t);
175 static void smb_user_nonauth_logon(uint32_t);
176 static void smb_user_auth_logoff(uint32_t);
177
178 /*
179 * Create a new user.
180 */
181 smb_user_t *
smb_user_login(smb_session_t * session,cred_t * cr,char * domain_name,char * account_name,uint32_t flags,uint32_t privileges,uint32_t audit_sid)182 smb_user_login(
183 smb_session_t *session,
184 cred_t *cr,
185 char *domain_name,
186 char *account_name,
187 uint32_t flags,
188 uint32_t privileges,
189 uint32_t audit_sid)
190 {
191 smb_user_t *user;
192
193 ASSERT(session);
194 ASSERT(session->s_magic == SMB_SESSION_MAGIC);
195 ASSERT(cr);
196 ASSERT(account_name);
197 ASSERT(domain_name);
198
199 user = kmem_cache_alloc(session->s_server->si_cache_user, KM_SLEEP);
200 bzero(user, sizeof (smb_user_t));
201 user->u_refcnt = 1;
202 user->u_session = session;
203 user->u_server = session->s_server;
204 user->u_logon_time = gethrestime_sec();
205 user->u_flags = flags;
206 user->u_name_len = strlen(account_name) + 1;
207 user->u_domain_len = strlen(domain_name) + 1;
208 user->u_name = smb_mem_strdup(account_name);
209 user->u_domain = smb_mem_strdup(domain_name);
210 user->u_audit_sid = audit_sid;
211
212 if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
213 if (!smb_idpool_constructor(&user->u_tid_pool)) {
214 smb_llist_constructor(&user->u_tree_list,
215 sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
216 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
217 smb_user_setcred(user, cr, privileges);
218 user->u_state = SMB_USER_STATE_LOGGED_IN;
219 user->u_magic = SMB_USER_MAGIC;
220 smb_llist_enter(&session->s_user_list, RW_WRITER);
221 smb_llist_insert_tail(&session->s_user_list, user);
222 smb_llist_exit(&session->s_user_list);
223 smb_server_inc_users(session->s_server);
224 return (user);
225 }
226 smb_idpool_free(&session->s_uid_pool, user->u_uid);
227 }
228 smb_mem_free(user->u_name);
229 smb_mem_free(user->u_domain);
230 kmem_cache_free(session->s_server->si_cache_user, user);
231 return (NULL);
232 }
233
234 /*
235 * Create a new user based on an existing user, used to support
236 * additional SessionSetupX requests for a user on a session.
237 *
238 * Assumes the caller has a reference on the original user from
239 * a user_lookup_by_x call.
240 */
241 smb_user_t *
smb_user_dup(smb_user_t * orig_user)242 smb_user_dup(
243 smb_user_t *orig_user)
244 {
245 smb_user_t *user;
246
247 ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
248 ASSERT(orig_user->u_refcnt);
249
250 user = smb_user_login(orig_user->u_session, orig_user->u_cred,
251 orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
252 orig_user->u_privileges, orig_user->u_audit_sid);
253
254 if (user)
255 smb_user_nonauth_logon(orig_user->u_audit_sid);
256
257 return (user);
258 }
259
260 /*
261 * smb_user_logoff
262 *
263 * Change the user state and disconnect trees.
264 * The user list must not be entered or modified here.
265 */
266 void
smb_user_logoff(smb_user_t * user)267 smb_user_logoff(
268 smb_user_t *user)
269 {
270 ASSERT(user->u_magic == SMB_USER_MAGIC);
271
272 mutex_enter(&user->u_mutex);
273 ASSERT(user->u_refcnt);
274 switch (user->u_state) {
275 case SMB_USER_STATE_LOGGED_IN: {
276 /*
277 * The user is moved into a state indicating that the log off
278 * process has started.
279 */
280 user->u_state = SMB_USER_STATE_LOGGING_OFF;
281 mutex_exit(&user->u_mutex);
282 /*
283 * All the trees hanging off of this user are disconnected.
284 */
285 smb_user_disconnect_trees(user);
286 smb_user_auth_logoff(user->u_audit_sid);
287 mutex_enter(&user->u_mutex);
288 user->u_state = SMB_USER_STATE_LOGGED_OFF;
289 smb_server_dec_users(user->u_server);
290 break;
291 }
292 case SMB_USER_STATE_LOGGED_OFF:
293 case SMB_USER_STATE_LOGGING_OFF:
294 break;
295
296 default:
297 ASSERT(0);
298 break;
299 }
300 mutex_exit(&user->u_mutex);
301 }
302
303 /*
304 * Take a reference on a user.
305 */
306 boolean_t
smb_user_hold(smb_user_t * user)307 smb_user_hold(smb_user_t *user)
308 {
309 ASSERT(user);
310 ASSERT(user->u_magic == SMB_USER_MAGIC);
311
312 mutex_enter(&user->u_mutex);
313
314 if (smb_user_is_logged_in(user)) {
315 user->u_refcnt++;
316 mutex_exit(&user->u_mutex);
317 return (B_TRUE);
318 }
319
320 mutex_exit(&user->u_mutex);
321 return (B_FALSE);
322 }
323
324 /*
325 * Release a reference on a user. If the reference count falls to
326 * zero and the user has logged off, post the object for deletion.
327 * Object deletion is deferred to avoid modifying a list while an
328 * iteration may be in progress.
329 */
330 void
smb_user_release(smb_user_t * user)331 smb_user_release(
332 smb_user_t *user)
333 {
334 ASSERT(user->u_magic == SMB_USER_MAGIC);
335
336 mutex_enter(&user->u_mutex);
337 ASSERT(user->u_refcnt);
338 user->u_refcnt--;
339
340 /* flush the tree list's delete queue */
341 smb_llist_flush(&user->u_tree_list);
342
343 switch (user->u_state) {
344 case SMB_USER_STATE_LOGGED_OFF:
345 if (user->u_refcnt == 0)
346 smb_session_post_user(user->u_session, user);
347 break;
348
349 case SMB_USER_STATE_LOGGED_IN:
350 case SMB_USER_STATE_LOGGING_OFF:
351 break;
352
353 default:
354 ASSERT(0);
355 break;
356 }
357 mutex_exit(&user->u_mutex);
358 }
359
360 void
smb_user_post_tree(smb_user_t * user,smb_tree_t * tree)361 smb_user_post_tree(smb_user_t *user, smb_tree_t *tree)
362 {
363 SMB_USER_VALID(user);
364 SMB_TREE_VALID(tree);
365 ASSERT(tree->t_refcnt == 0);
366 ASSERT(tree->t_state == SMB_TREE_STATE_DISCONNECTED);
367 ASSERT(tree->t_user == user);
368
369 smb_llist_post(&user->u_tree_list, tree, smb_tree_dealloc);
370 }
371
372
373 /*
374 * Find a tree by tree-id.
375 */
376 smb_tree_t *
smb_user_lookup_tree(smb_user_t * user,uint16_t tid)377 smb_user_lookup_tree(
378 smb_user_t *user,
379 uint16_t tid)
380
381 {
382 smb_tree_t *tree;
383
384 ASSERT(user);
385 ASSERT(user->u_magic == SMB_USER_MAGIC);
386
387 smb_llist_enter(&user->u_tree_list, RW_READER);
388 tree = smb_llist_head(&user->u_tree_list);
389
390 while (tree) {
391 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
392 ASSERT(tree->t_user == user);
393
394 if (tree->t_tid == tid) {
395 if (smb_tree_hold(tree)) {
396 smb_llist_exit(&user->u_tree_list);
397 return (tree);
398 } else {
399 smb_llist_exit(&user->u_tree_list);
400 return (NULL);
401 }
402 }
403
404 tree = smb_llist_next(&user->u_tree_list, tree);
405 }
406
407 smb_llist_exit(&user->u_tree_list);
408 return (NULL);
409 }
410
411 /*
412 * Find the first connected tree that matches the specified sharename.
413 * If the specified tree is NULL the search starts from the beginning of
414 * the user's tree list. If a tree is provided the search starts just
415 * after that tree.
416 */
417 smb_tree_t *
smb_user_lookup_share(smb_user_t * user,const char * sharename,smb_tree_t * tree)418 smb_user_lookup_share(
419 smb_user_t *user,
420 const char *sharename,
421 smb_tree_t *tree)
422 {
423 ASSERT(user);
424 ASSERT(user->u_magic == SMB_USER_MAGIC);
425 ASSERT(sharename);
426
427 smb_llist_enter(&user->u_tree_list, RW_READER);
428
429 if (tree) {
430 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
431 ASSERT(tree->t_user == user);
432 tree = smb_llist_next(&user->u_tree_list, tree);
433 } else {
434 tree = smb_llist_head(&user->u_tree_list);
435 }
436
437 while (tree) {
438 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
439 ASSERT(tree->t_user == user);
440 if (smb_strcasecmp(tree->t_sharename, sharename, 0) == 0) {
441 if (smb_tree_hold(tree)) {
442 smb_llist_exit(&user->u_tree_list);
443 return (tree);
444 }
445 }
446 tree = smb_llist_next(&user->u_tree_list, tree);
447 }
448
449 smb_llist_exit(&user->u_tree_list);
450 return (NULL);
451 }
452
453 /*
454 * Find the first connected tree that matches the specified volume name.
455 * If the specified tree is NULL the search starts from the beginning of
456 * the user's tree list. If a tree is provided the search starts just
457 * after that tree.
458 */
459 smb_tree_t *
smb_user_lookup_volume(smb_user_t * user,const char * name,smb_tree_t * tree)460 smb_user_lookup_volume(
461 smb_user_t *user,
462 const char *name,
463 smb_tree_t *tree)
464 {
465 ASSERT(user);
466 ASSERT(user->u_magic == SMB_USER_MAGIC);
467 ASSERT(name);
468
469 smb_llist_enter(&user->u_tree_list, RW_READER);
470
471 if (tree) {
472 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
473 ASSERT(tree->t_user == user);
474 tree = smb_llist_next(&user->u_tree_list, tree);
475 } else {
476 tree = smb_llist_head(&user->u_tree_list);
477 }
478
479 while (tree) {
480 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
481 ASSERT(tree->t_user == user);
482
483 if (smb_strcasecmp(tree->t_volume, name, 0) == 0) {
484 if (smb_tree_hold(tree)) {
485 smb_llist_exit(&user->u_tree_list);
486 return (tree);
487 }
488 }
489
490 tree = smb_llist_next(&user->u_tree_list, tree);
491 }
492
493 smb_llist_exit(&user->u_tree_list);
494 return (NULL);
495 }
496
497 /*
498 * Disconnect all trees that match the specified client process-id.
499 */
500 void
smb_user_close_pid(smb_user_t * user,uint16_t pid)501 smb_user_close_pid(
502 smb_user_t *user,
503 uint16_t pid)
504 {
505 smb_tree_t *tree;
506
507 ASSERT(user);
508 ASSERT(user->u_magic == SMB_USER_MAGIC);
509
510 tree = smb_user_get_tree(&user->u_tree_list, NULL);
511 while (tree) {
512 smb_tree_t *next;
513 ASSERT(tree->t_user == user);
514 smb_tree_close_pid(tree, pid);
515 next = smb_user_get_tree(&user->u_tree_list, tree);
516 smb_tree_release(tree);
517 tree = next;
518 }
519 }
520
521 /*
522 * Disconnect all trees that this user has connected.
523 */
524 void
smb_user_disconnect_trees(smb_user_t * user)525 smb_user_disconnect_trees(
526 smb_user_t *user)
527 {
528 smb_tree_t *tree;
529
530 ASSERT(user);
531 ASSERT(user->u_magic == SMB_USER_MAGIC);
532
533 tree = smb_user_get_tree(&user->u_tree_list, NULL);
534 while (tree) {
535 ASSERT(tree->t_user == user);
536 smb_tree_disconnect(tree, B_TRUE);
537 smb_tree_release(tree);
538 tree = smb_user_get_tree(&user->u_tree_list, NULL);
539 }
540 }
541
542 /*
543 * Disconnect all trees that match the specified share name.
544 */
545 void
smb_user_disconnect_share(smb_user_t * user,const char * sharename)546 smb_user_disconnect_share(
547 smb_user_t *user,
548 const char *sharename)
549 {
550 smb_tree_t *tree;
551 smb_tree_t *next;
552
553 ASSERT(user);
554 ASSERT(user->u_magic == SMB_USER_MAGIC);
555 ASSERT(user->u_refcnt);
556
557 tree = smb_user_lookup_share(user, sharename, NULL);
558 while (tree) {
559 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
560 smb_session_cancel_requests(user->u_session, tree, NULL);
561 smb_tree_disconnect(tree, B_TRUE);
562 next = smb_user_lookup_share(user, sharename, tree);
563 smb_tree_release(tree);
564 tree = next;
565 }
566 }
567
568 /*
569 * Close a file by its unique id.
570 */
571 int
smb_user_fclose(smb_user_t * user,uint32_t uniqid)572 smb_user_fclose(smb_user_t *user, uint32_t uniqid)
573 {
574 smb_llist_t *tree_list;
575 smb_tree_t *tree;
576 int rc = ENOENT;
577
578 ASSERT(user);
579 ASSERT(user->u_magic == SMB_USER_MAGIC);
580
581 tree_list = &user->u_tree_list;
582 ASSERT(tree_list);
583
584 smb_llist_enter(tree_list, RW_READER);
585 tree = smb_llist_head(tree_list);
586
587 while ((tree != NULL) && (rc == ENOENT)) {
588 ASSERT(tree->t_user == user);
589
590 if (smb_tree_hold(tree)) {
591 rc = smb_tree_fclose(tree, uniqid);
592 smb_tree_release(tree);
593 }
594
595 tree = smb_llist_next(tree_list, tree);
596 }
597
598 smb_llist_exit(tree_list);
599 return (rc);
600 }
601
602 /*
603 * Determine whether or not the user is an administrator.
604 * Members of the administrators group have administrative rights.
605 */
606 boolean_t
smb_user_is_admin(smb_user_t * user)607 smb_user_is_admin(smb_user_t *user)
608 {
609 char sidstr[SMB_SID_STRSZ];
610 ksidlist_t *ksidlist;
611 ksid_t ksid1;
612 ksid_t *ksid2;
613 boolean_t rc = B_FALSE;
614 int i;
615
616 ASSERT(user);
617 ASSERT(user->u_cred);
618
619 if (SMB_USER_IS_ADMIN(user))
620 return (B_TRUE);
621
622 bzero(&ksid1, sizeof (ksid_t));
623 (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
624 ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
625 ksid1.ks_domain = ksid_lookupdomain(sidstr);
626
627 ksidlist = crgetsidlist(user->u_cred);
628 ASSERT(ksidlist);
629 ASSERT(ksid1.ks_domain);
630 ASSERT(ksid1.ks_domain->kd_name);
631
632 i = 0;
633 ksid2 = crgetsid(user->u_cred, KSID_USER);
634 do {
635 ASSERT(ksid2->ks_domain);
636 ASSERT(ksid2->ks_domain->kd_name);
637
638 if (strcmp(ksid1.ks_domain->kd_name,
639 ksid2->ks_domain->kd_name) == 0 &&
640 ksid1.ks_rid == ksid2->ks_rid) {
641 user->u_flags |= SMB_USER_FLAG_ADMIN;
642 rc = B_TRUE;
643 break;
644 }
645
646 ksid2 = &ksidlist->ksl_sids[i];
647 } while (i++ < ksidlist->ksl_nsid);
648
649 ksid_rele(&ksid1);
650 return (rc);
651 }
652
653 /*
654 * This function should be called with a hold on the user.
655 */
656 boolean_t
smb_user_namecmp(smb_user_t * user,const char * name)657 smb_user_namecmp(smb_user_t *user, const char *name)
658 {
659 char *fq_name;
660 boolean_t match;
661
662 if (smb_strcasecmp(name, user->u_name, 0) == 0)
663 return (B_TRUE);
664
665 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
666
667 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
668 user->u_domain, user->u_name);
669
670 match = (smb_strcasecmp(name, fq_name, 0) == 0);
671 if (!match) {
672 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
673 user->u_name, user->u_domain);
674
675 match = (smb_strcasecmp(name, fq_name, 0) == 0);
676 }
677
678 kmem_free(fq_name, MAXNAMELEN);
679 return (match);
680 }
681
682 /*
683 * If the enumeration request is for user data, handle the request
684 * here. Otherwise, pass it on to the trees.
685 *
686 * This function should be called with a hold on the user.
687 */
688 int
smb_user_enum(smb_user_t * user,smb_svcenum_t * svcenum)689 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
690 {
691 smb_tree_t *tree;
692 smb_tree_t *next;
693 int rc;
694
695 ASSERT(user);
696 ASSERT(user->u_magic == SMB_USER_MAGIC);
697
698 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
699 return (smb_user_enum_private(user, svcenum));
700
701 tree = smb_user_get_tree(&user->u_tree_list, NULL);
702 while (tree) {
703 ASSERT(tree->t_user == user);
704
705 rc = smb_tree_enum(tree, svcenum);
706 if (rc != 0) {
707 smb_tree_release(tree);
708 break;
709 }
710
711 next = smb_user_get_tree(&user->u_tree_list, tree);
712 smb_tree_release(tree);
713 tree = next;
714 }
715
716 return (rc);
717 }
718
719 /* *************************** Static Functions ***************************** */
720
721 /*
722 * Determine whether or not a user is logged in.
723 * Typically, a reference can only be taken on a logged-in user.
724 *
725 * This is a private function and must be called with the user
726 * mutex held.
727 */
728 static boolean_t
smb_user_is_logged_in(smb_user_t * user)729 smb_user_is_logged_in(smb_user_t *user)
730 {
731 switch (user->u_state) {
732 case SMB_USER_STATE_LOGGED_IN:
733 return (B_TRUE);
734
735 case SMB_USER_STATE_LOGGING_OFF:
736 case SMB_USER_STATE_LOGGED_OFF:
737 return (B_FALSE);
738
739 default:
740 ASSERT(0);
741 return (B_FALSE);
742 }
743 }
744
745 /*
746 * Delete a user. The tree list should be empty.
747 *
748 * Remove the user from the session's user list before freeing resources
749 * associated with the user.
750 */
751 void
smb_user_delete(void * arg)752 smb_user_delete(void *arg)
753 {
754 smb_session_t *session;
755 smb_user_t *user = (smb_user_t *)arg;
756
757 SMB_USER_VALID(user);
758 ASSERT(user->u_refcnt == 0);
759 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
760
761 session = user->u_session;
762 smb_llist_enter(&session->s_user_list, RW_WRITER);
763 smb_llist_remove(&session->s_user_list, user);
764 smb_idpool_free(&session->s_uid_pool, user->u_uid);
765 smb_llist_exit(&session->s_user_list);
766
767 mutex_enter(&user->u_mutex);
768 mutex_exit(&user->u_mutex);
769
770 user->u_magic = (uint32_t)~SMB_USER_MAGIC;
771 mutex_destroy(&user->u_mutex);
772 smb_llist_destructor(&user->u_tree_list);
773 smb_idpool_destructor(&user->u_tid_pool);
774 if (user->u_cred)
775 crfree(user->u_cred);
776 if (user->u_privcred)
777 crfree(user->u_privcred);
778 smb_mem_free(user->u_name);
779 smb_mem_free(user->u_domain);
780 kmem_cache_free(user->u_server->si_cache_user, user);
781 }
782
783 /*
784 * Get the next connected tree in the list. A reference is taken on
785 * the tree, which can be released later with smb_tree_release().
786 *
787 * If the specified tree is NULL the search starts from the beginning of
788 * the tree list. If a tree is provided the search starts just after
789 * that tree.
790 *
791 * Returns NULL if there are no connected trees in the list.
792 */
793 static smb_tree_t *
smb_user_get_tree(smb_llist_t * tree_list,smb_tree_t * tree)794 smb_user_get_tree(
795 smb_llist_t *tree_list,
796 smb_tree_t *tree)
797 {
798 ASSERT(tree_list);
799
800 smb_llist_enter(tree_list, RW_READER);
801
802 if (tree) {
803 ASSERT(tree->t_magic == SMB_TREE_MAGIC);
804 tree = smb_llist_next(tree_list, tree);
805 } else {
806 tree = smb_llist_head(tree_list);
807 }
808
809 while (tree) {
810 if (smb_tree_hold(tree))
811 break;
812
813 tree = smb_llist_next(tree_list, tree);
814 }
815
816 smb_llist_exit(tree_list);
817 return (tree);
818 }
819
820 cred_t *
smb_user_getcred(smb_user_t * user)821 smb_user_getcred(smb_user_t *user)
822 {
823 return (user->u_cred);
824 }
825
826 cred_t *
smb_user_getprivcred(smb_user_t * user)827 smb_user_getprivcred(smb_user_t *user)
828 {
829 return ((user->u_privcred)? user->u_privcred : user->u_cred);
830 }
831
832 /*
833 * Assign the user cred and privileges.
834 *
835 * If the user has backup and/or restore privleges, dup the cred
836 * and add those privileges to this new privileged cred.
837 */
838 static void
smb_user_setcred(smb_user_t * user,cred_t * cr,uint32_t privileges)839 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
840 {
841 cred_t *privcred = NULL;
842
843 ASSERT(cr);
844 crhold(cr);
845
846 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
847 privcred = crdup(cr);
848
849 if (privcred != NULL) {
850 if (privileges & SMB_USER_PRIV_BACKUP) {
851 (void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
852 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
853 }
854
855 if (privileges & SMB_USER_PRIV_RESTORE) {
856 (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
857 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
858 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
859 PRIV_FILE_OWNER, PRIV_FILE_SETID,
860 PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
861 }
862 }
863
864 user->u_cred = cr;
865 user->u_privcred = privcred;
866 user->u_privileges = privileges;
867 }
868
869 /*
870 * Private function to support smb_user_enum.
871 */
872 static int
smb_user_enum_private(smb_user_t * user,smb_svcenum_t * svcenum)873 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
874 {
875 uint8_t *pb;
876 uint_t nbytes;
877 int rc;
878
879 if (svcenum->se_nskip > 0) {
880 svcenum->se_nskip--;
881 return (0);
882 }
883
884 if (svcenum->se_nitems >= svcenum->se_nlimit) {
885 svcenum->se_nitems = svcenum->se_nlimit;
886 return (0);
887 }
888
889 pb = &svcenum->se_buf[svcenum->se_bused];
890 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
891 if (rc == 0) {
892 svcenum->se_bavail -= nbytes;
893 svcenum->se_bused += nbytes;
894 svcenum->se_nitems++;
895 }
896
897 return (rc);
898 }
899
900 /*
901 * Encode the NetInfo for a user into a buffer. NetInfo contains
902 * information that is often needed in user space to support RPC
903 * requests.
904 */
905 int
smb_user_netinfo_encode(smb_user_t * user,uint8_t * buf,size_t buflen,uint32_t * nbytes)906 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
907 uint32_t *nbytes)
908 {
909 smb_netuserinfo_t info;
910 int rc;
911
912 smb_user_netinfo_init(user, &info);
913 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
914 smb_user_netinfo_fini(&info);
915
916 return (rc);
917 }
918
919 void
smb_user_netinfo_init(smb_user_t * user,smb_netuserinfo_t * info)920 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
921 {
922 smb_session_t *session;
923 char *buf;
924
925 ASSERT(user);
926 ASSERT(user->u_domain);
927 ASSERT(user->u_name);
928
929 session = user->u_session;
930 ASSERT(session);
931 ASSERT(session->workstation);
932
933 info->ui_session_id = session->s_kid;
934 info->ui_native_os = session->native_os;
935 info->ui_ipaddr = session->ipaddr;
936 info->ui_numopens = session->s_file_cnt;
937 info->ui_smb_uid = user->u_uid;
938 info->ui_logon_time = user->u_logon_time;
939 info->ui_flags = user->u_flags;
940 info->ui_posix_uid = crgetuid(user->u_cred);
941
942 info->ui_domain_len = user->u_domain_len;
943 info->ui_domain = smb_mem_strdup(user->u_domain);
944
945 info->ui_account_len = user->u_name_len;
946 info->ui_account = smb_mem_strdup(user->u_name);
947
948 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
949 smb_session_getclient(session, buf, MAXNAMELEN);
950 info->ui_workstation_len = strlen(buf) + 1;
951 info->ui_workstation = smb_mem_strdup(buf);
952 kmem_free(buf, MAXNAMELEN);
953 }
954
955 void
smb_user_netinfo_fini(smb_netuserinfo_t * info)956 smb_user_netinfo_fini(smb_netuserinfo_t *info)
957 {
958 if (info == NULL)
959 return;
960
961 if (info->ui_domain)
962 smb_mem_free(info->ui_domain);
963 if (info->ui_account)
964 smb_mem_free(info->ui_account);
965 if (info->ui_workstation)
966 smb_mem_free(info->ui_workstation);
967
968 bzero(info, sizeof (smb_netuserinfo_t));
969 }
970
971 static void
smb_user_nonauth_logon(uint32_t audit_sid)972 smb_user_nonauth_logon(uint32_t audit_sid)
973 {
974 (void) smb_kdoor_upcall(SMB_DR_USER_NONAUTH_LOGON,
975 &audit_sid, xdr_uint32_t, NULL, NULL);
976 }
977
978 static void
smb_user_auth_logoff(uint32_t audit_sid)979 smb_user_auth_logoff(uint32_t audit_sid)
980 {
981 (void) smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGOFF,
982 &audit_sid, xdr_uint32_t, NULL, NULL);
983 }
984
985 smb_token_t *
smb_get_token(smb_logon_t * user_info)986 smb_get_token(smb_logon_t *user_info)
987 {
988 smb_token_t *token;
989 int rc;
990
991 token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
992
993 rc = smb_kdoor_upcall(SMB_DR_USER_AUTH_LOGON,
994 user_info, smb_logon_xdr, token, smb_token_xdr);
995
996 if (rc != 0) {
997 kmem_free(token, sizeof (smb_token_t));
998 return (NULL);
999 }
1000
1001 if (!smb_token_valid(token)) {
1002 smb_token_free(token);
1003 return (NULL);
1004 }
1005
1006 return (token);
1007 }
1008