1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23f37b3cbbSMatt Barden * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
2586184067SGordon Ross * Copyright 2022-2023 RackTop Systems, Inc.
26da6c28aaSamw */
27da6c28aaSamw
28da6c28aaSamw /*
29da6c28aaSamw * General Structures Layout
30da6c28aaSamw * -------------------------
31da6c28aaSamw *
32da6c28aaSamw * This is a simplified diagram showing the relationship between most of the
33da6c28aaSamw * main structures.
34da6c28aaSamw *
35da6c28aaSamw * +-------------------+
36da6c28aaSamw * | SMB_INFO |
37da6c28aaSamw * +-------------------+
38da6c28aaSamw * |
39da6c28aaSamw * |
40da6c28aaSamw * v
41da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+
42da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION |
43da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+
443b13a1efSThomas Keiser * | |
453b13a1efSThomas Keiser * | |
463b13a1efSThomas Keiser * | v
473b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+
483b13a1efSThomas Keiser * | | USER |<--->| USER |...| USER |
493b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+
503b13a1efSThomas Keiser * |
513b13a1efSThomas Keiser * |
523b13a1efSThomas Keiser * v
53da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+
54da6c28aaSamw * | TREE |<----->| TREE |......| TREE |
55da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+
56da6c28aaSamw * | |
57da6c28aaSamw * | |
58da6c28aaSamw * | v
59da6c28aaSamw * | +-------+ +-------+ +-------+
60da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE |
61da6c28aaSamw * | +-------+ +-------+ +-------+
62da6c28aaSamw * |
63da6c28aaSamw * |
64da6c28aaSamw * v
65da6c28aaSamw * +-------+ +------+ +------+
66da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR |
67da6c28aaSamw * +-------+ +------+ +------+
68da6c28aaSamw *
69da6c28aaSamw *
70da6c28aaSamw * User State Machine
71da6c28aaSamw * ------------------
72da6c28aaSamw *
7312b65585SGordon Ross *
7412b65585SGordon Ross * | T0: Creation/Allocation
7512b65585SGordon Ross * | (1st session setup)
7612b65585SGordon Ross * v
7712b65585SGordon Ross * +-----------------------------+
7812b65585SGordon Ross * | SMB_USER_STATE_LOGGING_ON |<----------+
7912b65585SGordon Ross * +-----------------------------+ addl. session setup
8012b65585SGordon Ross * | | (more proc. required)
8112b65585SGordon Ross * | T2 | ^
8212b65585SGordon Ross * | | | T1: (cont.)
8312b65585SGordon Ross * | +------->-------?
8412b65585SGordon Ross * v | T3: (fail)
8512b65585SGordon Ross * +-----------------------------+ v
8612b65585SGordon Ross * | SMB_USER_STATE_LOGGED_ON | (logged off)
87da6c28aaSamw * +-----------------------------+
88da6c28aaSamw * |
8912b65585SGordon Ross * | T4
90da6c28aaSamw * |
91da6c28aaSamw * v
92da6c28aaSamw * +-----------------------------+
93da6c28aaSamw * | SMB_USER_STATE_LOGGING_OFF |
94da6c28aaSamw * +-----------------------------+
95da6c28aaSamw * |
9612b65585SGordon Ross * | T5
97da6c28aaSamw * |
98da6c28aaSamw * v
9912b65585SGordon Ross * +-----------------------------+ T6
100da6c28aaSamw * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free
101da6c28aaSamw * +-----------------------------+
102da6c28aaSamw *
10312b65585SGordon Ross * SMB_USER_STATE_LOGGING_ON
104da6c28aaSamw *
105da6c28aaSamw * While in this state:
10648bbca81SDaniel Hoffman * - The user is in the list of users for their session.
10712b65585SGordon Ross * - References will be given out ONLY for session setup.
10812b65585SGordon Ross * - This user can not access anything yet.
10912b65585SGordon Ross *
11012b65585SGordon Ross * SMB_USER_STATE_LOGGED_ON
11112b65585SGordon Ross *
11212b65585SGordon Ross * While in this state:
11348bbca81SDaniel Hoffman * - The user is in the list of users for their session.
114da6c28aaSamw * - References will be given out if the user is looked up.
115da6c28aaSamw * - The user can access files and pipes.
116da6c28aaSamw *
117da6c28aaSamw * SMB_USER_STATE_LOGGING_OFF
118da6c28aaSamw *
119da6c28aaSamw * While in this state:
12048bbca81SDaniel Hoffman * - The user is in the list of users for their session.
121da6c28aaSamw * - References will not be given out if the user is looked up.
122da6c28aaSamw * - The trees the user connected are being disconnected.
123da6c28aaSamw * - The resources associated with the user remain.
124da6c28aaSamw *
12512b65585SGordon Ross * SMB_USER_STATE_LOGGED_OFF
126da6c28aaSamw *
127da6c28aaSamw * While in this state:
12848bbca81SDaniel Hoffman * - The user is queued in the list of users of their session.
129da6c28aaSamw * - References will not be given out if the user is looked up.
130da6c28aaSamw * - The user has no more trees connected.
131da6c28aaSamw * - The resources associated with the user remain.
132da6c28aaSamw *
133da6c28aaSamw * Transition T0
134da6c28aaSamw *
13512b65585SGordon Ross * First request in an SMB Session Setup sequence creates a
13612b65585SGordon Ross * new user object and adds it to the list of users for
13712b65585SGordon Ross * this session. User UID is assigned and returned.
138da6c28aaSamw *
139da6c28aaSamw * Transition T1
140da6c28aaSamw *
14112b65585SGordon Ross * Subsequent SMB Session Setup requests (on the same UID
14212b65585SGordon Ross * assigned in T0) update the state of this user object,
14312b65585SGordon Ross * communicating with smbd for the crypto work.
144da6c28aaSamw *
145da6c28aaSamw * Transition T2
146da6c28aaSamw *
14712b65585SGordon Ross * If the SMB Session Setup sequence is successful, T2
14812b65585SGordon Ross * makes the new user object available for requests.
14912b65585SGordon Ross *
15012b65585SGordon Ross * Transition T3
15112b65585SGordon Ross *
15212b65585SGordon Ross * If an Session Setup request gets an error other than
15312b65585SGordon Ross * the expected "more processing required", then T3
15412b65585SGordon Ross * leads to state "LOGGED_OFF" and then tear-down of the
15512b65585SGordon Ross * partially constructed user.
15612b65585SGordon Ross *
15712b65585SGordon Ross * Transition T4
15812b65585SGordon Ross *
15912b65585SGordon Ross * Normal SMB User Logoff request, or session tear-down.
16012b65585SGordon Ross *
16112b65585SGordon Ross * Transition T5
16212b65585SGordon Ross *
163da6c28aaSamw * This transition occurs in smb_user_release(). The resources associated
164da6c28aaSamw * with the user are deleted as well as the user. For the transition to
165da6c28aaSamw * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
166da6c28aaSamw * reference count be zero.
167da6c28aaSamw *
168da6c28aaSamw * Comments
169da6c28aaSamw * --------
170da6c28aaSamw *
171da6c28aaSamw * The state machine of the user structures is controlled by 3 elements:
17248bbca81SDaniel Hoffman * - The list of users of the session they belong to.
173da6c28aaSamw * - The mutex embedded in the structure itself.
174da6c28aaSamw * - The reference count.
175da6c28aaSamw *
176da6c28aaSamw * There's a mutex embedded in the user structure used to protect its fields
177da6c28aaSamw * and there's a lock embedded in the list of users of a session. To
178da6c28aaSamw * increment or to decrement the reference count the mutex must be entered.
179da6c28aaSamw * To insert the user into the list of users of the session and to remove
180da6c28aaSamw * the user from it, the lock must be entered in RW_WRITER mode.
181da6c28aaSamw *
182da6c28aaSamw * Rules of access to a user structure:
183da6c28aaSamw *
184da6c28aaSamw * 1) In order to avoid deadlocks, when both (mutex and lock of the session
185811599a4SMatt Barden * list) have to be entered, the lock must be entered first. Additionally,
186811599a4SMatt Barden * one may NOT flush the deleteq of either the tree list or the ofile list
187811599a4SMatt Barden * while the user mutex is held.
188da6c28aaSamw *
189da6c28aaSamw * 2) All actions applied to a user require a reference count.
190da6c28aaSamw *
191da6c28aaSamw * 3) There are 2 ways of getting a reference count. One is when the user
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * logs in. The other when the user is looked up.
193da6c28aaSamw *
194da6c28aaSamw * It should be noted that the reference count of a user registers the
195da6c28aaSamw * number of references to the user in other structures (such as an smb
196da6c28aaSamw * request). The reference count is not incremented in these 2 instances:
197da6c28aaSamw *
19848bbca81SDaniel Hoffman * 1) The user is logged in. An user is anchored by their state. If there's
199da6c28aaSamw * no activity involving a user currently logged in, the reference
200da6c28aaSamw * count of that user is zero.
201da6c28aaSamw *
202da6c28aaSamw * 2) The user is queued in the list of users of the session. The fact of
203da6c28aaSamw * being queued in that list is NOT registered by incrementing the
204da6c28aaSamw * reference count.
205da6c28aaSamw */
206148c5f43SAlan Wright #include <sys/types.h>
207148c5f43SAlan Wright #include <sys/sid.h>
208148c5f43SAlan Wright #include <sys/priv_names.h>
2099e3ab9e9SMatt Barden #include <sys/priv.h>
2109e3ab9e9SMatt Barden #include <sys/policy.h>
211bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
2129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h>
213da6c28aaSamw
214c8ec8eeaSjose borrego #define ADMINISTRATORS_SID "S-1-5-32-544"
215c8ec8eeaSjose borrego
216811599a4SMatt Barden /* Don't leak object addresses */
217811599a4SMatt Barden #define SMB_USER_SSNID(u) \
218811599a4SMatt Barden ((uintptr_t)&smb_cache_user ^ (uintptr_t)(u))
219811599a4SMatt Barden
220811599a4SMatt Barden static void smb_user_delete(void *);
2211fcced4cSJordan Brown static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
2228622ec45SGordon Ross static void smb_user_auth_logoff(smb_user_t *);
2238f70e16bSGordon Ross static void smb_user_logoff_tq(void *);
224c8ec8eeaSjose borrego
225da6c28aaSamw /*
226148c5f43SAlan Wright * Create a new user.
227811599a4SMatt Barden *
228811599a4SMatt Barden * For SMB2 and later, session IDs (u_ssnid) need to be unique among all
229811599a4SMatt Barden * current and "recent" sessions. The session ID is derived from the
230811599a4SMatt Barden * address of the smb_user object (obscured by XOR with a constant).
231811599a4SMatt Barden * This adds a 3-bit generation number in the low bits, incremented
232811599a4SMatt Barden * when we allocate an smb_user_t from its kmem cache, so it can't
233811599a4SMatt Barden * be confused with a (recent) previous incarnation of this object.
234da6c28aaSamw */
235da6c28aaSamw smb_user_t *
smb_user_new(smb_session_t * session)23612b65585SGordon Ross smb_user_new(smb_session_t *session)
237da6c28aaSamw {
238da6c28aaSamw smb_user_t *user;
239811599a4SMatt Barden uint_t gen; // generation (low 3 bits of ssnid)
240817fa55fSGordon Ross uint32_t ucount;
241da6c28aaSamw
242da6c28aaSamw ASSERT(session);
243da6c28aaSamw ASSERT(session->s_magic == SMB_SESSION_MAGIC);
244da6c28aaSamw
2458622ec45SGordon Ross user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
246811599a4SMatt Barden gen = (user->u_ssnid + 1) & 7;
247da6c28aaSamw bzero(user, sizeof (smb_user_t));
24812b65585SGordon Ross
249da6c28aaSamw user->u_refcnt = 1;
250da6c28aaSamw user->u_session = session;
251faa1795aSjb user->u_server = session->s_server;
252da6c28aaSamw user->u_logon_time = gethrestime_sec();
253da6c28aaSamw
25412b65585SGordon Ross if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid))
25512b65585SGordon Ross goto errout;
256811599a4SMatt Barden user->u_ssnid = SMB_USER_SSNID(user) + gen;
25712b65585SGordon Ross
25812b65585SGordon Ross mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
25912b65585SGordon Ross user->u_state = SMB_USER_STATE_LOGGING_ON;
26012b65585SGordon Ross user->u_magic = SMB_USER_MAGIC;
26112b65585SGordon Ross
26212b65585SGordon Ross smb_llist_enter(&session->s_user_list, RW_WRITER);
263817fa55fSGordon Ross ucount = smb_llist_get_count(&session->s_user_list);
26412b65585SGordon Ross smb_llist_insert_tail(&session->s_user_list, user);
26512b65585SGordon Ross smb_llist_exit(&session->s_user_list);
26612b65585SGordon Ross smb_server_inc_users(session->s_server);
26712b65585SGordon Ross
268817fa55fSGordon Ross /*
269817fa55fSGordon Ross * If we added the first user to the session, cancel the
270817fa55fSGordon Ross * timeout that was started in smb_session_receiver().
271817fa55fSGordon Ross */
272817fa55fSGordon Ross if (ucount == 0) {
273817fa55fSGordon Ross timeout_id_t tmo = NULL;
274817fa55fSGordon Ross
275817fa55fSGordon Ross smb_rwx_rwenter(&session->s_lock, RW_WRITER);
276817fa55fSGordon Ross tmo = session->s_auth_tmo;
277817fa55fSGordon Ross session->s_auth_tmo = NULL;
278817fa55fSGordon Ross smb_rwx_rwexit(&session->s_lock);
279817fa55fSGordon Ross
280817fa55fSGordon Ross if (tmo != NULL)
281817fa55fSGordon Ross (void) untimeout(tmo);
282817fa55fSGordon Ross }
283817fa55fSGordon Ross
28412b65585SGordon Ross return (user);
28512b65585SGordon Ross
28612b65585SGordon Ross errout:
28712b65585SGordon Ross if (user->u_uid != 0)
28812b65585SGordon Ross smb_idpool_free(&session->s_uid_pool, user->u_uid);
2898622ec45SGordon Ross kmem_cache_free(smb_cache_user, user);
290da6c28aaSamw return (NULL);
291da6c28aaSamw }
292da6c28aaSamw
293da6c28aaSamw /*
29412b65585SGordon Ross * Fill in the details of a user, meaning a transition
29512b65585SGordon Ross * from state LOGGING_ON to state LOGGED_ON.
296da6c28aaSamw */
29712b65585SGordon Ross 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)29812b65585SGordon Ross smb_user_logon(
29912b65585SGordon Ross smb_user_t *user,
30012b65585SGordon Ross cred_t *cr,
30112b65585SGordon Ross char *domain_name,
30212b65585SGordon Ross char *account_name,
30312b65585SGordon Ross uint32_t flags,
30412b65585SGordon Ross uint32_t privileges,
30512b65585SGordon Ross uint32_t audit_sid)
306da6c28aaSamw {
307b210fedeSGordon Ross ksocket_t authsock = NULL;
3088f70e16bSGordon Ross timeout_id_t tmo = NULL;
309da6c28aaSamw
31012b65585SGordon Ross ASSERT(user->u_magic == SMB_USER_MAGIC);
31112b65585SGordon Ross ASSERT(cr);
31212b65585SGordon Ross ASSERT(account_name);
31312b65585SGordon Ross ASSERT(domain_name);
314da6c28aaSamw
31512b65585SGordon Ross mutex_enter(&user->u_mutex);
316da6c28aaSamw
31712b65585SGordon Ross if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
31812b65585SGordon Ross mutex_exit(&user->u_mutex);
31912b65585SGordon Ross return (-1);
32012b65585SGordon Ross }
321da6c28aaSamw
322b210fedeSGordon Ross /*
323b210fedeSGordon Ross * In the transition from LOGGING_ON to LOGGED_ON,
324b210fedeSGordon Ross * we always have an auth. socket to close.
325b210fedeSGordon Ross */
326b210fedeSGordon Ross authsock = user->u_authsock;
327b210fedeSGordon Ross user->u_authsock = NULL;
3288f70e16bSGordon Ross tmo = user->u_auth_tmo;
3298f70e16bSGordon Ross user->u_auth_tmo = NULL;
33012b65585SGordon Ross
33112b65585SGordon Ross user->u_state = SMB_USER_STATE_LOGGED_ON;
33212b65585SGordon Ross user->u_flags = flags;
33312b65585SGordon Ross user->u_name_len = strlen(account_name) + 1;
33412b65585SGordon Ross user->u_domain_len = strlen(domain_name) + 1;
33512b65585SGordon Ross user->u_name = smb_mem_strdup(account_name);
33612b65585SGordon Ross user->u_domain = smb_mem_strdup(domain_name);
33712b65585SGordon Ross user->u_audit_sid = audit_sid;
33812b65585SGordon Ross
33912b65585SGordon Ross smb_user_setcred(user, cr, privileges);
34012b65585SGordon Ross
34112b65585SGordon Ross mutex_exit(&user->u_mutex);
34212b65585SGordon Ross
3438f70e16bSGordon Ross /* Timeout callback takes u_mutex. See untimeout(9f) */
3448f70e16bSGordon Ross if (tmo != NULL)
3458f70e16bSGordon Ross (void) untimeout(tmo);
3468f70e16bSGordon Ross
347b210fedeSGordon Ross /* This close can block, so not under the mutex. */
3488d94f651SGordon Ross if (authsock != NULL)
3498d94f651SGordon Ross smb_authsock_close(user, authsock);
350b210fedeSGordon Ross
35112b65585SGordon Ross return (0);
352da6c28aaSamw }
353da6c28aaSamw
354da6c28aaSamw /*
355da6c28aaSamw * smb_user_logoff
356da6c28aaSamw *
357811599a4SMatt Barden * Change the user state to "logging off" and disconnect trees.
3581fcced4cSJordan Brown * The user list must not be entered or modified here.
359811599a4SMatt Barden *
360811599a4SMatt Barden * We remain in state "logging off" until the last ref. is gone,
361811599a4SMatt Barden * then smb_user_release takes us to state "logged off".
362da6c28aaSamw */
363da6c28aaSamw void
smb_user_logoff(smb_user_t * user)364da6c28aaSamw smb_user_logoff(
365da6c28aaSamw smb_user_t *user)
366da6c28aaSamw {
367b210fedeSGordon Ross ksocket_t authsock = NULL;
3688f70e16bSGordon Ross timeout_id_t tmo = NULL;
369b210fedeSGordon Ross
370da6c28aaSamw ASSERT(user->u_magic == SMB_USER_MAGIC);
371da6c28aaSamw
372da6c28aaSamw mutex_enter(&user->u_mutex);
373da6c28aaSamw ASSERT(user->u_refcnt);
374da6c28aaSamw switch (user->u_state) {
375b210fedeSGordon Ross case SMB_USER_STATE_LOGGING_ON:
376b210fedeSGordon Ross authsock = user->u_authsock;
377b210fedeSGordon Ross user->u_authsock = NULL;
3788f70e16bSGordon Ross tmo = user->u_auth_tmo;
3798f70e16bSGordon Ross user->u_auth_tmo = NULL;
380811599a4SMatt Barden user->u_state = SMB_USER_STATE_LOGGING_OFF;
381811599a4SMatt Barden mutex_exit(&user->u_mutex);
382811599a4SMatt Barden
383811599a4SMatt Barden /* Timeout callback takes u_mutex. See untimeout(9f) */
384811599a4SMatt Barden if (tmo != NULL)
385811599a4SMatt Barden (void) untimeout(tmo);
386811599a4SMatt Barden /* This close can block, so not under the mutex. */
387811599a4SMatt Barden if (authsock != NULL)
388811599a4SMatt Barden smb_authsock_close(user, authsock);
38912b65585SGordon Ross break;
39012b65585SGordon Ross
391b210fedeSGordon Ross case SMB_USER_STATE_LOGGED_ON:
392da6c28aaSamw /*
393da6c28aaSamw * The user is moved into a state indicating that the log off
394da6c28aaSamw * process has started.
395da6c28aaSamw */
396da6c28aaSamw user->u_state = SMB_USER_STATE_LOGGING_OFF;
397da6c28aaSamw mutex_exit(&user->u_mutex);
3983b13a1efSThomas Keiser smb_session_disconnect_owned_trees(user->u_session, user);
3998622ec45SGordon Ross smb_user_auth_logoff(user);
400da6c28aaSamw break;
401b210fedeSGordon Ross
402da6c28aaSamw case SMB_USER_STATE_LOGGED_OFF:
403da6c28aaSamw case SMB_USER_STATE_LOGGING_OFF:
404811599a4SMatt Barden mutex_exit(&user->u_mutex);
405da6c28aaSamw break;
406da6c28aaSamw
407da6c28aaSamw default:
408da6c28aaSamw ASSERT(0);
409811599a4SMatt Barden mutex_exit(&user->u_mutex);
410da6c28aaSamw break;
411da6c28aaSamw }
412da6c28aaSamw }
413da6c28aaSamw
4141fcced4cSJordan Brown /*
4153b13a1efSThomas Keiser * Take a reference on a user. Do not return a reference unless the user is in
4163b13a1efSThomas Keiser * the logged-in state.
4171fcced4cSJordan Brown */
4181fcced4cSJordan Brown boolean_t
smb_user_hold(smb_user_t * user)4191fcced4cSJordan Brown smb_user_hold(smb_user_t *user)
4201fcced4cSJordan Brown {
4213b13a1efSThomas Keiser SMB_USER_VALID(user);
4221fcced4cSJordan Brown
4231fcced4cSJordan Brown mutex_enter(&user->u_mutex);
4241fcced4cSJordan Brown
42512b65585SGordon Ross if (user->u_state == SMB_USER_STATE_LOGGED_ON) {
4261fcced4cSJordan Brown user->u_refcnt++;
4271fcced4cSJordan Brown mutex_exit(&user->u_mutex);
4281fcced4cSJordan Brown return (B_TRUE);
4291fcced4cSJordan Brown }
4301fcced4cSJordan Brown
4311fcced4cSJordan Brown mutex_exit(&user->u_mutex);
4321fcced4cSJordan Brown return (B_FALSE);
4331fcced4cSJordan Brown }
4341fcced4cSJordan Brown
4353b13a1efSThomas Keiser /*
4363b13a1efSThomas Keiser * Unconditionally take a reference on a user.
4373b13a1efSThomas Keiser */
4383b13a1efSThomas Keiser void
smb_user_hold_internal(smb_user_t * user)4393b13a1efSThomas Keiser smb_user_hold_internal(smb_user_t *user)
4403b13a1efSThomas Keiser {
4413b13a1efSThomas Keiser SMB_USER_VALID(user);
4423b13a1efSThomas Keiser
4433b13a1efSThomas Keiser mutex_enter(&user->u_mutex);
4443b13a1efSThomas Keiser user->u_refcnt++;
4453b13a1efSThomas Keiser mutex_exit(&user->u_mutex);
4463b13a1efSThomas Keiser }
4473b13a1efSThomas Keiser
448da6c28aaSamw /*
4499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Release a reference on a user. If the reference count falls to
4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * zero and the user has logged off, post the object for deletion.
4519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Object deletion is deferred to avoid modifying a list while an
4529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * iteration may be in progress.
453da6c28aaSamw */
454da6c28aaSamw void
smb_user_release(smb_user_t * user)455da6c28aaSamw smb_user_release(
456da6c28aaSamw smb_user_t *user)
457da6c28aaSamw {
458811599a4SMatt Barden smb_session_t *ssn = user->u_session;
459811599a4SMatt Barden
460811599a4SMatt Barden SMB_USER_VALID(user);
461811599a4SMatt Barden
462811599a4SMatt Barden /* flush the tree list delete queue */
463811599a4SMatt Barden smb_llist_flush(&ssn->s_tree_list);
464da6c28aaSamw
465da6c28aaSamw mutex_enter(&user->u_mutex);
466da6c28aaSamw ASSERT(user->u_refcnt);
467da6c28aaSamw user->u_refcnt--;
468c5866007SKeyur Desai
469da6c28aaSamw switch (user->u_state) {
470811599a4SMatt Barden case SMB_USER_STATE_LOGGING_OFF:
471811599a4SMatt Barden if (user->u_refcnt == 0) {
472811599a4SMatt Barden smb_session_t *ssn = user->u_session;
473811599a4SMatt Barden user->u_state = SMB_USER_STATE_LOGGED_OFF;
474811599a4SMatt Barden smb_llist_post(&ssn->s_user_list, user,
475811599a4SMatt Barden smb_user_delete);
476811599a4SMatt Barden }
477da6c28aaSamw break;
478da6c28aaSamw
47912b65585SGordon Ross case SMB_USER_STATE_LOGGING_ON:
48012b65585SGordon Ross case SMB_USER_STATE_LOGGED_ON:
481da6c28aaSamw break;
482da6c28aaSamw
483811599a4SMatt Barden case SMB_USER_STATE_LOGGED_OFF:
484da6c28aaSamw default:
485da6c28aaSamw ASSERT(0);
486da6c28aaSamw break;
487da6c28aaSamw }
488da6c28aaSamw mutex_exit(&user->u_mutex);
489da6c28aaSamw }
490da6c28aaSamw
4918f70e16bSGordon Ross /*
4928f70e16bSGordon Ross * Timeout handler for user logons that stay too long in
4938f70e16bSGordon Ross * state SMB_USER_STATE_LOGGING_ON. This is setup by a
4948f70e16bSGordon Ross * timeout call in smb_authsock_open, and called in a
4958f70e16bSGordon Ross * callout thread, so schedule a taskq job to do the
4968f70e16bSGordon Ross * real work of logging off this user.
4978f70e16bSGordon Ross */
4988f70e16bSGordon Ross void
smb_user_auth_tmo(void * arg)4998f70e16bSGordon Ross smb_user_auth_tmo(void *arg)
5008f70e16bSGordon Ross {
5018f70e16bSGordon Ross smb_user_t *user = arg;
5028f70e16bSGordon Ross smb_request_t *sr;
5039788d6deSGordon Ross taskqid_t tqid;
5048f70e16bSGordon Ross
5058f70e16bSGordon Ross SMB_USER_VALID(user);
5068f70e16bSGordon Ross
5078f70e16bSGordon Ross /*
5088f70e16bSGordon Ross * If we can't allocate a request, it means the
5098f70e16bSGordon Ross * session is being torn down, so nothing to do.
5108f70e16bSGordon Ross */
5118f70e16bSGordon Ross sr = smb_request_alloc(user->u_session, 0);
5128f70e16bSGordon Ross if (sr == NULL)
5138f70e16bSGordon Ross return;
5148f70e16bSGordon Ross
5158f70e16bSGordon Ross /*
5168f70e16bSGordon Ross * Check user state, and take a hold if it's
5178f70e16bSGordon Ross * still logging on. If not, we're done.
5188f70e16bSGordon Ross */
5198f70e16bSGordon Ross mutex_enter(&user->u_mutex);
5208f70e16bSGordon Ross if (user->u_state != SMB_USER_STATE_LOGGING_ON) {
5218f70e16bSGordon Ross mutex_exit(&user->u_mutex);
5228f70e16bSGordon Ross smb_request_free(sr);
5238f70e16bSGordon Ross return;
5248f70e16bSGordon Ross }
5258f70e16bSGordon Ross /* smb_user_hold_internal */
5268f70e16bSGordon Ross user->u_refcnt++;
5278f70e16bSGordon Ross mutex_exit(&user->u_mutex);
5288f70e16bSGordon Ross
5298f70e16bSGordon Ross /*
5308f70e16bSGordon Ross * The user hold is given to the SR, and released in
5318f70e16bSGordon Ross * smb_user_logoff_tq / smb_request_free
5328f70e16bSGordon Ross */
5338f70e16bSGordon Ross sr->uid_user = user;
5348f70e16bSGordon Ross sr->user_cr = user->u_cred;
5358f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_SUBMITTED;
5369788d6deSGordon Ross tqid = taskq_dispatch(
5378f70e16bSGordon Ross user->u_server->sv_worker_pool,
5388f70e16bSGordon Ross smb_user_logoff_tq, sr, TQ_SLEEP);
5399788d6deSGordon Ross VERIFY(tqid != TASKQID_INVALID);
5408f70e16bSGordon Ross }
5418f70e16bSGordon Ross
5428f70e16bSGordon Ross /*
5438f70e16bSGordon Ross * Helper for smb_user_auth_tmo()
5448f70e16bSGordon Ross */
5458f70e16bSGordon Ross static void
smb_user_logoff_tq(void * arg)5468f70e16bSGordon Ross smb_user_logoff_tq(void *arg)
5478f70e16bSGordon Ross {
5488f70e16bSGordon Ross smb_request_t *sr = arg;
5498f70e16bSGordon Ross
5508f70e16bSGordon Ross SMB_REQ_VALID(sr);
5518f70e16bSGordon Ross
5528f70e16bSGordon Ross mutex_enter(&sr->sr_mutex);
5538f70e16bSGordon Ross sr->sr_worker = curthread;
5548f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE;
5558f70e16bSGordon Ross mutex_exit(&sr->sr_mutex);
5568f70e16bSGordon Ross
5578f70e16bSGordon Ross smb_user_logoff(sr->uid_user);
5588f70e16bSGordon Ross
5598f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED;
5608f70e16bSGordon Ross smb_request_free(sr);
5618f70e16bSGordon Ross }
5628f70e16bSGordon Ross
563c8ec8eeaSjose borrego /*
564c8ec8eeaSjose borrego * Determine whether or not the user is an administrator.
565c8ec8eeaSjose borrego * Members of the administrators group have administrative rights.
566c8ec8eeaSjose borrego */
567c8ec8eeaSjose borrego boolean_t
smb_user_is_admin(smb_user_t * user)568148c5f43SAlan Wright smb_user_is_admin(smb_user_t *user)
569c8ec8eeaSjose borrego {
570b819cea2SGordon Ross #ifdef _KERNEL
571148c5f43SAlan Wright char sidstr[SMB_SID_STRSZ];
572148c5f43SAlan Wright ksidlist_t *ksidlist;
573f37b3cbbSMatt Barden ksid_t *ksid;
574f37b3cbbSMatt Barden uint32_t rid;
575f37b3cbbSMatt Barden int ret;
576b819cea2SGordon Ross #endif /* _KERNEL */
577b819cea2SGordon Ross boolean_t rc = B_FALSE;
578c8ec8eeaSjose borrego
579c8ec8eeaSjose borrego ASSERT(user);
580148c5f43SAlan Wright ASSERT(user->u_cred);
581c8ec8eeaSjose borrego
582148c5f43SAlan Wright if (SMB_USER_IS_ADMIN(user))
583c8ec8eeaSjose borrego return (B_TRUE);
584c8ec8eeaSjose borrego
585b819cea2SGordon Ross #ifdef _KERNEL
586148c5f43SAlan Wright (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
587f37b3cbbSMatt Barden ret = smb_sid_splitstr(sidstr, &rid);
588f37b3cbbSMatt Barden ASSERT3S(ret, ==, 0);
589148c5f43SAlan Wright
590148c5f43SAlan Wright ksidlist = crgetsidlist(user->u_cred);
591148c5f43SAlan Wright ASSERT(ksidlist);
592148c5f43SAlan Wright
593f37b3cbbSMatt Barden ksid = crgetsid(user->u_cred, KSID_USER);
594f37b3cbbSMatt Barden ASSERT(ksid != NULL);
595f37b3cbbSMatt Barden ASSERT(ksid->ks_domain != NULL);
596f37b3cbbSMatt Barden ASSERT(ksid->ks_domain->kd_name != NULL);
597f37b3cbbSMatt Barden
598f37b3cbbSMatt Barden if ((rid == ksid->ks_rid &&
599f37b3cbbSMatt Barden strcmp(sidstr, ksid_getdomain(ksid)) == 0) ||
600f37b3cbbSMatt Barden ksidlist_has_sid(ksidlist, sidstr, rid)) {
601f37b3cbbSMatt Barden user->u_flags |= SMB_USER_FLAG_ADMIN;
602f37b3cbbSMatt Barden rc = B_TRUE;
603f37b3cbbSMatt Barden }
604148c5f43SAlan Wright
605b819cea2SGordon Ross #endif /* _KERNEL */
606148c5f43SAlan Wright return (rc);
607c8ec8eeaSjose borrego }
608c8ec8eeaSjose borrego
6091fcced4cSJordan Brown /*
6101fcced4cSJordan Brown * This function should be called with a hold on the user.
6111fcced4cSJordan Brown */
6121fcced4cSJordan Brown boolean_t
smb_user_namecmp(smb_user_t * user,const char * name)6131fcced4cSJordan Brown smb_user_namecmp(smb_user_t *user, const char *name)
6141fcced4cSJordan Brown {
6151fcced4cSJordan Brown char *fq_name;
6161fcced4cSJordan Brown boolean_t match;
6171fcced4cSJordan Brown
618bbf6f00cSJordan Brown if (smb_strcasecmp(name, user->u_name, 0) == 0)
6191fcced4cSJordan Brown return (B_TRUE);
6201fcced4cSJordan Brown
6211fcced4cSJordan Brown fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
6221fcced4cSJordan Brown
6231fcced4cSJordan Brown (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
6241fcced4cSJordan Brown user->u_domain, user->u_name);
6251fcced4cSJordan Brown
626bbf6f00cSJordan Brown match = (smb_strcasecmp(name, fq_name, 0) == 0);
6271fcced4cSJordan Brown if (!match) {
6281fcced4cSJordan Brown (void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
6291fcced4cSJordan Brown user->u_name, user->u_domain);
6301fcced4cSJordan Brown
631bbf6f00cSJordan Brown match = (smb_strcasecmp(name, fq_name, 0) == 0);
6321fcced4cSJordan Brown }
6331fcced4cSJordan Brown
6341fcced4cSJordan Brown kmem_free(fq_name, MAXNAMELEN);
6351fcced4cSJordan Brown return (match);
6361fcced4cSJordan Brown }
6371fcced4cSJordan Brown
6381fcced4cSJordan Brown /*
6391fcced4cSJordan Brown * If the enumeration request is for user data, handle the request
6401fcced4cSJordan Brown * here. Otherwise, pass it on to the trees.
6411fcced4cSJordan Brown *
6421fcced4cSJordan Brown * This function should be called with a hold on the user.
6431fcced4cSJordan Brown */
6441fcced4cSJordan Brown int
smb_user_enum(smb_user_t * user,smb_svcenum_t * svcenum)6451fcced4cSJordan Brown smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
6461fcced4cSJordan Brown {
6473b13a1efSThomas Keiser int rc = 0;
6481fcced4cSJordan Brown
6491fcced4cSJordan Brown ASSERT(user);
6501fcced4cSJordan Brown ASSERT(user->u_magic == SMB_USER_MAGIC);
6511fcced4cSJordan Brown
6521fcced4cSJordan Brown if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
6531fcced4cSJordan Brown return (smb_user_enum_private(user, svcenum));
6541fcced4cSJordan Brown
6551fcced4cSJordan Brown return (rc);
6561fcced4cSJordan Brown }
6571fcced4cSJordan Brown
6581baeef30SPrashanth Badari /*
6591baeef30SPrashanth Badari * Count references by trees this user owns,
6601baeef30SPrashanth Badari * and allow waiting for them to go away.
6611baeef30SPrashanth Badari */
6621baeef30SPrashanth Badari void
smb_user_inc_trees(smb_user_t * user)6631baeef30SPrashanth Badari smb_user_inc_trees(smb_user_t *user)
6641baeef30SPrashanth Badari {
6651baeef30SPrashanth Badari mutex_enter(&user->u_mutex);
6661baeef30SPrashanth Badari user->u_owned_tree_cnt++;
6671baeef30SPrashanth Badari mutex_exit(&user->u_mutex);
6681baeef30SPrashanth Badari }
6691baeef30SPrashanth Badari
6701baeef30SPrashanth Badari void
smb_user_dec_trees(smb_user_t * user)6711baeef30SPrashanth Badari smb_user_dec_trees(smb_user_t *user)
6721baeef30SPrashanth Badari {
6731baeef30SPrashanth Badari mutex_enter(&user->u_mutex);
6741baeef30SPrashanth Badari user->u_owned_tree_cnt--;
6751baeef30SPrashanth Badari if (user->u_owned_tree_cnt == 0)
6761baeef30SPrashanth Badari cv_broadcast(&user->u_owned_tree_cv);
6771baeef30SPrashanth Badari mutex_exit(&user->u_mutex);
6781baeef30SPrashanth Badari }
6791baeef30SPrashanth Badari
6801baeef30SPrashanth Badari int smb_user_wait_tree_tmo = 30;
6811baeef30SPrashanth Badari
6821baeef30SPrashanth Badari /*
6831baeef30SPrashanth Badari * Wait (up to 30 sec.) for trees to go away.
6841baeef30SPrashanth Badari * Should happen in less than a second.
6851baeef30SPrashanth Badari */
6861baeef30SPrashanth Badari void
smb_user_wait_trees(smb_user_t * user)6871baeef30SPrashanth Badari smb_user_wait_trees(smb_user_t *user)
6881baeef30SPrashanth Badari {
6891baeef30SPrashanth Badari clock_t time;
6901baeef30SPrashanth Badari
6911baeef30SPrashanth Badari time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt();
6921baeef30SPrashanth Badari mutex_enter(&user->u_mutex);
6931baeef30SPrashanth Badari while (user->u_owned_tree_cnt != 0) {
6941baeef30SPrashanth Badari if (cv_timedwait(&user->u_owned_tree_cv,
6951baeef30SPrashanth Badari &user->u_mutex, time) < 0)
6961baeef30SPrashanth Badari break;
6971baeef30SPrashanth Badari }
6981baeef30SPrashanth Badari mutex_exit(&user->u_mutex);
6991baeef30SPrashanth Badari if (user->u_owned_tree_cnt != 0) {
70086184067SGordon Ross #ifdef DEBUG
70186184067SGordon Ross cmn_err(CE_NOTE, "!smb_user_wait_trees failed");
7021baeef30SPrashanth Badari #endif
70386184067SGordon Ross DTRACE_PROBE1(max__wait, smb_user_t *, user);
70486184067SGordon Ross }
7051baeef30SPrashanth Badari }
7061baeef30SPrashanth Badari
707da6c28aaSamw /* *************************** Static Functions ***************************** */
708da6c28aaSamw
709da6c28aaSamw /*
7109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Delete a user. The tree list should be empty.
7119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States *
7129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Remove the user from the session's user list before freeing resources
7139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * associated with the user.
714da6c28aaSamw */
715811599a4SMatt Barden static void
smb_user_delete(void * arg)7169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_delete(void *arg)
717da6c28aaSamw {
718da6c28aaSamw smb_session_t *session;
7199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t *user = (smb_user_t *)arg;
720811599a4SMatt Barden uint32_t ucount;
721da6c28aaSamw
7229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_USER_VALID(user);
723da6c28aaSamw ASSERT(user->u_refcnt == 0);
724da6c28aaSamw ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
72512b65585SGordon Ross ASSERT(user->u_authsock == NULL);
7268f70e16bSGordon Ross ASSERT(user->u_auth_tmo == NULL);
727da6c28aaSamw
728da6c28aaSamw session = user->u_session;
729811599a4SMatt Barden
730811599a4SMatt Barden smb_server_dec_users(session->s_server);
731da6c28aaSamw smb_llist_enter(&session->s_user_list, RW_WRITER);
732da6c28aaSamw smb_llist_remove(&session->s_user_list, user);
7339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_idpool_free(&session->s_uid_pool, user->u_uid);
734811599a4SMatt Barden ucount = smb_llist_get_count(&session->s_user_list);
735da6c28aaSamw smb_llist_exit(&session->s_user_list);
736da6c28aaSamw
737817fa55fSGordon Ross /*
738817fa55fSGordon Ross * When the last smb_user_t object goes away, schedule a timeout
739817fa55fSGordon Ross * after which we'll terminate this session if the client hasn't
740817fa55fSGordon Ross * authenticated another smb_user_t on this session by then.
741817fa55fSGordon Ross */
742811599a4SMatt Barden if (ucount == 0) {
743811599a4SMatt Barden smb_rwx_rwenter(&session->s_lock, RW_WRITER);
744817fa55fSGordon Ross if (session->s_state == SMB_SESSION_STATE_NEGOTIATED &&
745817fa55fSGordon Ross session->s_auth_tmo == NULL) {
746817fa55fSGordon Ross session->s_auth_tmo =
747817fa55fSGordon Ross timeout((tmo_func_t)smb_session_disconnect,
748817fa55fSGordon Ross session, SEC_TO_TICK(smb_session_auth_tmo));
749817fa55fSGordon Ross }
750811599a4SMatt Barden smb_rwx_cvbcast(&session->s_lock);
751811599a4SMatt Barden smb_rwx_rwexit(&session->s_lock);
752811599a4SMatt Barden }
753811599a4SMatt Barden
754811599a4SMatt Barden /*
755811599a4SMatt Barden * This user is no longer on s_user_list, however...
756811599a4SMatt Barden *
757811599a4SMatt Barden * This is called via smb_llist_post, which means it may run
758811599a4SMatt Barden * BEFORE smb_user_release drops u_mutex (if another thread
759811599a4SMatt Barden * flushes the delete queue before we do). Synchronize.
760811599a4SMatt Barden */
7619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&user->u_mutex);
7629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&user->u_mutex);
7639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
764da6c28aaSamw user->u_magic = (uint32_t)~SMB_USER_MAGIC;
765da6c28aaSamw mutex_destroy(&user->u_mutex);
766148c5f43SAlan Wright if (user->u_cred)
767148c5f43SAlan Wright crfree(user->u_cred);
768b89a8333Snatalie li - Sun Microsystems - Irvine United States if (user->u_privcred)
769b89a8333Snatalie li - Sun Microsystems - Irvine United States crfree(user->u_privcred);
7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(user->u_name);
7719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(user->u_domain);
7728622ec45SGordon Ross kmem_cache_free(smb_cache_user, user);
773da6c28aaSamw }
774c8ec8eeaSjose borrego
775b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
smb_user_getcred(smb_user_t * user)776b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getcred(smb_user_t *user)
777b89a8333Snatalie li - Sun Microsystems - Irvine United States {
778b89a8333Snatalie li - Sun Microsystems - Irvine United States return (user->u_cred);
779b89a8333Snatalie li - Sun Microsystems - Irvine United States }
780b89a8333Snatalie li - Sun Microsystems - Irvine United States
781b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t *
smb_user_getprivcred(smb_user_t * user)782b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getprivcred(smb_user_t *user)
783b89a8333Snatalie li - Sun Microsystems - Irvine United States {
784b89a8333Snatalie li - Sun Microsystems - Irvine United States return ((user->u_privcred)? user->u_privcred : user->u_cred);
785b89a8333Snatalie li - Sun Microsystems - Irvine United States }
7861fcced4cSJordan Brown
787b819cea2SGordon Ross #ifdef _KERNEL
788148c5f43SAlan Wright /*
789148c5f43SAlan Wright * Assign the user cred and privileges.
790148c5f43SAlan Wright *
791148c5f43SAlan Wright * If the user has backup and/or restore privleges, dup the cred
792148c5f43SAlan Wright * and add those privileges to this new privileged cred.
793148c5f43SAlan Wright */
794b819cea2SGordon Ross void
smb_user_setcred(smb_user_t * user,cred_t * cr,uint32_t privileges)795148c5f43SAlan Wright smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
796148c5f43SAlan Wright {
797148c5f43SAlan Wright cred_t *privcred = NULL;
798148c5f43SAlan Wright
799148c5f43SAlan Wright ASSERT(cr);
800148c5f43SAlan Wright crhold(cr);
801148c5f43SAlan Wright
8020292c176SMatt Barden /*
8030292c176SMatt Barden * See smb.4 bypass_traverse_checking
8040292c176SMatt Barden *
8050292c176SMatt Barden * For historical reasons, the Windows privilege is named
8060292c176SMatt Barden * SeChangeNotifyPrivilege, though the description is
8070292c176SMatt Barden * "Bypass traverse checking".
8080292c176SMatt Barden */
8090292c176SMatt Barden if ((privileges & SMB_USER_PRIV_CHANGE_NOTIFY) != 0) {
8100292c176SMatt Barden (void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL);
8110292c176SMatt Barden }
8120292c176SMatt Barden
8130292c176SMatt Barden /*
8140292c176SMatt Barden * Window's "take ownership privilege" is similar to our
8150292c176SMatt Barden * PRIV_FILE_CHOWN privilege. It's normally given to members of the
8160292c176SMatt Barden * "Administrators" group, which normally includes the the local
8170292c176SMatt Barden * Administrator (like root) and when joined to a domain,
8180292c176SMatt Barden * "Domain Admins".
8190292c176SMatt Barden */
8200292c176SMatt Barden if ((privileges & SMB_USER_PRIV_TAKE_OWNERSHIP) != 0) {
8210292c176SMatt Barden (void) crsetpriv(cr,
8220292c176SMatt Barden PRIV_FILE_CHOWN,
8230292c176SMatt Barden PRIV_FILE_CHOWN_SELF,
8240292c176SMatt Barden NULL);
8250292c176SMatt Barden }
8260292c176SMatt Barden
8270292c176SMatt Barden /*
8280292c176SMatt Barden * Bypass ACL for READ accesses.
8290292c176SMatt Barden */
8300292c176SMatt Barden if ((privileges & SMB_USER_PRIV_READ_FILE) != 0) {
8310292c176SMatt Barden (void) crsetpriv(cr, PRIV_FILE_DAC_READ, NULL);
8320292c176SMatt Barden }
8330292c176SMatt Barden
8340292c176SMatt Barden /*
8350292c176SMatt Barden * Bypass ACL for WRITE accesses.
8360292c176SMatt Barden * Include FILE_OWNER, as it covers WRITE_ACL and DELETE.
8370292c176SMatt Barden */
8380292c176SMatt Barden if ((privileges & SMB_USER_PRIV_WRITE_FILE) != 0) {
8390292c176SMatt Barden (void) crsetpriv(cr,
8400292c176SMatt Barden PRIV_FILE_DAC_WRITE,
8410292c176SMatt Barden PRIV_FILE_OWNER,
8420292c176SMatt Barden NULL);
8430292c176SMatt Barden }
8440292c176SMatt Barden
8450292c176SMatt Barden /*
8460292c176SMatt Barden * These privileges are used only when a file is opened with
8470292c176SMatt Barden * 'backup intent'. These allow users to bypass certain access
8480292c176SMatt Barden * controls. Administrators typically have these privileges,
8490292c176SMatt Barden * and they are used during recursive take-ownership operations.
8500292c176SMatt Barden * Some commonly used tools use 'backup intent' to administrate
8510292c176SMatt Barden * files that do not grant explicit permissions to Administrators.
8520292c176SMatt Barden */
853148c5f43SAlan Wright if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
854148c5f43SAlan Wright privcred = crdup(cr);
855148c5f43SAlan Wright
856148c5f43SAlan Wright if (privcred != NULL) {
857148c5f43SAlan Wright if (privileges & SMB_USER_PRIV_BACKUP) {
858148c5f43SAlan Wright (void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
859148c5f43SAlan Wright PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
860148c5f43SAlan Wright }
861148c5f43SAlan Wright
862148c5f43SAlan Wright if (privileges & SMB_USER_PRIV_RESTORE) {
863148c5f43SAlan Wright (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
864148c5f43SAlan Wright PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
865148c5f43SAlan Wright PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
866148c5f43SAlan Wright PRIV_FILE_OWNER, PRIV_FILE_SETID,
867148c5f43SAlan Wright PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
868148c5f43SAlan Wright }
869148c5f43SAlan Wright }
870148c5f43SAlan Wright
871148c5f43SAlan Wright user->u_cred = cr;
872148c5f43SAlan Wright user->u_privcred = privcred;
873148c5f43SAlan Wright user->u_privileges = privileges;
874148c5f43SAlan Wright }
875b819cea2SGordon Ross #endif /* _KERNEL */
876148c5f43SAlan Wright
8779e3ab9e9SMatt Barden /*
8789e3ab9e9SMatt Barden * Determines whether a user can be granted ACCESS_SYSTEM_SECURITY
8799e3ab9e9SMatt Barden */
8809e3ab9e9SMatt Barden boolean_t
smb_user_has_security_priv(smb_user_t * user,cred_t * cr)8819e3ab9e9SMatt Barden smb_user_has_security_priv(smb_user_t *user, cred_t *cr)
8829e3ab9e9SMatt Barden {
8839e3ab9e9SMatt Barden /* Need SeSecurityPrivilege to get/set SACL */
8849e3ab9e9SMatt Barden if ((user->u_privileges & SMB_USER_PRIV_SECURITY) != 0)
8859e3ab9e9SMatt Barden return (B_TRUE);
8869e3ab9e9SMatt Barden
8879e3ab9e9SMatt Barden #ifdef _KERNEL
8889e3ab9e9SMatt Barden /*
8899e3ab9e9SMatt Barden * ACCESS_SYSTEM_SECURITY is also granted if the file is opened with
8909e3ab9e9SMatt Barden * BACKUP/RESTORE intent by a user with BACKUP/RESTORE privilege,
8919e3ab9e9SMatt Barden * which means we'll be using u_privcred.
8929e3ab9e9SMatt Barden *
8939e3ab9e9SMatt Barden * We translate BACKUP as DAC_READ and RESTORE as DAC_WRITE,
8949e3ab9e9SMatt Barden * to account for our various SMB_USER_* privileges.
8959e3ab9e9SMatt Barden */
8969e3ab9e9SMatt Barden if (PRIV_POLICY_ONLY(cr,
8979e3ab9e9SMatt Barden priv_getbyname(PRIV_FILE_DAC_READ, 0), B_FALSE) ||
8989e3ab9e9SMatt Barden PRIV_POLICY_ONLY(cr,
8999e3ab9e9SMatt Barden priv_getbyname(PRIV_FILE_DAC_WRITE, 0), B_FALSE))
9009e3ab9e9SMatt Barden return (B_TRUE);
9019e3ab9e9SMatt Barden #else
9029e3ab9e9SMatt Barden /*
9039e3ab9e9SMatt Barden * No "real" privileges in fksmbsrv, so use the SMB privs instead.
9049e3ab9e9SMatt Barden */
9059e3ab9e9SMatt Barden if ((user->u_privileges &
9069e3ab9e9SMatt Barden (SMB_USER_PRIV_BACKUP |
9079e3ab9e9SMatt Barden SMB_USER_PRIV_RESTORE |
9089e3ab9e9SMatt Barden SMB_USER_PRIV_READ_FILE |
9099e3ab9e9SMatt Barden SMB_USER_PRIV_WRITE_FILE)) != 0)
9109e3ab9e9SMatt Barden return (B_TRUE);
9119e3ab9e9SMatt Barden #endif
9129e3ab9e9SMatt Barden
9139e3ab9e9SMatt Barden return (B_FALSE);
9149e3ab9e9SMatt Barden }
9159e3ab9e9SMatt Barden
9161fcced4cSJordan Brown /*
9171fcced4cSJordan Brown * Private function to support smb_user_enum.
9181fcced4cSJordan Brown */
9191fcced4cSJordan Brown static int
smb_user_enum_private(smb_user_t * user,smb_svcenum_t * svcenum)9201fcced4cSJordan Brown smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
9211fcced4cSJordan Brown {
9221fcced4cSJordan Brown uint8_t *pb;
9231fcced4cSJordan Brown uint_t nbytes;
9241fcced4cSJordan Brown int rc;
9251fcced4cSJordan Brown
9261fcced4cSJordan Brown if (svcenum->se_nskip > 0) {
9271fcced4cSJordan Brown svcenum->se_nskip--;
9281fcced4cSJordan Brown return (0);
9291fcced4cSJordan Brown }
9301fcced4cSJordan Brown
9311fcced4cSJordan Brown if (svcenum->se_nitems >= svcenum->se_nlimit) {
9321fcced4cSJordan Brown svcenum->se_nitems = svcenum->se_nlimit;
9331fcced4cSJordan Brown return (0);
9341fcced4cSJordan Brown }
9351fcced4cSJordan Brown
9361fcced4cSJordan Brown pb = &svcenum->se_buf[svcenum->se_bused];
9371fcced4cSJordan Brown rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
9381fcced4cSJordan Brown if (rc == 0) {
9391fcced4cSJordan Brown svcenum->se_bavail -= nbytes;
9401fcced4cSJordan Brown svcenum->se_bused += nbytes;
9411fcced4cSJordan Brown svcenum->se_nitems++;
9421fcced4cSJordan Brown }
9431fcced4cSJordan Brown
9441fcced4cSJordan Brown return (rc);
9451fcced4cSJordan Brown }
9461fcced4cSJordan Brown
9471fcced4cSJordan Brown /*
9481fcced4cSJordan Brown * Encode the NetInfo for a user into a buffer. NetInfo contains
9491fcced4cSJordan Brown * information that is often needed in user space to support RPC
9501fcced4cSJordan Brown * requests.
9511fcced4cSJordan Brown */
9521fcced4cSJordan Brown int
smb_user_netinfo_encode(smb_user_t * user,uint8_t * buf,size_t buflen,uint32_t * nbytes)9531fcced4cSJordan Brown smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
9541fcced4cSJordan Brown uint32_t *nbytes)
9551fcced4cSJordan Brown {
9561fcced4cSJordan Brown smb_netuserinfo_t info;
9571fcced4cSJordan Brown int rc;
9581fcced4cSJordan Brown
9591fcced4cSJordan Brown smb_user_netinfo_init(user, &info);
9601fcced4cSJordan Brown rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
9611fcced4cSJordan Brown smb_user_netinfo_fini(&info);
9621fcced4cSJordan Brown
9631fcced4cSJordan Brown return (rc);
9641fcced4cSJordan Brown }
9651fcced4cSJordan Brown
9661fcced4cSJordan Brown void
smb_user_netinfo_init(smb_user_t * user,smb_netuserinfo_t * info)9671fcced4cSJordan Brown smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
9681fcced4cSJordan Brown {
9691fcced4cSJordan Brown smb_session_t *session;
9701fcced4cSJordan Brown char *buf;
9711fcced4cSJordan Brown
9721fcced4cSJordan Brown ASSERT(user);
9731fcced4cSJordan Brown ASSERT(user->u_domain);
9741fcced4cSJordan Brown ASSERT(user->u_name);
9751fcced4cSJordan Brown
9761fcced4cSJordan Brown session = user->u_session;
9771fcced4cSJordan Brown ASSERT(session);
9781fcced4cSJordan Brown ASSERT(session->workstation);
9791fcced4cSJordan Brown
9801fcced4cSJordan Brown info->ui_session_id = session->s_kid;
98197264293SGordon Ross info->ui_user_id = user->u_ssnid;
9821fcced4cSJordan Brown info->ui_native_os = session->native_os;
9831fcced4cSJordan Brown info->ui_ipaddr = session->ipaddr;
9841fcced4cSJordan Brown info->ui_numopens = session->s_file_cnt;
9851fcced4cSJordan Brown info->ui_logon_time = user->u_logon_time;
9861fcced4cSJordan Brown info->ui_flags = user->u_flags;
987c5866007SKeyur Desai info->ui_posix_uid = crgetuid(user->u_cred);
9881fcced4cSJordan Brown
9891fcced4cSJordan Brown info->ui_domain_len = user->u_domain_len;
9909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_domain = smb_mem_strdup(user->u_domain);
9911fcced4cSJordan Brown
9921fcced4cSJordan Brown info->ui_account_len = user->u_name_len;
9939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_account = smb_mem_strdup(user->u_name);
9941fcced4cSJordan Brown
9951fcced4cSJordan Brown buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
9961fcced4cSJordan Brown smb_session_getclient(session, buf, MAXNAMELEN);
9971fcced4cSJordan Brown info->ui_workstation_len = strlen(buf) + 1;
9989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_workstation = smb_mem_strdup(buf);
9991fcced4cSJordan Brown kmem_free(buf, MAXNAMELEN);
10001fcced4cSJordan Brown }
10011fcced4cSJordan Brown
10021fcced4cSJordan Brown void
smb_user_netinfo_fini(smb_netuserinfo_t * info)10031fcced4cSJordan Brown smb_user_netinfo_fini(smb_netuserinfo_t *info)
10041fcced4cSJordan Brown {
10051fcced4cSJordan Brown if (info == NULL)
10061fcced4cSJordan Brown return;
10071fcced4cSJordan Brown
10081fcced4cSJordan Brown if (info->ui_domain)
10099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_domain);
10101fcced4cSJordan Brown if (info->ui_account)
10119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_account);
10121fcced4cSJordan Brown if (info->ui_workstation)
10139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_workstation);
10141fcced4cSJordan Brown
10151fcced4cSJordan Brown bzero(info, sizeof (smb_netuserinfo_t));
10161fcced4cSJordan Brown }
10179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
1018*a9609934SGordon Ross uint64_t smb_user_auth_logoff_failures;
1019*a9609934SGordon Ross
1020811599a4SMatt Barden /*
1021811599a4SMatt Barden * Tell smbd this user is going away so it can clean up their
1022811599a4SMatt Barden * audit session, autohome dir, etc.
1023811599a4SMatt Barden *
1024811599a4SMatt Barden * Note that when we're shutting down, smbd will already have set
1025811599a4SMatt Barden * smbd.s_shutting_down and therefore will ignore door calls.
1026811599a4SMatt Barden * Skip this during shutdown to reduce upcall noise.
1027811599a4SMatt Barden */
10289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_user_auth_logoff(smb_user_t * user)10298622ec45SGordon Ross smb_user_auth_logoff(smb_user_t *user)
10309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
1031811599a4SMatt Barden smb_server_t *sv = user->u_server;
1032811599a4SMatt Barden uint32_t audit_sid;
1033811599a4SMatt Barden
1034811599a4SMatt Barden if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
1035811599a4SMatt Barden return;
10368622ec45SGordon Ross
1037*a9609934SGordon Ross if (smb_threshold_enter(&sv->sv_logoff_ct) != 0) {
1038*a9609934SGordon Ross smb_user_auth_logoff_failures++;
1039*a9609934SGordon Ross return;
1040*a9609934SGordon Ross }
1041*a9609934SGordon Ross
1042811599a4SMatt Barden audit_sid = user->u_audit_sid;
1043811599a4SMatt Barden (void) smb_kdoor_upcall(sv, SMB_DR_USER_AUTH_LOGOFF,
10449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States &audit_sid, xdr_uint32_t, NULL, NULL);
1045*a9609934SGordon Ross
1046*a9609934SGordon Ross smb_threshold_exit(&sv->sv_logoff_ct);
10479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1048811599a4SMatt Barden
1049811599a4SMatt Barden boolean_t
smb_is_same_user(cred_t * cr1,cred_t * cr2)1050811599a4SMatt Barden smb_is_same_user(cred_t *cr1, cred_t *cr2)
1051811599a4SMatt Barden {
1052811599a4SMatt Barden ksid_t *ks1 = crgetsid(cr1, KSID_USER);
1053811599a4SMatt Barden ksid_t *ks2 = crgetsid(cr2, KSID_USER);
1054811599a4SMatt Barden
1055bf996dbcSPrashanth Badari if (ks1 == NULL || ks2 == NULL) {
1056bf996dbcSPrashanth Badari return (B_FALSE);
1057bf996dbcSPrashanth Badari }
1058811599a4SMatt Barden return (ks1->ks_rid == ks2->ks_rid &&
1059811599a4SMatt Barden strcmp(ks1->ks_domain->kd_name, ks2->ks_domain->kd_name) == 0);
1060811599a4SMatt Barden }
1061