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. 230292c176SMatt Barden * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. 2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 25da6c28aaSamw */ 26da6c28aaSamw 27da6c28aaSamw /* 28da6c28aaSamw * General Structures Layout 29da6c28aaSamw * ------------------------- 30da6c28aaSamw * 31da6c28aaSamw * This is a simplified diagram showing the relationship between most of the 32da6c28aaSamw * main structures. 33da6c28aaSamw * 34da6c28aaSamw * +-------------------+ 35da6c28aaSamw * | SMB_INFO | 36da6c28aaSamw * +-------------------+ 37da6c28aaSamw * | 38da6c28aaSamw * | 39da6c28aaSamw * v 40da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 41da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION | 42da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 433b13a1efSThomas Keiser * | | 443b13a1efSThomas Keiser * | | 453b13a1efSThomas Keiser * | v 463b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 473b13a1efSThomas Keiser * | | USER |<--->| USER |...| USER | 483b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 49da6c28aaSamw * | 50da6c28aaSamw * | 51da6c28aaSamw * v 52da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 53da6c28aaSamw * | TREE |<----->| TREE |......| TREE | 54da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 55da6c28aaSamw * | | 56da6c28aaSamw * | | 57da6c28aaSamw * | v 58da6c28aaSamw * | +-------+ +-------+ +-------+ 59da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE | 60da6c28aaSamw * | +-------+ +-------+ +-------+ 61da6c28aaSamw * | 62da6c28aaSamw * | 63da6c28aaSamw * v 64da6c28aaSamw * +-------+ +------+ +------+ 65da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR | 66da6c28aaSamw * +-------+ +------+ +------+ 67da6c28aaSamw * 68da6c28aaSamw * 69da6c28aaSamw * User State Machine 70da6c28aaSamw * ------------------ 71da6c28aaSamw * 7212b65585SGordon Ross * 7312b65585SGordon Ross * | T0: Creation/Allocation 7412b65585SGordon Ross * | (1st session setup) 7512b65585SGordon Ross * v 7612b65585SGordon Ross * +-----------------------------+ 7712b65585SGordon Ross * | SMB_USER_STATE_LOGGING_ON |<----------+ 7812b65585SGordon Ross * +-----------------------------+ addl. session setup 7912b65585SGordon Ross * | | (more proc. required) 8012b65585SGordon Ross * | T2 | ^ 8112b65585SGordon Ross * | | | T1: (cont.) 8212b65585SGordon Ross * | +------->-------? 8312b65585SGordon Ross * v | T3: (fail) 8412b65585SGordon Ross * +-----------------------------+ v 8512b65585SGordon Ross * | SMB_USER_STATE_LOGGED_ON | (logged off) 86da6c28aaSamw * +-----------------------------+ 87da6c28aaSamw * | 8812b65585SGordon Ross * | T4 89da6c28aaSamw * | 90da6c28aaSamw * v 91da6c28aaSamw * +-----------------------------+ 92da6c28aaSamw * | SMB_USER_STATE_LOGGING_OFF | 93da6c28aaSamw * +-----------------------------+ 94da6c28aaSamw * | 9512b65585SGordon Ross * | T5 96da6c28aaSamw * | 97da6c28aaSamw * v 9812b65585SGordon Ross * +-----------------------------+ T6 99da6c28aaSamw * | SMB_USER_STATE_LOGGED_OFF |----------> Deletion/Free 100da6c28aaSamw * +-----------------------------+ 101da6c28aaSamw * 10212b65585SGordon Ross * SMB_USER_STATE_LOGGING_ON 103da6c28aaSamw * 104da6c28aaSamw * While in this state: 10548bbca81SDaniel Hoffman * - The user is in the list of users for their session. 10612b65585SGordon Ross * - References will be given out ONLY for session setup. 10712b65585SGordon Ross * - This user can not access anything yet. 10812b65585SGordon Ross * 10912b65585SGordon Ross * SMB_USER_STATE_LOGGED_ON 11012b65585SGordon Ross * 11112b65585SGordon Ross * While in this state: 11248bbca81SDaniel Hoffman * - The user is in the list of users for their session. 113da6c28aaSamw * - References will be given out if the user is looked up. 114da6c28aaSamw * - The user can access files and pipes. 115da6c28aaSamw * 116da6c28aaSamw * SMB_USER_STATE_LOGGING_OFF 117da6c28aaSamw * 118da6c28aaSamw * While in this state: 11948bbca81SDaniel Hoffman * - The user is in the list of users for their session. 120da6c28aaSamw * - References will not be given out if the user is looked up. 121da6c28aaSamw * - The trees the user connected are being disconnected. 122da6c28aaSamw * - The resources associated with the user remain. 123da6c28aaSamw * 12412b65585SGordon Ross * SMB_USER_STATE_LOGGED_OFF 125da6c28aaSamw * 126da6c28aaSamw * While in this state: 12748bbca81SDaniel Hoffman * - The user is queued in the list of users of their session. 128da6c28aaSamw * - References will not be given out if the user is looked up. 129da6c28aaSamw * - The user has no more trees connected. 130da6c28aaSamw * - The resources associated with the user remain. 131da6c28aaSamw * 132da6c28aaSamw * Transition T0 133da6c28aaSamw * 13412b65585SGordon Ross * First request in an SMB Session Setup sequence creates a 13512b65585SGordon Ross * new user object and adds it to the list of users for 13612b65585SGordon Ross * this session. User UID is assigned and returned. 137da6c28aaSamw * 138da6c28aaSamw * Transition T1 139da6c28aaSamw * 14012b65585SGordon Ross * Subsequent SMB Session Setup requests (on the same UID 14112b65585SGordon Ross * assigned in T0) update the state of this user object, 14212b65585SGordon Ross * communicating with smbd for the crypto work. 143da6c28aaSamw * 144da6c28aaSamw * Transition T2 145da6c28aaSamw * 14612b65585SGordon Ross * If the SMB Session Setup sequence is successful, T2 14712b65585SGordon Ross * makes the new user object available for requests. 14812b65585SGordon Ross * 14912b65585SGordon Ross * Transition T3 15012b65585SGordon Ross * 15112b65585SGordon Ross * If an Session Setup request gets an error other than 15212b65585SGordon Ross * the expected "more processing required", then T3 15312b65585SGordon Ross * leads to state "LOGGED_OFF" and then tear-down of the 15412b65585SGordon Ross * partially constructed user. 15512b65585SGordon Ross * 15612b65585SGordon Ross * Transition T4 15712b65585SGordon Ross * 15812b65585SGordon Ross * Normal SMB User Logoff request, or session tear-down. 15912b65585SGordon Ross * 16012b65585SGordon Ross * Transition T5 16112b65585SGordon Ross * 162da6c28aaSamw * This transition occurs in smb_user_release(). The resources associated 163da6c28aaSamw * with the user are deleted as well as the user. For the transition to 164da6c28aaSamw * occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the 165da6c28aaSamw * reference count be zero. 166da6c28aaSamw * 167da6c28aaSamw * Comments 168da6c28aaSamw * -------- 169da6c28aaSamw * 170da6c28aaSamw * The state machine of the user structures is controlled by 3 elements: 17148bbca81SDaniel Hoffman * - The list of users of the session they belong to. 172da6c28aaSamw * - The mutex embedded in the structure itself. 173da6c28aaSamw * - The reference count. 174da6c28aaSamw * 175da6c28aaSamw * There's a mutex embedded in the user structure used to protect its fields 176da6c28aaSamw * and there's a lock embedded in the list of users of a session. To 177da6c28aaSamw * increment or to decrement the reference count the mutex must be entered. 178da6c28aaSamw * To insert the user into the list of users of the session and to remove 179da6c28aaSamw * the user from it, the lock must be entered in RW_WRITER mode. 180da6c28aaSamw * 181da6c28aaSamw * Rules of access to a user structure: 182da6c28aaSamw * 183da6c28aaSamw * 1) In order to avoid deadlocks, when both (mutex and lock of the session 184811599a4SMatt Barden * list) have to be entered, the lock must be entered first. Additionally, 185811599a4SMatt Barden * one may NOT flush the deleteq of either the tree list or the ofile list 186811599a4SMatt Barden * while the user mutex is held. 187da6c28aaSamw * 188da6c28aaSamw * 2) All actions applied to a user require a reference count. 189da6c28aaSamw * 190da6c28aaSamw * 3) There are 2 ways of getting a reference count. One is when the user 1919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * logs in. The other when the user is looked up. 192da6c28aaSamw * 193da6c28aaSamw * It should be noted that the reference count of a user registers the 194da6c28aaSamw * number of references to the user in other structures (such as an smb 195da6c28aaSamw * request). The reference count is not incremented in these 2 instances: 196da6c28aaSamw * 19748bbca81SDaniel Hoffman * 1) The user is logged in. An user is anchored by their state. If there's 198da6c28aaSamw * no activity involving a user currently logged in, the reference 199da6c28aaSamw * count of that user is zero. 200da6c28aaSamw * 201da6c28aaSamw * 2) The user is queued in the list of users of the session. The fact of 202da6c28aaSamw * being queued in that list is NOT registered by incrementing the 203da6c28aaSamw * reference count. 204da6c28aaSamw */ 205148c5f43SAlan Wright #include <sys/types.h> 206148c5f43SAlan Wright #include <sys/sid.h> 207148c5f43SAlan Wright #include <sys/priv_names.h> 2089e3ab9e9SMatt Barden #include <sys/priv.h> 2099e3ab9e9SMatt Barden #include <sys/policy.h> 210bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 2119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h> 212da6c28aaSamw 213c8ec8eeaSjose borrego #define ADMINISTRATORS_SID "S-1-5-32-544" 214c8ec8eeaSjose borrego 215811599a4SMatt Barden /* Don't leak object addresses */ 216811599a4SMatt Barden #define SMB_USER_SSNID(u) \ 217811599a4SMatt Barden ((uintptr_t)&smb_cache_user ^ (uintptr_t)(u)) 218811599a4SMatt Barden 219811599a4SMatt Barden static void smb_user_delete(void *); 2201fcced4cSJordan Brown static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *); 2218622ec45SGordon Ross static void smb_user_auth_logoff(smb_user_t *); 2228f70e16bSGordon Ross static void smb_user_logoff_tq(void *); 223c8ec8eeaSjose borrego 224da6c28aaSamw /* 225148c5f43SAlan Wright * Create a new user. 226811599a4SMatt Barden * 227811599a4SMatt Barden * For SMB2 and later, session IDs (u_ssnid) need to be unique among all 228811599a4SMatt Barden * current and "recent" sessions. The session ID is derived from the 229811599a4SMatt Barden * address of the smb_user object (obscured by XOR with a constant). 230811599a4SMatt Barden * This adds a 3-bit generation number in the low bits, incremented 231811599a4SMatt Barden * when we allocate an smb_user_t from its kmem cache, so it can't 232811599a4SMatt Barden * be confused with a (recent) previous incarnation of this object. 233da6c28aaSamw */ 234da6c28aaSamw smb_user_t * 23512b65585SGordon Ross smb_user_new(smb_session_t *session) 23612b65585SGordon Ross { 23712b65585SGordon Ross smb_user_t *user; 238811599a4SMatt Barden uint_t gen; // generation (low 3 bits of ssnid) 239817fa55fSGordon Ross uint32_t ucount; 24012b65585SGordon Ross 24112b65585SGordon Ross ASSERT(session); 24212b65585SGordon Ross ASSERT(session->s_magic == SMB_SESSION_MAGIC); 24312b65585SGordon Ross 24412b65585SGordon Ross user = kmem_cache_alloc(smb_cache_user, KM_SLEEP); 245811599a4SMatt Barden gen = (user->u_ssnid + 1) & 7; 24612b65585SGordon Ross bzero(user, sizeof (smb_user_t)); 24712b65585SGordon Ross 24812b65585SGordon Ross user->u_refcnt = 1; 24912b65585SGordon Ross user->u_session = session; 25012b65585SGordon Ross user->u_server = session->s_server; 25112b65585SGordon Ross user->u_logon_time = gethrestime_sec(); 25212b65585SGordon Ross 25312b65585SGordon Ross if (smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) 25412b65585SGordon Ross goto errout; 255811599a4SMatt Barden user->u_ssnid = SMB_USER_SSNID(user) + gen; 25612b65585SGordon Ross 25712b65585SGordon Ross mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL); 25812b65585SGordon Ross user->u_state = SMB_USER_STATE_LOGGING_ON; 25912b65585SGordon Ross user->u_magic = SMB_USER_MAGIC; 26012b65585SGordon Ross 26112b65585SGordon Ross smb_llist_enter(&session->s_user_list, RW_WRITER); 262817fa55fSGordon Ross ucount = smb_llist_get_count(&session->s_user_list); 26312b65585SGordon Ross smb_llist_insert_tail(&session->s_user_list, user); 26412b65585SGordon Ross smb_llist_exit(&session->s_user_list); 26512b65585SGordon Ross smb_server_inc_users(session->s_server); 26612b65585SGordon Ross 267817fa55fSGordon Ross /* 268817fa55fSGordon Ross * If we added the first user to the session, cancel the 269817fa55fSGordon Ross * timeout that was started in smb_session_receiver(). 270817fa55fSGordon Ross */ 271817fa55fSGordon Ross if (ucount == 0) { 272817fa55fSGordon Ross timeout_id_t tmo = NULL; 273817fa55fSGordon Ross 274817fa55fSGordon Ross smb_rwx_rwenter(&session->s_lock, RW_WRITER); 275817fa55fSGordon Ross tmo = session->s_auth_tmo; 276817fa55fSGordon Ross session->s_auth_tmo = NULL; 277817fa55fSGordon Ross smb_rwx_rwexit(&session->s_lock); 278817fa55fSGordon Ross 279817fa55fSGordon Ross if (tmo != NULL) 280817fa55fSGordon Ross (void) untimeout(tmo); 281817fa55fSGordon Ross } 282817fa55fSGordon Ross 28312b65585SGordon Ross return (user); 28412b65585SGordon Ross 28512b65585SGordon Ross errout: 28612b65585SGordon Ross if (user->u_uid != 0) 28712b65585SGordon Ross smb_idpool_free(&session->s_uid_pool, user->u_uid); 28812b65585SGordon Ross kmem_cache_free(smb_cache_user, user); 28912b65585SGordon Ross return (NULL); 29012b65585SGordon Ross } 29112b65585SGordon Ross 29212b65585SGordon Ross /* 29312b65585SGordon Ross * Fill in the details of a user, meaning a transition 29412b65585SGordon Ross * from state LOGGING_ON to state LOGGED_ON. 29512b65585SGordon Ross */ 29612b65585SGordon Ross int 29712b65585SGordon Ross smb_user_logon( 29812b65585SGordon Ross smb_user_t *user, 299da6c28aaSamw cred_t *cr, 300da6c28aaSamw char *domain_name, 301da6c28aaSamw char *account_name, 302da6c28aaSamw uint32_t flags, 303da6c28aaSamw uint32_t privileges, 304da6c28aaSamw uint32_t audit_sid) 305da6c28aaSamw { 306b210fedeSGordon Ross ksocket_t authsock = NULL; 3078f70e16bSGordon Ross timeout_id_t tmo = NULL; 308da6c28aaSamw 30912b65585SGordon Ross ASSERT(user->u_magic == SMB_USER_MAGIC); 310da6c28aaSamw ASSERT(cr); 311da6c28aaSamw ASSERT(account_name); 312da6c28aaSamw ASSERT(domain_name); 313da6c28aaSamw 31412b65585SGordon Ross mutex_enter(&user->u_mutex); 31512b65585SGordon Ross 31612b65585SGordon Ross if (user->u_state != SMB_USER_STATE_LOGGING_ON) { 31712b65585SGordon Ross mutex_exit(&user->u_mutex); 31812b65585SGordon Ross return (-1); 31912b65585SGordon Ross } 32012b65585SGordon Ross 321b210fedeSGordon Ross /* 322b210fedeSGordon Ross * In the transition from LOGGING_ON to LOGGED_ON, 323b210fedeSGordon Ross * we always have an auth. socket to close. 324b210fedeSGordon Ross */ 325b210fedeSGordon Ross authsock = user->u_authsock; 326b210fedeSGordon Ross user->u_authsock = NULL; 3278f70e16bSGordon Ross tmo = user->u_auth_tmo; 3288f70e16bSGordon Ross user->u_auth_tmo = NULL; 32912b65585SGordon Ross 33012b65585SGordon Ross user->u_state = SMB_USER_STATE_LOGGED_ON; 331da6c28aaSamw user->u_flags = flags; 332da6c28aaSamw user->u_name_len = strlen(account_name) + 1; 333da6c28aaSamw user->u_domain_len = strlen(domain_name) + 1; 3349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States user->u_name = smb_mem_strdup(account_name); 3359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States user->u_domain = smb_mem_strdup(domain_name); 336da6c28aaSamw user->u_audit_sid = audit_sid; 337da6c28aaSamw 338148c5f43SAlan Wright smb_user_setcred(user, cr, privileges); 339da6c28aaSamw 34012b65585SGordon Ross mutex_exit(&user->u_mutex); 341da6c28aaSamw 3428f70e16bSGordon Ross /* Timeout callback takes u_mutex. See untimeout(9f) */ 3438f70e16bSGordon Ross if (tmo != NULL) 3448f70e16bSGordon Ross (void) untimeout(tmo); 3458f70e16bSGordon Ross 346b210fedeSGordon Ross /* This close can block, so not under the mutex. */ 3478d94f651SGordon Ross if (authsock != NULL) 348b210fedeSGordon Ross smb_authsock_close(user, authsock); 349b210fedeSGordon Ross 35012b65585SGordon Ross return (0); 351da6c28aaSamw } 352da6c28aaSamw 353da6c28aaSamw /* 354da6c28aaSamw * smb_user_logoff 355da6c28aaSamw * 356811599a4SMatt Barden * Change the user state to "logging off" and disconnect trees. 3571fcced4cSJordan Brown * The user list must not be entered or modified here. 358811599a4SMatt Barden * 359811599a4SMatt Barden * We remain in state "logging off" until the last ref. is gone, 360811599a4SMatt Barden * then smb_user_release takes us to state "logged off". 361da6c28aaSamw */ 362da6c28aaSamw void 363da6c28aaSamw smb_user_logoff( 364da6c28aaSamw smb_user_t *user) 365da6c28aaSamw { 366b210fedeSGordon Ross ksocket_t authsock = NULL; 3678f70e16bSGordon Ross timeout_id_t tmo = NULL; 368b210fedeSGordon Ross 369da6c28aaSamw ASSERT(user->u_magic == SMB_USER_MAGIC); 370da6c28aaSamw 371da6c28aaSamw mutex_enter(&user->u_mutex); 372da6c28aaSamw ASSERT(user->u_refcnt); 373da6c28aaSamw switch (user->u_state) { 374b210fedeSGordon Ross case SMB_USER_STATE_LOGGING_ON: 375b210fedeSGordon Ross authsock = user->u_authsock; 376b210fedeSGordon Ross user->u_authsock = NULL; 3778f70e16bSGordon Ross tmo = user->u_auth_tmo; 3788f70e16bSGordon Ross user->u_auth_tmo = NULL; 379811599a4SMatt Barden user->u_state = SMB_USER_STATE_LOGGING_OFF; 380811599a4SMatt Barden mutex_exit(&user->u_mutex); 381811599a4SMatt Barden 382811599a4SMatt Barden /* Timeout callback takes u_mutex. See untimeout(9f) */ 383811599a4SMatt Barden if (tmo != NULL) 384811599a4SMatt Barden (void) untimeout(tmo); 385811599a4SMatt Barden /* This close can block, so not under the mutex. */ 386811599a4SMatt Barden if (authsock != NULL) 387811599a4SMatt Barden smb_authsock_close(user, authsock); 38812b65585SGordon Ross break; 38912b65585SGordon Ross 390b210fedeSGordon Ross case SMB_USER_STATE_LOGGED_ON: 391da6c28aaSamw /* 392da6c28aaSamw * The user is moved into a state indicating that the log off 393da6c28aaSamw * process has started. 394da6c28aaSamw */ 395da6c28aaSamw user->u_state = SMB_USER_STATE_LOGGING_OFF; 396da6c28aaSamw mutex_exit(&user->u_mutex); 3973b13a1efSThomas Keiser smb_session_disconnect_owned_trees(user->u_session, user); 3988622ec45SGordon Ross smb_user_auth_logoff(user); 399da6c28aaSamw break; 400b210fedeSGordon Ross 401da6c28aaSamw case SMB_USER_STATE_LOGGED_OFF: 402da6c28aaSamw case SMB_USER_STATE_LOGGING_OFF: 403811599a4SMatt Barden mutex_exit(&user->u_mutex); 404da6c28aaSamw break; 405da6c28aaSamw 406da6c28aaSamw default: 407da6c28aaSamw ASSERT(0); 408da6c28aaSamw mutex_exit(&user->u_mutex); 409811599a4SMatt Barden break; 410b210fedeSGordon Ross } 411da6c28aaSamw } 412da6c28aaSamw 413da6c28aaSamw /* 4143b13a1efSThomas Keiser * Take a reference on a user. Do not return a reference unless the user is in 4153b13a1efSThomas Keiser * the logged-in state. 4161fcced4cSJordan Brown */ 4171fcced4cSJordan Brown boolean_t 4181fcced4cSJordan Brown smb_user_hold(smb_user_t *user) 4191fcced4cSJordan Brown { 4203b13a1efSThomas Keiser SMB_USER_VALID(user); 4211fcced4cSJordan Brown 4221fcced4cSJordan Brown mutex_enter(&user->u_mutex); 4231fcced4cSJordan Brown 42412b65585SGordon Ross if (user->u_state == SMB_USER_STATE_LOGGED_ON) { 4251fcced4cSJordan Brown user->u_refcnt++; 4261fcced4cSJordan Brown mutex_exit(&user->u_mutex); 4271fcced4cSJordan Brown return (B_TRUE); 4281fcced4cSJordan Brown } 4291fcced4cSJordan Brown 4301fcced4cSJordan Brown mutex_exit(&user->u_mutex); 4311fcced4cSJordan Brown return (B_FALSE); 4321fcced4cSJordan Brown } 4331fcced4cSJordan Brown 4341fcced4cSJordan Brown /* 4353b13a1efSThomas Keiser * Unconditionally take a reference on a user. 4363b13a1efSThomas Keiser */ 4373b13a1efSThomas Keiser void 4383b13a1efSThomas Keiser smb_user_hold_internal(smb_user_t *user) 4393b13a1efSThomas Keiser { 4403b13a1efSThomas Keiser SMB_USER_VALID(user); 4413b13a1efSThomas Keiser 4423b13a1efSThomas Keiser mutex_enter(&user->u_mutex); 4433b13a1efSThomas Keiser user->u_refcnt++; 4443b13a1efSThomas Keiser mutex_exit(&user->u_mutex); 4453b13a1efSThomas Keiser } 4463b13a1efSThomas Keiser 4473b13a1efSThomas Keiser /* 4489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Release a reference on a user. If the reference count falls to 4499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * zero and the user has logged off, post the object for deletion. 4509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Object deletion is deferred to avoid modifying a list while an 4519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * iteration may be in progress. 452da6c28aaSamw */ 453da6c28aaSamw void 454da6c28aaSamw smb_user_release( 455da6c28aaSamw smb_user_t *user) 456da6c28aaSamw { 457811599a4SMatt Barden smb_session_t *ssn = user->u_session; 458811599a4SMatt Barden 459811599a4SMatt Barden SMB_USER_VALID(user); 460811599a4SMatt Barden 461811599a4SMatt Barden /* flush the tree list delete queue */ 462811599a4SMatt Barden smb_llist_flush(&ssn->s_tree_list); 463da6c28aaSamw 464da6c28aaSamw mutex_enter(&user->u_mutex); 465da6c28aaSamw ASSERT(user->u_refcnt); 466da6c28aaSamw user->u_refcnt--; 467c5866007SKeyur Desai 468da6c28aaSamw switch (user->u_state) { 469811599a4SMatt Barden case SMB_USER_STATE_LOGGING_OFF: 470811599a4SMatt Barden if (user->u_refcnt == 0) { 471811599a4SMatt Barden smb_session_t *ssn = user->u_session; 472811599a4SMatt Barden user->u_state = SMB_USER_STATE_LOGGED_OFF; 473811599a4SMatt Barden smb_llist_post(&ssn->s_user_list, user, 474811599a4SMatt Barden smb_user_delete); 475811599a4SMatt Barden } 476da6c28aaSamw break; 477da6c28aaSamw 47812b65585SGordon Ross case SMB_USER_STATE_LOGGING_ON: 47912b65585SGordon Ross case SMB_USER_STATE_LOGGED_ON: 480da6c28aaSamw break; 481da6c28aaSamw 482811599a4SMatt Barden case SMB_USER_STATE_LOGGED_OFF: 483da6c28aaSamw default: 484da6c28aaSamw ASSERT(0); 485da6c28aaSamw break; 486da6c28aaSamw } 487da6c28aaSamw mutex_exit(&user->u_mutex); 488da6c28aaSamw } 489da6c28aaSamw 4901fcced4cSJordan Brown /* 4918f70e16bSGordon Ross * Timeout handler for user logons that stay too long in 4928f70e16bSGordon Ross * state SMB_USER_STATE_LOGGING_ON. This is setup by a 4938f70e16bSGordon Ross * timeout call in smb_authsock_open, and called in a 4948f70e16bSGordon Ross * callout thread, so schedule a taskq job to do the 4958f70e16bSGordon Ross * real work of logging off this user. 4968f70e16bSGordon Ross */ 4978f70e16bSGordon Ross void 4988f70e16bSGordon Ross smb_user_auth_tmo(void *arg) 4998f70e16bSGordon Ross { 5008f70e16bSGordon Ross smb_user_t *user = arg; 5018f70e16bSGordon Ross smb_request_t *sr; 502*9788d6deSGordon Ross taskqid_t tqid; 5038f70e16bSGordon Ross 5048f70e16bSGordon Ross SMB_USER_VALID(user); 5058f70e16bSGordon Ross 5068f70e16bSGordon Ross /* 5078f70e16bSGordon Ross * If we can't allocate a request, it means the 5088f70e16bSGordon Ross * session is being torn down, so nothing to do. 5098f70e16bSGordon Ross */ 5108f70e16bSGordon Ross sr = smb_request_alloc(user->u_session, 0); 5118f70e16bSGordon Ross if (sr == NULL) 5128f70e16bSGordon Ross return; 5138f70e16bSGordon Ross 5148f70e16bSGordon Ross /* 5158f70e16bSGordon Ross * Check user state, and take a hold if it's 5168f70e16bSGordon Ross * still logging on. If not, we're done. 5178f70e16bSGordon Ross */ 5188f70e16bSGordon Ross mutex_enter(&user->u_mutex); 5198f70e16bSGordon Ross if (user->u_state != SMB_USER_STATE_LOGGING_ON) { 5208f70e16bSGordon Ross mutex_exit(&user->u_mutex); 5218f70e16bSGordon Ross smb_request_free(sr); 5228f70e16bSGordon Ross return; 5238f70e16bSGordon Ross } 5248f70e16bSGordon Ross /* smb_user_hold_internal */ 5258f70e16bSGordon Ross user->u_refcnt++; 5268f70e16bSGordon Ross mutex_exit(&user->u_mutex); 5278f70e16bSGordon Ross 5288f70e16bSGordon Ross /* 5298f70e16bSGordon Ross * The user hold is given to the SR, and released in 5308f70e16bSGordon Ross * smb_user_logoff_tq / smb_request_free 5318f70e16bSGordon Ross */ 5328f70e16bSGordon Ross sr->uid_user = user; 5338f70e16bSGordon Ross sr->user_cr = user->u_cred; 5348f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_SUBMITTED; 535*9788d6deSGordon Ross tqid = taskq_dispatch( 5368f70e16bSGordon Ross user->u_server->sv_worker_pool, 5378f70e16bSGordon Ross smb_user_logoff_tq, sr, TQ_SLEEP); 538*9788d6deSGordon Ross VERIFY(tqid != TASKQID_INVALID); 5398f70e16bSGordon Ross } 5408f70e16bSGordon Ross 5418f70e16bSGordon Ross /* 5428f70e16bSGordon Ross * Helper for smb_user_auth_tmo() 5438f70e16bSGordon Ross */ 5448f70e16bSGordon Ross static void 5458f70e16bSGordon Ross smb_user_logoff_tq(void *arg) 5468f70e16bSGordon Ross { 5478f70e16bSGordon Ross smb_request_t *sr = arg; 5488f70e16bSGordon Ross 5498f70e16bSGordon Ross SMB_REQ_VALID(sr); 5508f70e16bSGordon Ross 5518f70e16bSGordon Ross mutex_enter(&sr->sr_mutex); 5528f70e16bSGordon Ross sr->sr_worker = curthread; 5538f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 5548f70e16bSGordon Ross mutex_exit(&sr->sr_mutex); 5558f70e16bSGordon Ross 5568f70e16bSGordon Ross smb_user_logoff(sr->uid_user); 5578f70e16bSGordon Ross 5588f70e16bSGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED; 5598f70e16bSGordon Ross smb_request_free(sr); 5608f70e16bSGordon Ross } 5618f70e16bSGordon Ross 5628f70e16bSGordon Ross /* 563c8ec8eeaSjose borrego * Determine whether or not the user is an administrator. 564c8ec8eeaSjose borrego * Members of the administrators group have administrative rights. 565c8ec8eeaSjose borrego */ 566c8ec8eeaSjose borrego boolean_t 567148c5f43SAlan Wright smb_user_is_admin(smb_user_t *user) 568c8ec8eeaSjose borrego { 569b819cea2SGordon Ross #ifdef _KERNEL 570148c5f43SAlan Wright char sidstr[SMB_SID_STRSZ]; 571148c5f43SAlan Wright ksidlist_t *ksidlist; 572148c5f43SAlan Wright ksid_t ksid1; 573148c5f43SAlan Wright ksid_t *ksid2; 574148c5f43SAlan Wright int i; 575b819cea2SGordon Ross #endif /* _KERNEL */ 576b819cea2SGordon Ross boolean_t rc = B_FALSE; 577c8ec8eeaSjose borrego 578c8ec8eeaSjose borrego ASSERT(user); 579148c5f43SAlan Wright ASSERT(user->u_cred); 580c8ec8eeaSjose borrego 581148c5f43SAlan Wright if (SMB_USER_IS_ADMIN(user)) 582c8ec8eeaSjose borrego return (B_TRUE); 583c8ec8eeaSjose borrego 584b819cea2SGordon Ross #ifdef _KERNEL 585148c5f43SAlan Wright bzero(&ksid1, sizeof (ksid_t)); 586148c5f43SAlan Wright (void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ); 587148c5f43SAlan Wright ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0); 588148c5f43SAlan Wright ksid1.ks_domain = ksid_lookupdomain(sidstr); 589148c5f43SAlan Wright 590148c5f43SAlan Wright ksidlist = crgetsidlist(user->u_cred); 591148c5f43SAlan Wright ASSERT(ksidlist); 592148c5f43SAlan Wright ASSERT(ksid1.ks_domain); 593148c5f43SAlan Wright ASSERT(ksid1.ks_domain->kd_name); 594148c5f43SAlan Wright 595148c5f43SAlan Wright i = 0; 596148c5f43SAlan Wright ksid2 = crgetsid(user->u_cred, KSID_USER); 597148c5f43SAlan Wright do { 598148c5f43SAlan Wright ASSERT(ksid2->ks_domain); 599148c5f43SAlan Wright ASSERT(ksid2->ks_domain->kd_name); 600148c5f43SAlan Wright 601148c5f43SAlan Wright if (strcmp(ksid1.ks_domain->kd_name, 602148c5f43SAlan Wright ksid2->ks_domain->kd_name) == 0 && 603148c5f43SAlan Wright ksid1.ks_rid == ksid2->ks_rid) { 604148c5f43SAlan Wright user->u_flags |= SMB_USER_FLAG_ADMIN; 605148c5f43SAlan Wright rc = B_TRUE; 606148c5f43SAlan Wright break; 607148c5f43SAlan Wright } 608148c5f43SAlan Wright 609148c5f43SAlan Wright ksid2 = &ksidlist->ksl_sids[i]; 610148c5f43SAlan Wright } while (i++ < ksidlist->ksl_nsid); 611148c5f43SAlan Wright 612148c5f43SAlan Wright ksid_rele(&ksid1); 613b819cea2SGordon Ross #endif /* _KERNEL */ 614148c5f43SAlan Wright return (rc); 615c8ec8eeaSjose borrego } 616c8ec8eeaSjose borrego 6171fcced4cSJordan Brown /* 6181fcced4cSJordan Brown * This function should be called with a hold on the user. 6191fcced4cSJordan Brown */ 6201fcced4cSJordan Brown boolean_t 6211fcced4cSJordan Brown smb_user_namecmp(smb_user_t *user, const char *name) 6221fcced4cSJordan Brown { 6231fcced4cSJordan Brown char *fq_name; 6241fcced4cSJordan Brown boolean_t match; 6251fcced4cSJordan Brown 626bbf6f00cSJordan Brown if (smb_strcasecmp(name, user->u_name, 0) == 0) 6271fcced4cSJordan Brown return (B_TRUE); 6281fcced4cSJordan Brown 6291fcced4cSJordan Brown fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 6301fcced4cSJordan Brown 6311fcced4cSJordan Brown (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s", 6321fcced4cSJordan Brown user->u_domain, user->u_name); 6331fcced4cSJordan Brown 634bbf6f00cSJordan Brown match = (smb_strcasecmp(name, fq_name, 0) == 0); 6351fcced4cSJordan Brown if (!match) { 6361fcced4cSJordan Brown (void) snprintf(fq_name, MAXNAMELEN, "%s@%s", 6371fcced4cSJordan Brown user->u_name, user->u_domain); 6381fcced4cSJordan Brown 639bbf6f00cSJordan Brown match = (smb_strcasecmp(name, fq_name, 0) == 0); 6401fcced4cSJordan Brown } 6411fcced4cSJordan Brown 6421fcced4cSJordan Brown kmem_free(fq_name, MAXNAMELEN); 6431fcced4cSJordan Brown return (match); 6441fcced4cSJordan Brown } 6451fcced4cSJordan Brown 6461fcced4cSJordan Brown /* 6471fcced4cSJordan Brown * If the enumeration request is for user data, handle the request 6481fcced4cSJordan Brown * here. Otherwise, pass it on to the trees. 6491fcced4cSJordan Brown * 6501fcced4cSJordan Brown * This function should be called with a hold on the user. 6511fcced4cSJordan Brown */ 6521fcced4cSJordan Brown int 6531fcced4cSJordan Brown smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum) 6541fcced4cSJordan Brown { 6553b13a1efSThomas Keiser int rc = 0; 6561fcced4cSJordan Brown 6571fcced4cSJordan Brown ASSERT(user); 6581fcced4cSJordan Brown ASSERT(user->u_magic == SMB_USER_MAGIC); 6591fcced4cSJordan Brown 6601fcced4cSJordan Brown if (svcenum->se_type == SMB_SVCENUM_TYPE_USER) 6611fcced4cSJordan Brown return (smb_user_enum_private(user, svcenum)); 6621fcced4cSJordan Brown 6631fcced4cSJordan Brown return (rc); 6641fcced4cSJordan Brown } 6651fcced4cSJordan Brown 6661baeef30SPrashanth Badari /* 6671baeef30SPrashanth Badari * Count references by trees this user owns, 6681baeef30SPrashanth Badari * and allow waiting for them to go away. 6691baeef30SPrashanth Badari */ 6701baeef30SPrashanth Badari void 6711baeef30SPrashanth Badari smb_user_inc_trees(smb_user_t *user) 6721baeef30SPrashanth Badari { 6731baeef30SPrashanth Badari mutex_enter(&user->u_mutex); 6741baeef30SPrashanth Badari user->u_owned_tree_cnt++; 6751baeef30SPrashanth Badari mutex_exit(&user->u_mutex); 6761baeef30SPrashanth Badari } 6771baeef30SPrashanth Badari 6781baeef30SPrashanth Badari void 6791baeef30SPrashanth Badari smb_user_dec_trees(smb_user_t *user) 6801baeef30SPrashanth Badari { 6811baeef30SPrashanth Badari mutex_enter(&user->u_mutex); 6821baeef30SPrashanth Badari user->u_owned_tree_cnt--; 6831baeef30SPrashanth Badari if (user->u_owned_tree_cnt == 0) 6841baeef30SPrashanth Badari cv_broadcast(&user->u_owned_tree_cv); 6851baeef30SPrashanth Badari mutex_exit(&user->u_mutex); 6861baeef30SPrashanth Badari } 6871baeef30SPrashanth Badari 6881baeef30SPrashanth Badari int smb_user_wait_tree_tmo = 30; 6891baeef30SPrashanth Badari 6901baeef30SPrashanth Badari /* 6911baeef30SPrashanth Badari * Wait (up to 30 sec.) for trees to go away. 6921baeef30SPrashanth Badari * Should happen in less than a second. 6931baeef30SPrashanth Badari */ 6941baeef30SPrashanth Badari void 6951baeef30SPrashanth Badari smb_user_wait_trees(smb_user_t *user) 6961baeef30SPrashanth Badari { 6971baeef30SPrashanth Badari clock_t time; 6981baeef30SPrashanth Badari 6991baeef30SPrashanth Badari time = SEC_TO_TICK(smb_user_wait_tree_tmo) + ddi_get_lbolt(); 7001baeef30SPrashanth Badari mutex_enter(&user->u_mutex); 7011baeef30SPrashanth Badari while (user->u_owned_tree_cnt != 0) { 7021baeef30SPrashanth Badari if (cv_timedwait(&user->u_owned_tree_cv, 7031baeef30SPrashanth Badari &user->u_mutex, time) < 0) 7041baeef30SPrashanth Badari break; 7051baeef30SPrashanth Badari } 7061baeef30SPrashanth Badari mutex_exit(&user->u_mutex); 7071baeef30SPrashanth Badari #ifdef DEBUG 7081baeef30SPrashanth Badari if (user->u_owned_tree_cnt != 0) { 7091baeef30SPrashanth Badari cmn_err(CE_NOTE, "smb_user_wait_trees failed"); 7101baeef30SPrashanth Badari debug_enter("smb_user_wait_trees debug"); 7111baeef30SPrashanth Badari } 7121baeef30SPrashanth Badari #endif 7131baeef30SPrashanth Badari } 7141baeef30SPrashanth Badari 715da6c28aaSamw /* *************************** Static Functions ***************************** */ 716da6c28aaSamw 717da6c28aaSamw /* 7189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Delete a user. The tree list should be empty. 7199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 7209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Remove the user from the session's user list before freeing resources 7219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * associated with the user. 722da6c28aaSamw */ 723811599a4SMatt Barden static void 7249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_delete(void *arg) 725da6c28aaSamw { 726da6c28aaSamw smb_session_t *session; 7279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t *user = (smb_user_t *)arg; 728811599a4SMatt Barden uint32_t ucount; 729da6c28aaSamw 7309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_USER_VALID(user); 731da6c28aaSamw ASSERT(user->u_refcnt == 0); 732da6c28aaSamw ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF); 73312b65585SGordon Ross ASSERT(user->u_authsock == NULL); 7348f70e16bSGordon Ross ASSERT(user->u_auth_tmo == NULL); 735da6c28aaSamw 736da6c28aaSamw session = user->u_session; 737811599a4SMatt Barden 738811599a4SMatt Barden smb_server_dec_users(session->s_server); 739da6c28aaSamw smb_llist_enter(&session->s_user_list, RW_WRITER); 740da6c28aaSamw smb_llist_remove(&session->s_user_list, user); 7419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_idpool_free(&session->s_uid_pool, user->u_uid); 742811599a4SMatt Barden ucount = smb_llist_get_count(&session->s_user_list); 743da6c28aaSamw smb_llist_exit(&session->s_user_list); 744da6c28aaSamw 745817fa55fSGordon Ross /* 746817fa55fSGordon Ross * When the last smb_user_t object goes away, schedule a timeout 747817fa55fSGordon Ross * after which we'll terminate this session if the client hasn't 748817fa55fSGordon Ross * authenticated another smb_user_t on this session by then. 749817fa55fSGordon Ross */ 750811599a4SMatt Barden if (ucount == 0) { 751811599a4SMatt Barden smb_rwx_rwenter(&session->s_lock, RW_WRITER); 752817fa55fSGordon Ross if (session->s_state == SMB_SESSION_STATE_NEGOTIATED && 753817fa55fSGordon Ross session->s_auth_tmo == NULL) { 754817fa55fSGordon Ross session->s_auth_tmo = 755817fa55fSGordon Ross timeout((tmo_func_t)smb_session_disconnect, 756817fa55fSGordon Ross session, SEC_TO_TICK(smb_session_auth_tmo)); 757817fa55fSGordon Ross } 758811599a4SMatt Barden smb_rwx_cvbcast(&session->s_lock); 759811599a4SMatt Barden smb_rwx_rwexit(&session->s_lock); 760811599a4SMatt Barden } 761811599a4SMatt Barden 762811599a4SMatt Barden /* 763811599a4SMatt Barden * This user is no longer on s_user_list, however... 764811599a4SMatt Barden * 765811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 766811599a4SMatt Barden * BEFORE smb_user_release drops u_mutex (if another thread 767811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 768811599a4SMatt Barden */ 7699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&user->u_mutex); 7709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&user->u_mutex); 7719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 772da6c28aaSamw user->u_magic = (uint32_t)~SMB_USER_MAGIC; 773da6c28aaSamw mutex_destroy(&user->u_mutex); 774148c5f43SAlan Wright if (user->u_cred) 775da6c28aaSamw crfree(user->u_cred); 776b89a8333Snatalie li - Sun Microsystems - Irvine United States if (user->u_privcred) 777b89a8333Snatalie li - Sun Microsystems - Irvine United States crfree(user->u_privcred); 7789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(user->u_name); 7799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(user->u_domain); 7808622ec45SGordon Ross kmem_cache_free(smb_cache_user, user); 781da6c28aaSamw } 782c8ec8eeaSjose borrego 783b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t * 784b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getcred(smb_user_t *user) 785b89a8333Snatalie li - Sun Microsystems - Irvine United States { 786b89a8333Snatalie li - Sun Microsystems - Irvine United States return (user->u_cred); 787b89a8333Snatalie li - Sun Microsystems - Irvine United States } 788b89a8333Snatalie li - Sun Microsystems - Irvine United States 789b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t * 790b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_user_getprivcred(smb_user_t *user) 791b89a8333Snatalie li - Sun Microsystems - Irvine United States { 792b89a8333Snatalie li - Sun Microsystems - Irvine United States return ((user->u_privcred)? user->u_privcred : user->u_cred); 793b89a8333Snatalie li - Sun Microsystems - Irvine United States } 7941fcced4cSJordan Brown 795b819cea2SGordon Ross #ifdef _KERNEL 7961fcced4cSJordan Brown /* 797148c5f43SAlan Wright * Assign the user cred and privileges. 798148c5f43SAlan Wright * 799148c5f43SAlan Wright * If the user has backup and/or restore privleges, dup the cred 800148c5f43SAlan Wright * and add those privileges to this new privileged cred. 801148c5f43SAlan Wright */ 802b819cea2SGordon Ross void 803148c5f43SAlan Wright smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges) 804148c5f43SAlan Wright { 805148c5f43SAlan Wright cred_t *privcred = NULL; 806148c5f43SAlan Wright 807148c5f43SAlan Wright ASSERT(cr); 808148c5f43SAlan Wright crhold(cr); 809148c5f43SAlan Wright 8100292c176SMatt Barden /* 8110292c176SMatt Barden * See smb.4 bypass_traverse_checking 8120292c176SMatt Barden * 8130292c176SMatt Barden * For historical reasons, the Windows privilege is named 8140292c176SMatt Barden * SeChangeNotifyPrivilege, though the description is 8150292c176SMatt Barden * "Bypass traverse checking". 8160292c176SMatt Barden */ 8170292c176SMatt Barden if ((privileges & SMB_USER_PRIV_CHANGE_NOTIFY) != 0) { 8180292c176SMatt Barden (void) crsetpriv(cr, PRIV_FILE_DAC_SEARCH, NULL); 8190292c176SMatt Barden } 8200292c176SMatt Barden 8210292c176SMatt Barden /* 8220292c176SMatt Barden * Window's "take ownership privilege" is similar to our 8230292c176SMatt Barden * PRIV_FILE_CHOWN privilege. It's normally given to members of the 8240292c176SMatt Barden * "Administrators" group, which normally includes the the local 8250292c176SMatt Barden * Administrator (like root) and when joined to a domain, 8260292c176SMatt Barden * "Domain Admins". 8270292c176SMatt Barden */ 8280292c176SMatt Barden if ((privileges & SMB_USER_PRIV_TAKE_OWNERSHIP) != 0) { 8290292c176SMatt Barden (void) crsetpriv(cr, 8300292c176SMatt Barden PRIV_FILE_CHOWN, 8310292c176SMatt Barden PRIV_FILE_CHOWN_SELF, 8320292c176SMatt Barden NULL); 8330292c176SMatt Barden } 8340292c176SMatt Barden 8350292c176SMatt Barden /* 8360292c176SMatt Barden * Bypass ACL for READ accesses. 8370292c176SMatt Barden */ 8380292c176SMatt Barden if ((privileges & SMB_USER_PRIV_READ_FILE) != 0) { 8390292c176SMatt Barden (void) crsetpriv(cr, PRIV_FILE_DAC_READ, NULL); 8400292c176SMatt Barden } 8410292c176SMatt Barden 8420292c176SMatt Barden /* 8430292c176SMatt Barden * Bypass ACL for WRITE accesses. 8440292c176SMatt Barden * Include FILE_OWNER, as it covers WRITE_ACL and DELETE. 8450292c176SMatt Barden */ 8460292c176SMatt Barden if ((privileges & SMB_USER_PRIV_WRITE_FILE) != 0) { 8470292c176SMatt Barden (void) crsetpriv(cr, 8480292c176SMatt Barden PRIV_FILE_DAC_WRITE, 8490292c176SMatt Barden PRIV_FILE_OWNER, 8500292c176SMatt Barden NULL); 8510292c176SMatt Barden } 8520292c176SMatt Barden 8530292c176SMatt Barden /* 8540292c176SMatt Barden * These privileges are used only when a file is opened with 8550292c176SMatt Barden * 'backup intent'. These allow users to bypass certain access 8560292c176SMatt Barden * controls. Administrators typically have these privileges, 8570292c176SMatt Barden * and they are used during recursive take-ownership operations. 8580292c176SMatt Barden * Some commonly used tools use 'backup intent' to administrate 8590292c176SMatt Barden * files that do not grant explicit permissions to Administrators. 8600292c176SMatt Barden */ 861148c5f43SAlan Wright if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE)) 862148c5f43SAlan Wright privcred = crdup(cr); 863148c5f43SAlan Wright 864148c5f43SAlan Wright if (privcred != NULL) { 865148c5f43SAlan Wright if (privileges & SMB_USER_PRIV_BACKUP) { 866148c5f43SAlan Wright (void) crsetpriv(privcred, PRIV_FILE_DAC_READ, 867148c5f43SAlan Wright PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL); 868148c5f43SAlan Wright } 869148c5f43SAlan Wright 870148c5f43SAlan Wright if (privileges & SMB_USER_PRIV_RESTORE) { 871148c5f43SAlan Wright (void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE, 872148c5f43SAlan Wright PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF, 873148c5f43SAlan Wright PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY, 874148c5f43SAlan Wright PRIV_FILE_OWNER, PRIV_FILE_SETID, 875148c5f43SAlan Wright PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL); 876148c5f43SAlan Wright } 877148c5f43SAlan Wright } 878148c5f43SAlan Wright 879148c5f43SAlan Wright user->u_cred = cr; 880148c5f43SAlan Wright user->u_privcred = privcred; 881148c5f43SAlan Wright user->u_privileges = privileges; 882148c5f43SAlan Wright } 883b819cea2SGordon Ross #endif /* _KERNEL */ 884148c5f43SAlan Wright 885148c5f43SAlan Wright /* 8869e3ab9e9SMatt Barden * Determines whether a user can be granted ACCESS_SYSTEM_SECURITY 8879e3ab9e9SMatt Barden */ 8889e3ab9e9SMatt Barden boolean_t 8899e3ab9e9SMatt Barden smb_user_has_security_priv(smb_user_t *user, cred_t *cr) 8909e3ab9e9SMatt Barden { 8919e3ab9e9SMatt Barden /* Need SeSecurityPrivilege to get/set SACL */ 8929e3ab9e9SMatt Barden if ((user->u_privileges & SMB_USER_PRIV_SECURITY) != 0) 8939e3ab9e9SMatt Barden return (B_TRUE); 8949e3ab9e9SMatt Barden 8959e3ab9e9SMatt Barden #ifdef _KERNEL 8969e3ab9e9SMatt Barden /* 8979e3ab9e9SMatt Barden * ACCESS_SYSTEM_SECURITY is also granted if the file is opened with 8989e3ab9e9SMatt Barden * BACKUP/RESTORE intent by a user with BACKUP/RESTORE privilege, 8999e3ab9e9SMatt Barden * which means we'll be using u_privcred. 9009e3ab9e9SMatt Barden * 9019e3ab9e9SMatt Barden * We translate BACKUP as DAC_READ and RESTORE as DAC_WRITE, 9029e3ab9e9SMatt Barden * to account for our various SMB_USER_* privileges. 9039e3ab9e9SMatt Barden */ 9049e3ab9e9SMatt Barden if (PRIV_POLICY_ONLY(cr, 9059e3ab9e9SMatt Barden priv_getbyname(PRIV_FILE_DAC_READ, 0), B_FALSE) || 9069e3ab9e9SMatt Barden PRIV_POLICY_ONLY(cr, 9079e3ab9e9SMatt Barden priv_getbyname(PRIV_FILE_DAC_WRITE, 0), B_FALSE)) 9089e3ab9e9SMatt Barden return (B_TRUE); 9099e3ab9e9SMatt Barden #else 9109e3ab9e9SMatt Barden /* 9119e3ab9e9SMatt Barden * No "real" privileges in fksmbsrv, so use the SMB privs instead. 9129e3ab9e9SMatt Barden */ 9139e3ab9e9SMatt Barden if ((user->u_privileges & 9149e3ab9e9SMatt Barden (SMB_USER_PRIV_BACKUP | 9159e3ab9e9SMatt Barden SMB_USER_PRIV_RESTORE | 9169e3ab9e9SMatt Barden SMB_USER_PRIV_READ_FILE | 9179e3ab9e9SMatt Barden SMB_USER_PRIV_WRITE_FILE)) != 0) 9189e3ab9e9SMatt Barden return (B_TRUE); 9199e3ab9e9SMatt Barden #endif 9209e3ab9e9SMatt Barden 9219e3ab9e9SMatt Barden return (B_FALSE); 9229e3ab9e9SMatt Barden } 9239e3ab9e9SMatt Barden 9249e3ab9e9SMatt Barden /* 9251fcced4cSJordan Brown * Private function to support smb_user_enum. 9261fcced4cSJordan Brown */ 9271fcced4cSJordan Brown static int 9281fcced4cSJordan Brown smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum) 9291fcced4cSJordan Brown { 9301fcced4cSJordan Brown uint8_t *pb; 9311fcced4cSJordan Brown uint_t nbytes; 9321fcced4cSJordan Brown int rc; 9331fcced4cSJordan Brown 9341fcced4cSJordan Brown if (svcenum->se_nskip > 0) { 9351fcced4cSJordan Brown svcenum->se_nskip--; 9361fcced4cSJordan Brown return (0); 9371fcced4cSJordan Brown } 9381fcced4cSJordan Brown 9391fcced4cSJordan Brown if (svcenum->se_nitems >= svcenum->se_nlimit) { 9401fcced4cSJordan Brown svcenum->se_nitems = svcenum->se_nlimit; 9411fcced4cSJordan Brown return (0); 9421fcced4cSJordan Brown } 9431fcced4cSJordan Brown 9441fcced4cSJordan Brown pb = &svcenum->se_buf[svcenum->se_bused]; 9451fcced4cSJordan Brown rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes); 9461fcced4cSJordan Brown if (rc == 0) { 9471fcced4cSJordan Brown svcenum->se_bavail -= nbytes; 9481fcced4cSJordan Brown svcenum->se_bused += nbytes; 9491fcced4cSJordan Brown svcenum->se_nitems++; 9501fcced4cSJordan Brown } 9511fcced4cSJordan Brown 9521fcced4cSJordan Brown return (rc); 9531fcced4cSJordan Brown } 9541fcced4cSJordan Brown 9551fcced4cSJordan Brown /* 9561fcced4cSJordan Brown * Encode the NetInfo for a user into a buffer. NetInfo contains 9571fcced4cSJordan Brown * information that is often needed in user space to support RPC 9581fcced4cSJordan Brown * requests. 9591fcced4cSJordan Brown */ 9601fcced4cSJordan Brown int 9611fcced4cSJordan Brown smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen, 9621fcced4cSJordan Brown uint32_t *nbytes) 9631fcced4cSJordan Brown { 9641fcced4cSJordan Brown smb_netuserinfo_t info; 9651fcced4cSJordan Brown int rc; 9661fcced4cSJordan Brown 9671fcced4cSJordan Brown smb_user_netinfo_init(user, &info); 9681fcced4cSJordan Brown rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes); 9691fcced4cSJordan Brown smb_user_netinfo_fini(&info); 9701fcced4cSJordan Brown 9711fcced4cSJordan Brown return (rc); 9721fcced4cSJordan Brown } 9731fcced4cSJordan Brown 9741fcced4cSJordan Brown void 9751fcced4cSJordan Brown smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info) 9761fcced4cSJordan Brown { 9771fcced4cSJordan Brown smb_session_t *session; 9781fcced4cSJordan Brown char *buf; 9791fcced4cSJordan Brown 9801fcced4cSJordan Brown ASSERT(user); 9811fcced4cSJordan Brown ASSERT(user->u_domain); 9821fcced4cSJordan Brown ASSERT(user->u_name); 9831fcced4cSJordan Brown 9841fcced4cSJordan Brown session = user->u_session; 9851fcced4cSJordan Brown ASSERT(session); 9861fcced4cSJordan Brown ASSERT(session->workstation); 9871fcced4cSJordan Brown 9881fcced4cSJordan Brown info->ui_session_id = session->s_kid; 9891fcced4cSJordan Brown info->ui_native_os = session->native_os; 9901fcced4cSJordan Brown info->ui_ipaddr = session->ipaddr; 9911fcced4cSJordan Brown info->ui_numopens = session->s_file_cnt; 9921fcced4cSJordan Brown info->ui_logon_time = user->u_logon_time; 9931fcced4cSJordan Brown info->ui_flags = user->u_flags; 994c5866007SKeyur Desai info->ui_posix_uid = crgetuid(user->u_cred); 9951fcced4cSJordan Brown 9961fcced4cSJordan Brown info->ui_domain_len = user->u_domain_len; 9979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_domain = smb_mem_strdup(user->u_domain); 9981fcced4cSJordan Brown 9991fcced4cSJordan Brown info->ui_account_len = user->u_name_len; 10009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_account = smb_mem_strdup(user->u_name); 10011fcced4cSJordan Brown 10021fcced4cSJordan Brown buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); 10031fcced4cSJordan Brown smb_session_getclient(session, buf, MAXNAMELEN); 10041fcced4cSJordan Brown info->ui_workstation_len = strlen(buf) + 1; 10059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States info->ui_workstation = smb_mem_strdup(buf); 10061fcced4cSJordan Brown kmem_free(buf, MAXNAMELEN); 10071fcced4cSJordan Brown } 10081fcced4cSJordan Brown 10091fcced4cSJordan Brown void 10101fcced4cSJordan Brown smb_user_netinfo_fini(smb_netuserinfo_t *info) 10111fcced4cSJordan Brown { 10121fcced4cSJordan Brown if (info == NULL) 10131fcced4cSJordan Brown return; 10141fcced4cSJordan Brown 10151fcced4cSJordan Brown if (info->ui_domain) 10169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_domain); 10171fcced4cSJordan Brown if (info->ui_account) 10189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_account); 10191fcced4cSJordan Brown if (info->ui_workstation) 10209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(info->ui_workstation); 10211fcced4cSJordan Brown 10221fcced4cSJordan Brown bzero(info, sizeof (smb_netuserinfo_t)); 10231fcced4cSJordan Brown } 10249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1025811599a4SMatt Barden /* 1026811599a4SMatt Barden * Tell smbd this user is going away so it can clean up their 1027811599a4SMatt Barden * audit session, autohome dir, etc. 1028811599a4SMatt Barden * 1029811599a4SMatt Barden * Note that when we're shutting down, smbd will already have set 1030811599a4SMatt Barden * smbd.s_shutting_down and therefore will ignore door calls. 1031811599a4SMatt Barden * Skip this during shutdown to reduce upcall noise. 1032811599a4SMatt Barden */ 10339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void 10348622ec45SGordon Ross smb_user_auth_logoff(smb_user_t *user) 10359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 1036811599a4SMatt Barden smb_server_t *sv = user->u_server; 1037811599a4SMatt Barden uint32_t audit_sid; 10388622ec45SGordon Ross 1039811599a4SMatt Barden if (sv->sv_state != SMB_SERVER_STATE_RUNNING) 1040811599a4SMatt Barden return; 1041811599a4SMatt Barden 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); 10459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1046811599a4SMatt Barden 1047811599a4SMatt Barden boolean_t 1048811599a4SMatt Barden smb_is_same_user(cred_t *cr1, cred_t *cr2) 1049811599a4SMatt Barden { 1050811599a4SMatt Barden ksid_t *ks1 = crgetsid(cr1, KSID_USER); 1051811599a4SMatt Barden ksid_t *ks2 = crgetsid(cr2, KSID_USER); 1052811599a4SMatt Barden 1053bf996dbcSPrashanth Badari if (ks1 == NULL || ks2 == NULL) { 1054bf996dbcSPrashanth Badari return (B_FALSE); 1055bf996dbcSPrashanth Badari } 1056811599a4SMatt Barden return (ks1->ks_rid == ks2->ks_rid && 1057811599a4SMatt Barden strcmp(ks1->ks_domain->kd_name, ks2->ks_domain->kd_name) == 0); 1058811599a4SMatt Barden } 1059