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 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
25 */
26
27 /*
28 * General Structures Layout
29 * -------------------------
30 *
31 * This is a simplified diagram showing the relationship between most of the
32 * main structures.
33 *
34 * +-------------------+
35 * | SMB_INFO |
36 * +-------------------+
37 * |
38 * |
39 * v
40 * +-------------------+ +-------------------+ +-------------------+
41 * | SESSION |<----->| SESSION |......| SESSION |
42 * +-------------------+ +-------------------+ +-------------------+
43 * | |
44 * | |
45 * | v
46 * | +-------------------+ +-------------------+ +-------------------+
47 * | | USER |<--->| USER |...| USER |
48 * | +-------------------+ +-------------------+ +-------------------+
49 * |
50 * |
51 * v
52 * +-------------------+ +-------------------+ +-------------------+
53 * | TREE |<----->| TREE |......| TREE |
54 * +-------------------+ +-------------------+ +-------------------+
55 * | |
56 * | |
57 * | v
58 * | +-------+ +-------+ +-------+
59 * | | OFILE |<----->| OFILE |......| OFILE |
60 * | +-------+ +-------+ +-------+
61 * |
62 * |
63 * v
64 * +-------+ +------+ +------+
65 * | ODIR |<----->| ODIR |......| ODIR |
66 * +-------+ +------+ +------+
67 *
68 *
69 * User State Machine
70 * ------------------
71 *
72 *
73 * | T0: Creation/Allocation
74 * | (1st session setup)
75 * v
76 * +-----------------------------+
77 * | SMB_USER_STATE_LOGGING_ON |<----------+
78 * +-----------------------------+ addl. session setup
79 * | | (more proc. required)
80 * | T2 | ^
81 * | | | T1: (cont.)
82 * | +------->-------?
83 * v | T3: (fail)
84 * +-----------------------------+ v
85 * | SMB_USER_STATE_LOGGED_ON | (logged off)
86 * +-----------------------------+
87 * |
88 * | T4
89 * |
90 * v
91 * +-----------------------------+
92 * | SMB_USER_STATE_LOGGING_OFF |
93 * +-----------------------------+
94 * |
95 * | T5
96 * |
97 * v
98 * +-----------------------------+ T6
99 * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free
100 * +-----------------------------+
101 *
102 * SMB_USER_STATE_LOGGING_ON
103 *
104 * While in this state:
105 * - The user is in the list of users for their session.
106 * - References will be given out ONLY for session setup.
107 * - This user can not access anything yet.
108 *
109 * SMB_USER_STATE_LOGGED_ON
110 *
111 * While in this state:
112 * - The user is in the list of users for their session.
113 * - References will be given out if the user is looked up.
114 * - The user can access files and pipes.
115 *
116 * SMB_USER_STATE_LOGGING_OFF
117 *
118 * While in this state:
119 * - The user is in the list of users for their session.
120 * - References will not be given out if the user is looked up.
121 * - The trees the user connected are being disconnected.
122 * - The resources associated with the user remain.
123 *
124 * SMB_USER_STATE_LOGGED_OFF
125 *
126 * While in this state:
127 * - The user is queued in the list of users of their session.
128 * - References will not be given out if the user is looked up.
129 * - The user has no more trees connected.
130 * - The resources associated with the user remain.
131 *
132 * Transition T0
133 *
134 * First request in an SMB Session Setup sequence creates a
135 * new user object and adds it to the list of users for
136 * this session. User UID is assigned and returned.
137 *
138 * Transition T1
139 *
140 * Subsequent SMB Session Setup requests (on the same UID
141 * assigned in T0) update the state of this user object,
142 * communicating with smbd for the crypto work.
143 *
144 * Transition T2
145 *
146 * If the SMB Session Setup sequence is successful, T2
147 * makes the new user object available for requests.
148 *
149 * Transition T3
150 *
151 * If an Session Setup request gets an error other than
152 * the expected "more processing required", then T3
153 * leads to state "LOGGED_OFF" and then tear-down of the
154 * partially constructed user.
155 *
156 * Transition T4
157 *
158 * Normal SMB User Logoff request, or session tear-down.
159 *
160 * Transition T5
161 *
162 * This transition occurs in smb_user_release(). The resources associated
163 * with the user are deleted as well as the user. For the transition to
164 * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
165 * reference count be zero.
166 *
167 * Comments
168 * --------
169 *
170 * The state machine of the user structures is controlled by 3 elements:
171 * - The list of users of the session they belong to.
172 * - The mutex embedded in the structure itself.
173 * - The reference count.
174 *
175 * There's a mutex embedded in the user structure used to protect its fields
176 * and there's a lock embedded in the list of users of a session. To
177 * increment or to decrement the reference count the mutex must be entered.
178 * To insert the user into the list of users of the session and to remove
179 * the user from it, the lock must be entered in RW_WRITER mode.
180 *
181 * Rules of access to a user structure:
182 *
183 * 1) In order to avoid deadlocks, when both (mutex and lock of the session
184 * list) have to be entered, the lock must be entered first.
185 *
186 * 2) All actions applied to a user require a reference count.
187 *
188 * 3) There are 2 ways of getting a reference count. One is when the user
189 * logs in. The other when the user is looked up.
190 *
191 * It should be noted that the reference count of a user registers the
192 * number of references to the user in other structures (such as an smb
193 * request). The reference count is not incremented in these 2 instances:
194 *
195 * 1) The user is logged in. An user is anchored by their state. If there's
196 * no activity involving a user currently logged in, the reference
197 * count of that user is zero.
198 *
199 * 2) The user is queued in the list of users of the session. The fact of
200 * being queued in that list is NOT registered by incrementing the
201 * reference count.
202 */
203 #include <sys/types.h>
204 #include <sys/sid.h>
205 #include <sys/priv_names.h>
206 #include <smbsrv/smb_kproto.h>
207 #include <smbsrv/smb_door.h>
208
209 #define ADMINISTRATORS_SID "S-1-5-32-544"
210
211 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
212 static void smb_user_auth_logoff(smb_user_t *);
213
214
215 /*
216 * Create a new user.
217 */
218 smb_user_t *
219 smb_user_new(smb_session_t *session)
220 {
221 smb_user_t *user;
222
223 ASSERT(session);
224 ASSERT(session->s_magic == SMB_SESSION_MAGIC);
225
226 user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
227 bzero(user, sizeof (smb_user_t));
228
229 user->u_refcnt = 1;
230 user->u_session = session;
231 user->u_server = session->s_server;
232 user->u_logon_time = gethrestime_sec();
233
234 if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
235 goto errout;
236
237 mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
238 user->u_state = SMB_USER_STATE_LOGGING_ON;
239 user->u_magic = SMB_USER_MAGIC;
240
241 smb_llist_enter(&session->s_user_list, RW_WRITER);
242 smb_llist_insert_tail(&session->s_user_list, user);
243 smb_llist_exit(&session->s_user_list);
244 smb_server_inc_users(session->s_server);
245
246 return (user);
247
248 errout:
249 if (user->u_uid != 0)
250 smb_idpool_free(&session->s_uid_pool, user->u_uid);
251 kmem_cache_free(smb_cache_user, user);
252 return (NULL);
253 }
254
255 /*
256 * Fill in the details of a user, meaning a transition
257 * from state LOGGING_ON to state LOGGED_ON.
258 */
259 int
260 smb_user_logon(
261 smb_user_t *user,
262 cred_t *cr,
263 char *domain_name,
264 char *account_name,
265 uint32_t flags,
266 uint32_t privileges,
267 uint32_t audit_sid)
268 {
269
270 ASSERT(user->u_magic == SMB_USER_MAGIC);
271 ASSERT(cr);
272 ASSERT(account_name);
273 ASSERT(domain_name);
274
275 mutex_enter(&user->u_mutex);
276
277 if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
278 mutex_exit(&user->u_mutex);
279 return (-1);
280 }
281
282 smb_authsock_close(user);
283
284 user->u_state = SMB_USER_STATE_LOGGED_ON;
285 user->u_flags = flags;
286 user->u_name_len = strlen(account_name) + 1;
287 user->u_domain_len = strlen(domain_name) + 1;
288 user->u_name = smb_mem_strdup(account_name);
289 user->u_domain = smb_mem_strdup(domain_name);
290 user->u_audit_sid = audit_sid;
291
292 smb_user_setcred(user, cr, privileges);
293
294 mutex_exit(&user->u_mutex);
295
296 return (0);
297 }
298
299 /*
300 * smb_user_logoff
301 *
302 * Change the user state and disconnect trees.
303 * The user list must not be entered or modified here.
304 */
305 void
306 smb_user_logoff(
307 smb_user_t *user)
308 {
309 ASSERT(user->u_magic == SMB_USER_MAGIC);
310
311 mutex_enter(&user->u_mutex);
312 ASSERT(user->u_refcnt);
313 switch (user->u_state) {
314 case SMB_USER_STATE_LOGGING_ON: {
315 smb_authsock_close(user);
316 user->u_state = SMB_USER_STATE_LOGGED_OFF;
317 smb_server_dec_users(user->u_server);
318 break;
319 }
320
321 case SMB_USER_STATE_LOGGED_ON: {
322 /*
323 * The user is moved into a state indicating that the log off
324 * process has started.
325 */
326 user->u_state = SMB_USER_STATE_LOGGING_OFF;
327 mutex_exit(&user->u_mutex);
328 smb_session_disconnect_owned_trees(user->u_session, user);
329 smb_user_auth_logoff(user);
330 mutex_enter(&user->u_mutex);
331 user->u_state = SMB_USER_STATE_LOGGED_OFF;
332 smb_server_dec_users(user->u_server);
333 break;
334 }
335 case SMB_USER_STATE_LOGGED_OFF:
336 case SMB_USER_STATE_LOGGING_OFF:
337 break;
338
339 default:
340 ASSERT(0);
341 break;
342 }
343 mutex_exit(&user->u_mutex);
344 }
345
346 /*
347 * Take a reference on a user. Do not return a reference unless the user is in
348 * the logged-in state.
349 */
350 boolean_t
351 smb_user_hold(smb_user_t *user)
352 {
353 SMB_USER_VALID(user);
354
355 mutex_enter(&user->u_mutex);
356
357 if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
358 user->u_refcnt++;
359 mutex_exit(&user->u_mutex);
360 return (B_TRUE);
361 }
362
363 mutex_exit(&user->u_mutex);
364 return (B_FALSE);
365 }
366
367 /*
368 * Unconditionally take a reference on a user.
369 */
370 void
371 smb_user_hold_internal(smb_user_t *user)
372 {
373 SMB_USER_VALID(user);
374
375 mutex_enter(&user->u_mutex);
376 user->u_refcnt++;
377 mutex_exit(&user->u_mutex);
378 }
379
380 /*
381 * Release a reference on a user. If the reference count falls to
382 * zero and the user has logged off, post the object for deletion.
383 * Object deletion is deferred to avoid modifying a list while an
384 * iteration may be in progress.
385 */
386 void
387 smb_user_release(
388 smb_user_t *user)
389 {
390 ASSERT(user->u_magic == SMB_USER_MAGIC);
391
392 mutex_enter(&user->u_mutex);
393 ASSERT(user->u_refcnt);
394 user->u_refcnt--;
395
396 switch (user->u_state) {
397 case SMB_USER_STATE_LOGGED_OFF:
398 if (user->u_refcnt == 0)
399 smb_session_post_user(user->u_session, user);
400 break;
401
402 case SMB_USER_STATE_LOGGING_ON:
403 case SMB_USER_STATE_LOGGED_ON:
404 case SMB_USER_STATE_LOGGING_OFF:
405 break;
406
407 default:
408 ASSERT(0);
409 break;
410 }
411 mutex_exit(&user->u_mutex);
412 }
413
414 /*
415 * Determine whether or not the user is an administrator.
416 * Members of the administrators group have administrative rights.
417 */
418 boolean_t
419 smb_user_is_admin(smb_user_t *user)
420 {
421 #ifdef _KERNEL
422 char sidstr[SMB_SID_STRSZ];
423 ksidlist_t *ksidlist;
424 ksid_t ksid1;
425 ksid_t *ksid2;
426 int i;
427 #endif /* _KERNEL */
428 boolean_t rc = B_FALSE;
429
430 ASSERT(user);
431 ASSERT(user->u_cred);
432
433 if (SMB_USER_IS_ADMIN(user))
434 return (B_TRUE);
435
436 #ifdef _KERNEL
437 bzero(&ksid1, sizeof (ksid_t));
438 (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
439 ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
440 ksid1.ks_domain = ksid_lookupdomain(sidstr);
441
442 ksidlist = crgetsidlist(user->u_cred);
443 ASSERT(ksidlist);
444 ASSERT(ksid1.ks_domain);
445 ASSERT(ksid1.ks_domain->kd_name);
446
447 i = 0;
448 ksid2 = crgetsid(user->u_cred, KSID_USER);
449 do {
450 ASSERT(ksid2->ks_domain);
451 ASSERT(ksid2->ks_domain->kd_name);
452
453 if (strcmp(ksid1.ks_domain->kd_name,
454 ksid2->ks_domain->kd_name) == 0 &&
455 ksid1.ks_rid == ksid2->ks_rid) {
456 user->u_flags |= SMB_USER_FLAG_ADMIN;
457 rc = B_TRUE;
458 break;
459 }
460
461 ksid2 = &ksidlist->ksl_sids[i];
462 } while (i++ < ksidlist->ksl_nsid);
463
464 ksid_rele(&ksid1);
465 #endif /* _KERNEL */
466 return (rc);
467 }
468
469 /*
470 * This function should be called with a hold on the user.
471 */
472 boolean_t
473 smb_user_namecmp(smb_user_t *user, const char *name)
474 {
475 char *fq_name;
476 boolean_t match;
477
478 if (smb_strcasecmp(name, user->u_name, 0) == 0)
479 return (B_TRUE);
480
481 fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
482
483 (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
484 user->u_domain, user->u_name);
485
486 match = (smb_strcasecmp(name, fq_name, 0) == 0);
487 if (!match) {
488 (void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
489 user->u_name, user->u_domain);
490
491 match = (smb_strcasecmp(name, fq_name, 0) == 0);
492 }
493
494 kmem_free(fq_name, MAXNAMELEN);
495 return (match);
496 }
497
498 /*
499 * If the enumeration request is for user data, handle the request
500 * here. Otherwise, pass it on to the trees.
501 *
502 * This function should be called with a hold on the user.
503 */
504 int
505 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
506 {
507 int rc = 0;
508
509 ASSERT(user);
510 ASSERT(user->u_magic == SMB_USER_MAGIC);
511
512 if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
513 return (smb_user_enum_private(user, svcenum));
514
515 return (rc);
516 }
517
518 /* *************************** Static Functions ***************************** */
519
520 /*
521 * Delete a user. The tree list should be empty.
522 *
523 * Remove the user from the session's user list before freeing resources
524 * associated with the user.
525 */
526 void
527 smb_user_delete(void *arg)
528 {
529 smb_session_t *session;
530 smb_user_t *user = (smb_user_t *)arg;
531
532 SMB_USER_VALID(user);
533 ASSERT(user->u_refcnt == 0);
534 ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
535 ASSERT(user->u_authsock == NULL);
536
537 session = user->u_session;
538 smb_llist_enter(&session->s_user_list, RW_WRITER);
539 smb_llist_remove(&session->s_user_list, user);
540 smb_idpool_free(&session->s_uid_pool, user->u_uid);
541 smb_llist_exit(&session->s_user_list);
542
543 mutex_enter(&user->u_mutex);
544 mutex_exit(&user->u_mutex);
545
546 user->u_magic = (uint32_t)~SMB_USER_MAGIC;
547 mutex_destroy(&user->u_mutex);
548 if (user->u_cred)
549 crfree(user->u_cred);
550 if (user->u_privcred)
551 crfree(user->u_privcred);
552 smb_mem_free(user->u_name);
553 smb_mem_free(user->u_domain);
554 kmem_cache_free(smb_cache_user, user);
555 }
556
557 cred_t *
558 smb_user_getcred(smb_user_t *user)
559 {
560 return (user->u_cred);
561 }
562
563 cred_t *
564 smb_user_getprivcred(smb_user_t *user)
565 {
566 return ((user->u_privcred)? user->u_privcred : user->u_cred);
567 }
568
569 #ifdef _KERNEL
570 /*
571 * Assign the user cred and privileges.
572 *
573 * If the user has backup and/or restore privleges, dup the cred
574 * and add those privileges to this new privileged cred.
575 */
576 void
577 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
578 {
579 cred_t *privcred = NULL;
580
581 ASSERT(cr);
582 crhold(cr);
583
584 if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
585 privcred = crdup(cr);
586
587 if (privcred != NULL) {
588 if (privileges & SMB_USER_PRIV_BACKUP) {
589 (void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
590 PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
591 }
592
593 if (privileges & SMB_USER_PRIV_RESTORE) {
594 (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
595 PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
596 PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
597 PRIV_FILE_OWNER, PRIV_FILE_SETID,
598 PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
599 }
600 }
601
602 user->u_cred = cr;
603 user->u_privcred = privcred;
604 user->u_privileges = privileges;
605 }
606 #endif /* _KERNEL */
607
608 /*
609 * Private function to support smb_user_enum.
610 */
611 static int
612 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
613 {
614 uint8_t *pb;
615 uint_t nbytes;
616 int rc;
617
618 if (svcenum->se_nskip > 0) {
619 svcenum->se_nskip--;
620 return (0);
621 }
622
623 if (svcenum->se_nitems >= svcenum->se_nlimit) {
624 svcenum->se_nitems = svcenum->se_nlimit;
625 return (0);
626 }
627
628 pb = &svcenum->se_buf[svcenum->se_bused];
629 rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
630 if (rc == 0) {
631 svcenum->se_bavail -= nbytes;
632 svcenum->se_bused += nbytes;
633 svcenum->se_nitems++;
634 }
635
636 return (rc);
637 }
638
639 /*
640 * Encode the NetInfo for a user into a buffer. NetInfo contains
641 * information that is often needed in user space to support RPC
642 * requests.
643 */
644 int
645 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
646 uint32_t *nbytes)
647 {
648 smb_netuserinfo_t info;
649 int rc;
650
651 smb_user_netinfo_init(user, &info);
652 rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
653 smb_user_netinfo_fini(&info);
654
655 return (rc);
656 }
657
658 void
659 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
660 {
661 smb_session_t *session;
662 char *buf;
663
664 ASSERT(user);
665 ASSERT(user->u_domain);
666 ASSERT(user->u_name);
667
668 session = user->u_session;
669 ASSERT(session);
670 ASSERT(session->workstation);
671
672 info->ui_session_id = session->s_kid;
673 info->ui_native_os = session->native_os;
674 info->ui_ipaddr = session->ipaddr;
675 info->ui_numopens = session->s_file_cnt;
676 info->ui_smb_uid = user->u_uid;
677 info->ui_logon_time = user->u_logon_time;
678 info->ui_flags = user->u_flags;
679 info->ui_posix_uid = crgetuid(user->u_cred);
680
681 info->ui_domain_len = user->u_domain_len;
682 info->ui_domain = smb_mem_strdup(user->u_domain);
683
684 info->ui_account_len = user->u_name_len;
685 info->ui_account = smb_mem_strdup(user->u_name);
686
687 buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
688 smb_session_getclient(session, buf, MAXNAMELEN);
689 info->ui_workstation_len = strlen(buf) + 1;
690 info->ui_workstation = smb_mem_strdup(buf);
691 kmem_free(buf, MAXNAMELEN);
692 }
693
694 void
695 smb_user_netinfo_fini(smb_netuserinfo_t *info)
696 {
697 if (info == NULL)
698 return;
699
700 if (info->ui_domain)
701 smb_mem_free(info->ui_domain);
702 if (info->ui_account)
703 smb_mem_free(info->ui_account);
704 if (info->ui_workstation)
705 smb_mem_free(info->ui_workstation);
706
707 bzero(info, sizeof (smb_netuserinfo_t));
708 }
709
710 static void
711 smb_user_auth_logoff(smb_user_t *user)
712 {
713 uint32_t audit_sid = user->u_audit_sid;
714
715 (void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF,
716 &audit_sid, xdr_uint32_t, NULL, NULL);
717 }