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