15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 226139Sjb150015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_acl.c 1.5 08/07/28 SMI" 275331Samw 285331Samw #include <sys/acl.h> 295521Sas200622 #include <acl/acl_common.h> 306432Sas200622 #include <smbsrv/smb_sid.h> 315331Samw #include <smbsrv/smb_fsops.h> 325331Samw #include <smbsrv/smb_idmap.h> 335521Sas200622 #include <smbsrv/smb_kproto.h> 345521Sas200622 #include <smbsrv/ntstatus.h> 355521Sas200622 #include <smbsrv/ntaccess.h> 365331Samw 375331Samw #define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE) 385331Samw 395331Samw #define ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER) 405331Samw #define ZACE_IS_OWNGRP(zace) \ 415331Samw ((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP)) 425331Samw 435331Samw #define ZACE_IS_USER(zace) \ 445331Samw (((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace))) 455331Samw #define ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP) 465331Samw #define ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE) 475331Samw 485331Samw #define ZACE_IS_PROPAGATE(zace) \ 495331Samw ((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0) 505331Samw 515331Samw #define ZACE_IS_CREATOR_OWNER(zace) \ 525331Samw (ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID)) 535331Samw 545331Samw #define ZACE_IS_CREATOR_GROUP(zace) \ 555331Samw (ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID)) 565331Samw 575331Samw #define ZACE_IS_CREATOR(zace) \ 585331Samw (ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace)) 595331Samw 605331Samw /* 615331Samw * ACE groups within a DACL 625331Samw * 635331Samw * This is from lower to higher ACE order priority 645331Samw */ 655331Samw #define SMB_AG_START 0 665331Samw #define SMB_AG_ALW_INHRT 0 675331Samw #define SMB_AG_DNY_INHRT 1 685331Samw #define SMB_AG_ALW_DRCT 2 695331Samw #define SMB_AG_DNY_DRCT 3 705331Samw #define SMB_AG_NUM 4 715331Samw 725331Samw /* 735521Sas200622 * SID for Everyone group: S-1-1-0. 745521Sas200622 */ 756432Sas200622 smb_sid_t everyone_sid = { 765521Sas200622 NT_SID_REVISION, 775521Sas200622 1, 785521Sas200622 NT_SECURITY_WORLD_AUTH, 795521Sas200622 { 0 } 805521Sas200622 }; 815521Sas200622 825521Sas200622 #define DEFAULT_DACL_ACENUM 2 835521Sas200622 /* 845521Sas200622 * Default ACL: 855521Sas200622 * owner: full access 865521Sas200622 * SYSTEM: full access 875521Sas200622 */ 885521Sas200622 static ace_t default_dacl[DEFAULT_DACL_ACENUM] = { 895521Sas200622 { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE }, 905521Sas200622 { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP, 915521Sas200622 ACE_ACCESS_ALLOWED_ACE_TYPE } 925521Sas200622 }; 935521Sas200622 945521Sas200622 /* 955521Sas200622 * Note: 965331Samw * 975521Sas200622 * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format 985521Sas200622 * smb_fsacl_xxx functions work with acl_t which represents the Solaris native 995521Sas200622 * format 1005521Sas200622 */ 1015521Sas200622 102*7348SJose.Borrego@Sun.COM static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t); 103*7348SJose.Borrego@Sun.COM static acl_t *smb_fsacl_null_empty(boolean_t); 1045521Sas200622 static int smb_fsacl_inheritable(acl_t *, int); 1055521Sas200622 1065521Sas200622 static void smb_ace_inherit(ace_t *, ace_t *, int); 1075521Sas200622 static boolean_t smb_ace_isvalid(smb_ace_t *, int); 1085521Sas200622 static uint16_t smb_ace_len(smb_ace_t *); 1095521Sas200622 static uint32_t smb_ace_mask_g2s(uint32_t); 110*7348SJose.Borrego@Sun.COM static uint16_t smb_ace_flags_tozfs(uint8_t); 1115521Sas200622 static uint8_t smb_ace_flags_fromzfs(uint16_t); 1125521Sas200622 1135521Sas200622 smb_acl_t * 1145521Sas200622 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt) 1155521Sas200622 { 1165521Sas200622 smb_acl_t *acl; 1175521Sas200622 int size; 1185521Sas200622 1195521Sas200622 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t)); 1205521Sas200622 acl = kmem_zalloc(size, KM_SLEEP); 1215521Sas200622 acl->sl_revision = revision; 1225521Sas200622 acl->sl_bsize = bsize; 1235521Sas200622 acl->sl_acecnt = acecnt; 1245521Sas200622 acl->sl_aces = (smb_ace_t *)(acl + 1); 1255521Sas200622 1265521Sas200622 list_create(&acl->sl_sorted, sizeof (smb_ace_t), 1275521Sas200622 offsetof(smb_ace_t, se_sln)); 1285521Sas200622 return (acl); 1295521Sas200622 } 1305521Sas200622 1315521Sas200622 void 1325521Sas200622 smb_acl_free(smb_acl_t *acl) 1335521Sas200622 { 1345521Sas200622 int i, size; 1355521Sas200622 void *ace; 1365521Sas200622 1375521Sas200622 if (acl == NULL) 1385521Sas200622 return; 1395521Sas200622 1406432Sas200622 for (i = 0; i < acl->sl_acecnt; i++) 1416432Sas200622 smb_sid_free(acl->sl_aces[i].se_sid); 1425521Sas200622 1435521Sas200622 while ((ace = list_head(&acl->sl_sorted)) != NULL) 1445521Sas200622 list_remove(&acl->sl_sorted, ace); 1455521Sas200622 list_destroy(&acl->sl_sorted); 1465521Sas200622 1475521Sas200622 size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t)); 1485521Sas200622 kmem_free(acl, size); 1495521Sas200622 } 1505521Sas200622 1515521Sas200622 /* 1525521Sas200622 * smb_acl_len 1535521Sas200622 * 1545521Sas200622 * Returns the size of given ACL in bytes. Note that this 1555521Sas200622 * is not an in-memory size, it's the ACL's size as it would 1565521Sas200622 * appear on the wire 1575521Sas200622 */ 1585521Sas200622 uint16_t 1595521Sas200622 smb_acl_len(smb_acl_t *acl) 1605521Sas200622 { 161*7348SJose.Borrego@Sun.COM return ((acl) ? acl->sl_bsize : 0); 1625521Sas200622 } 1635521Sas200622 1645521Sas200622 boolean_t 1655521Sas200622 smb_acl_isvalid(smb_acl_t *acl, int which_acl) 1665521Sas200622 { 1675521Sas200622 int i; 1685521Sas200622 1695521Sas200622 if (acl->sl_bsize < SMB_ACL_HDRSIZE) 1705521Sas200622 return (B_FALSE); 1715521Sas200622 1725521Sas200622 if (acl->sl_revision != ACL_REVISION) { 1735521Sas200622 /* 1745521Sas200622 * we are rejecting ACLs with object-specific ACEs for now 1755521Sas200622 */ 1765521Sas200622 return (B_FALSE); 1775521Sas200622 } 1785521Sas200622 1795521Sas200622 for (i = 0; i < acl->sl_acecnt; i++) { 1805521Sas200622 if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl)) 1815521Sas200622 return (B_FALSE); 1825521Sas200622 } 1835521Sas200622 1845521Sas200622 return (B_TRUE); 1855521Sas200622 } 1865521Sas200622 1875521Sas200622 /* 1885521Sas200622 * smb_acl_sort 1895521Sas200622 * 1905521Sas200622 * Sorts the given ACL in place if it needs to be sorted. 1915331Samw * 1925331Samw * The following is an excerpt from MSDN website. 1935331Samw * 1945331Samw * Order of ACEs in a DACL 1955331Samw * 1965331Samw * For Windows NT versions 4.0 and earlier, the preferred order of ACEs 1975331Samw * is simple: In a DACL, all access-denied ACEs should precede any 1985331Samw * access-allowed ACEs. 1995331Samw * 2005331Samw * For Windows 2000 or later, the proper order of ACEs is more complicated 2015331Samw * because of the introduction of object-specific ACEs and automatic 2025331Samw * inheritance. 2035331Samw * 2045331Samw * The following describes the preferred order: 2055331Samw * 2065331Samw * To ensure that noninherited ACEs have precedence over inherited ACEs, 2075331Samw * place all noninherited ACEs in a group before any inherited ACEs. This 2085331Samw * ordering ensures, for example, that a noninherited access-denied ACE 2095331Samw * is enforced regardless of any inherited ACE that allows access. 2105331Samw * Within the groups of noninherited ACEs and inherited ACEs, order ACEs 2115331Samw * according to ACE type, as the following shows: 2125331Samw * . Access-denied ACEs that apply to the object itself 2135331Samw * . Access-denied ACEs that apply to a subobject of the 2145331Samw * object, such as a property set or property 2155331Samw * . Access-allowed ACEs that apply to the object itself 2165331Samw * . Access-allowed ACEs that apply to a subobject of the object 2175331Samw * 2185521Sas200622 * So, here is the desired ACE order 2195331Samw * 2205331Samw * deny-direct, allow-direct, deny-inherited, allow-inherited 2215331Samw * 2225521Sas200622 * Of course, not all ACE types are required in an ACL. 2235331Samw */ 2245521Sas200622 void 2255331Samw smb_acl_sort(smb_acl_t *acl) 2265331Samw { 2275521Sas200622 list_t ace_grps[SMB_AG_NUM]; 2285521Sas200622 list_t *alist; 2295331Samw smb_ace_t *ace; 2305331Samw uint8_t ace_flags; 2315521Sas200622 int ag, i; 2325331Samw 2335331Samw ASSERT(acl); 2345331Samw 2355331Samw if (acl->sl_acecnt == 0) { 2365331Samw /* 2375331Samw * ACL with no entry is a valid ACL and it means 2385331Samw * no access for anybody. 2395331Samw */ 2405521Sas200622 return; 2415331Samw } 2425331Samw 2435331Samw for (i = SMB_AG_START; i < SMB_AG_NUM; i++) { 2445521Sas200622 list_create(&ace_grps[i], sizeof (smb_ace_t), 2455521Sas200622 offsetof(smb_ace_t, se_sln)); 2465331Samw } 2475331Samw 2485521Sas200622 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) { 2495521Sas200622 ace_flags = ace->se_hdr.se_flags; 2505331Samw 2515521Sas200622 switch (ace->se_hdr.se_type) { 2525331Samw case ACCESS_DENIED_ACE_TYPE: 2535521Sas200622 ag = (ace_flags & INHERITED_ACE) ? 2545521Sas200622 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT; 2555331Samw break; 2565331Samw 2575331Samw case ACCESS_ALLOWED_ACE_TYPE: 2585521Sas200622 ag = (ace_flags & INHERITED_ACE) ? 2595521Sas200622 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT; 2605331Samw break; 2615331Samw 2625331Samw default: 2635331Samw /* 2645331Samw * This is the lowest priority group so we put 2655331Samw * evertything unknown here. 2665331Samw */ 2675331Samw ag = SMB_AG_ALW_INHRT; 2685331Samw break; 2695331Samw } 2705331Samw 2715521Sas200622 /* Add the ACE to the selected group */ 2725521Sas200622 list_insert_tail(&ace_grps[ag], ace); 2735331Samw } 2745331Samw 2755521Sas200622 /* 2765521Sas200622 * start with highest priority ACE group and append 2775521Sas200622 * the ACEs to the ACL. 2785521Sas200622 */ 2795521Sas200622 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) { 2805521Sas200622 alist = &ace_grps[i]; 2815521Sas200622 while ((ace = list_head(alist)) != NULL) { 2825521Sas200622 list_remove(alist, ace); 2835521Sas200622 list_insert_tail(&acl->sl_sorted, ace); 2845521Sas200622 } 2855521Sas200622 list_destroy(alist); 2865331Samw } 2875331Samw } 2885331Samw 2895521Sas200622 /* 2905521Sas200622 * smb_acl_from_zfs 2915521Sas200622 * 2925521Sas200622 * Converts given ZFS ACL to a Windows ACL. 2935521Sas200622 * 2945521Sas200622 * A pointer to allocated memory for the Win ACL will be 2955521Sas200622 * returned upon successful conversion. 2965521Sas200622 */ 2975521Sas200622 smb_acl_t * 2985521Sas200622 smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid) 2995331Samw { 3005521Sas200622 ace_t *zace; 3015521Sas200622 int numaces; 3025521Sas200622 smb_acl_t *acl; 3035331Samw smb_ace_t *ace; 3045521Sas200622 smb_idmap_batch_t sib; 3055521Sas200622 smb_idmap_t *sim; 3065521Sas200622 idmap_stat idm_stat; 3075331Samw 3085521Sas200622 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt, 3095521Sas200622 SMB_IDMAP_ID2SID); 3105521Sas200622 if (idm_stat != IDMAP_SUCCESS) 3115331Samw return (NULL); 3125331Samw 313*7348SJose.Borrego@Sun.COM if (smb_fsacl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) { 3145521Sas200622 smb_idmap_batch_destroy(&sib); 3155521Sas200622 return (NULL); 3165331Samw } 3175331Samw 3185521Sas200622 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt); 3195331Samw 3205521Sas200622 sim = sib.sib_maps; 3215521Sas200622 for (numaces = 0, zace = zacl->acl_aclp; 3225521Sas200622 numaces < zacl->acl_cnt; 3235521Sas200622 zace++, numaces++, sim++) { 3245521Sas200622 ASSERT(sim->sim_sid); 3255521Sas200622 if (sim->sim_sid == NULL) { 3265521Sas200622 smb_acl_free(acl); 3275521Sas200622 acl = NULL; 3285521Sas200622 break; 3295521Sas200622 } 3305331Samw 3315521Sas200622 ace = &acl->sl_aces[numaces]; 3325521Sas200622 ace->se_hdr.se_type = zace->a_type; 3335521Sas200622 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags); 3345521Sas200622 ace->se_mask = zace->a_access_mask; 3356432Sas200622 ace->se_sid = smb_sid_dup(sim->sim_sid); 3365521Sas200622 ace->se_hdr.se_bsize = smb_ace_len(ace); 3375521Sas200622 3385521Sas200622 acl->sl_bsize += ace->se_hdr.se_bsize; 3395331Samw } 3405331Samw 3415521Sas200622 smb_idmap_batch_destroy(&sib); 3425521Sas200622 return (acl); 3435331Samw } 3445331Samw 3455331Samw /* 3465521Sas200622 * smb_acl_to_zfs 3475331Samw * 3485521Sas200622 * Converts given Windows ACL to a ZFS ACL. 3495331Samw * 3505521Sas200622 * fs_acl will contain a pointer to the created ZFS ACL. 3515521Sas200622 * The allocated memory should be freed by calling 3525521Sas200622 * smb_fsacl_free(). 3535331Samw * 3545521Sas200622 * Since the output parameter, fs_acl, is allocated in this 3555521Sas200622 * function, the caller has to make sure *fs_acl is NULL which 3565521Sas200622 * means it's not pointing to any memory. 3575331Samw */ 3585331Samw uint32_t 3595521Sas200622 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl) 3605331Samw { 3615521Sas200622 smb_ace_t *ace; 3625521Sas200622 acl_t *zacl; 3635521Sas200622 ace_t *zace; 3645521Sas200622 smb_idmap_batch_t sib; 3655521Sas200622 smb_idmap_t *sim; 3665521Sas200622 idmap_stat idm_stat; 367*7348SJose.Borrego@Sun.COM int i; 3685331Samw 3695521Sas200622 ASSERT(fs_acl); 3705521Sas200622 ASSERT(*fs_acl == NULL); 3715521Sas200622 3725521Sas200622 if (acl && !smb_acl_isvalid(acl, which_acl)) 3735521Sas200622 return (NT_STATUS_INVALID_ACL); 3745521Sas200622 3755521Sas200622 if ((acl == NULL) || (acl->sl_acecnt == 0)) { 3765521Sas200622 if (which_acl == SMB_DACL_SECINFO) { 377*7348SJose.Borrego@Sun.COM *fs_acl = smb_fsacl_null_empty(acl == NULL); 3785521Sas200622 } 3795521Sas200622 3805521Sas200622 return (NT_STATUS_SUCCESS); 3815331Samw } 3825331Samw 3835521Sas200622 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt, 3845521Sas200622 SMB_IDMAP_SID2ID); 3855521Sas200622 if (idm_stat != IDMAP_SUCCESS) 3865521Sas200622 return (NT_STATUS_INTERNAL_ERROR); 3875521Sas200622 3885521Sas200622 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags); 3895521Sas200622 3905521Sas200622 zace = zacl->acl_aclp; 3915521Sas200622 ace = acl->sl_aces; 3925521Sas200622 sim = sib.sib_maps; 3935521Sas200622 3945521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 3955521Sas200622 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES; 3965521Sas200622 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask); 397*7348SJose.Borrego@Sun.COM zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags); 3985521Sas200622 3996432Sas200622 if (smb_sid_cmp(ace->se_sid, &everyone_sid)) 4005521Sas200622 zace->a_flags |= ACE_EVERYONE; 4015521Sas200622 else { 4025521Sas200622 sim->sim_id = &zace->a_who; 4035521Sas200622 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, 4045521Sas200622 ace->se_sid, -1); 4055521Sas200622 4065521Sas200622 if (idm_stat != IDMAP_SUCCESS) { 4075521Sas200622 smb_fsacl_free(zacl); 4085521Sas200622 smb_idmap_batch_destroy(&sib); 4095521Sas200622 return (NT_STATUS_INTERNAL_ERROR); 4105521Sas200622 } 4115521Sas200622 } 4125331Samw } 4135331Samw 4145521Sas200622 idm_stat = smb_idmap_batch_getmappings(&sib); 4155521Sas200622 if (idm_stat != IDMAP_SUCCESS) { 4165521Sas200622 smb_fsacl_free(zacl); 4175521Sas200622 smb_idmap_batch_destroy(&sib); 4185521Sas200622 return (NT_STATUS_NONE_MAPPED); 4195331Samw } 4205331Samw 4215521Sas200622 /* 4225521Sas200622 * Set the ACEs group flag based on the type of ID returned. 4235521Sas200622 */ 4245521Sas200622 zace = zacl->acl_aclp; 4255521Sas200622 ace = acl->sl_aces; 4265521Sas200622 sim = sib.sib_maps; 4275521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 4285521Sas200622 if (zace->a_flags & ACE_EVERYONE) 4295521Sas200622 continue; 4305521Sas200622 4315521Sas200622 if (sim->sim_idtype == SMB_IDMAP_GROUP) 4325521Sas200622 zace->a_flags |= ACE_IDENTIFIER_GROUP; 4335331Samw } 4345331Samw 4355521Sas200622 smb_idmap_batch_destroy(&sib); 4365521Sas200622 4375521Sas200622 *fs_acl = zacl; 4385521Sas200622 return (NT_STATUS_SUCCESS); 4395331Samw } 4405331Samw 4415331Samw /* 442*7348SJose.Borrego@Sun.COM * smb_fsacl_getsids 4435331Samw * 4445331Samw * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs. 4455331Samw */ 4465331Samw static idmap_stat 447*7348SJose.Borrego@Sun.COM smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid) 4485331Samw { 4495331Samw ace_t *zace; 4505331Samw idmap_stat idm_stat; 4515331Samw smb_idmap_t *sim; 4525331Samw uid_t id; 4535331Samw int i, idtype; 4545331Samw 4555331Samw sim = sib->sib_maps; 4565331Samw 4575331Samw for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; 4585331Samw zace++, i++, sim++) { 4595331Samw switch (zace->a_flags & ACE_TYPE_FLAGS) { 4605331Samw case ACE_OWNER: 4615331Samw id = uid; 4625331Samw idtype = SMB_IDMAP_USER; 4635331Samw break; 4645331Samw 4655331Samw case (ACE_GROUP | ACE_IDENTIFIER_GROUP): 4665331Samw /* owning group */ 4675331Samw id = gid; 4685331Samw idtype = SMB_IDMAP_GROUP; 4695331Samw break; 4705331Samw 4715331Samw case ACE_IDENTIFIER_GROUP: 4725331Samw /* regular group */ 4735331Samw id = zace->a_who; 4745331Samw idtype = SMB_IDMAP_GROUP; 4755331Samw break; 4765331Samw 4775331Samw case ACE_EVERYONE: 4785331Samw idtype = SMB_IDMAP_EVERYONE; 4795331Samw break; 4805331Samw 4815331Samw default: 4825331Samw /* user entry */ 4835331Samw id = zace->a_who; 4845331Samw idtype = SMB_IDMAP_USER; 4855331Samw } 4865331Samw 4875331Samw idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim, 4885331Samw id, idtype); 4895331Samw 4905331Samw if (idm_stat != IDMAP_SUCCESS) { 4915331Samw return (idm_stat); 4925331Samw } 4935331Samw } 4945331Samw 4955331Samw idm_stat = smb_idmap_batch_getmappings(sib); 4965331Samw return (idm_stat); 4975331Samw } 4985331Samw 4995331Samw /* 500*7348SJose.Borrego@Sun.COM * smb_fsacl_null_empty 5015331Samw * 5025331Samw * NULL DACL means everyone full-access 5035331Samw * Empty DACL means everyone full-deny 5045331Samw * 5055331Samw * ZFS ACL must have at least one entry so smb server has 5065331Samw * to simulate the aforementioned expected behavior by adding 5075331Samw * an entry in case the requested DACL is null or empty. Adding 5085331Samw * a everyone full-deny entry has proved to be problematic in 5095331Samw * tests since a deny entry takes precedence over allow entries. 5105331Samw * So, instead of adding a everyone full-deny, an owner ACE with 5115331Samw * owner implicit permissions will be set. 5125331Samw */ 5135521Sas200622 static acl_t * 514*7348SJose.Borrego@Sun.COM smb_fsacl_null_empty(boolean_t null) 5155331Samw { 5165331Samw acl_t *zacl; 5175331Samw ace_t *zace; 5185331Samw 5195521Sas200622 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT); 5205331Samw zace = zacl->acl_aclp; 5215331Samw 5225331Samw zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 5235331Samw if (null) { 5245331Samw zace->a_access_mask = ACE_ALL_PERMS; 5255331Samw zace->a_flags = ACE_EVERYONE; 5265331Samw } else { 5275331Samw zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL | 5285331Samw ACE_READ_ATTRIBUTES; 5295331Samw zace->a_flags = ACE_OWNER; 5305331Samw } 5315331Samw 5325331Samw return (zacl); 5335331Samw } 5345331Samw 5355331Samw /* 5365521Sas200622 * FS ACL (acl_t) Functions 5375331Samw */ 5385521Sas200622 acl_t * 5395521Sas200622 smb_fsacl_alloc(int acenum, int flags) 5405331Samw { 5415521Sas200622 acl_t *acl; 5425331Samw 5435521Sas200622 acl = acl_alloc(ACE_T); 5445521Sas200622 acl->acl_cnt = acenum; 5455521Sas200622 acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP); 5465521Sas200622 acl->acl_flags = flags; 5475521Sas200622 return (acl); 5485521Sas200622 } 5495331Samw 5505521Sas200622 void 5515521Sas200622 smb_fsacl_free(acl_t *acl) 5525521Sas200622 { 5535521Sas200622 if (acl) 5545521Sas200622 acl_free(acl); 5555521Sas200622 } 5565331Samw 5575521Sas200622 /* 5585521Sas200622 * smb_fsop_aclmerge 5595521Sas200622 * 5605521Sas200622 * smb_fsop_aclread/write routines which interact with filesystem 5615521Sas200622 * work with single ACL. This routine merges given DACL and SACL 5625521Sas200622 * which might have been created during CIFS to FS conversion into 5635521Sas200622 * one single ACL. 5645521Sas200622 */ 5655521Sas200622 acl_t * 5665521Sas200622 smb_fsacl_merge(acl_t *dacl, acl_t *sacl) 5675521Sas200622 { 5685521Sas200622 acl_t *acl; 5695521Sas200622 int dacl_size; 5705331Samw 5715521Sas200622 ASSERT(dacl); 5725521Sas200622 ASSERT(sacl); 5735331Samw 5745521Sas200622 acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags); 5755521Sas200622 dacl_size = dacl->acl_cnt * dacl->acl_entry_size; 5765521Sas200622 bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size); 5775521Sas200622 bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size, 5785521Sas200622 sacl->acl_cnt * sacl->acl_entry_size); 5795331Samw 5805521Sas200622 return (acl); 5815331Samw } 5825331Samw 5835331Samw /* 5845521Sas200622 * smb_fsacl_split 5855331Samw * 5865521Sas200622 * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on 5875521Sas200622 * the 'which_acl' parameter. Note that output dacl/sacl parameters could be 5885521Sas200622 * NULL even if they're specified in 'which_acl', which means the target 5895521Sas200622 * doesn't have any access and/or audit ACEs. 5905331Samw */ 5915521Sas200622 void 5925521Sas200622 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl) 5935331Samw { 5945331Samw ace_t *zace; 5955521Sas200622 ace_t *access_ace; 5965521Sas200622 ace_t *audit_ace; 5975521Sas200622 int naccess, naudit; 5985521Sas200622 int get_dacl, get_sacl; 5995521Sas200622 int i; 6005521Sas200622 6015521Sas200622 *dacl = *sacl = NULL; 6025521Sas200622 naccess = naudit = 0; 6035521Sas200622 get_dacl = (which_acl & SMB_DACL_SECINFO); 6045521Sas200622 get_sacl = (which_acl & SMB_SACL_SECINFO); 6055331Samw 6065521Sas200622 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 6075521Sas200622 if (get_dacl && smb_ace_is_access(zace->a_type)) 6085521Sas200622 naccess++; 6095521Sas200622 else if (get_sacl && smb_ace_is_audit(zace->a_type)) 6105521Sas200622 naudit++; 6115521Sas200622 } 6125331Samw 6135521Sas200622 if (naccess) { 6145521Sas200622 *dacl = smb_fsacl_alloc(naccess, zacl->acl_flags); 6155521Sas200622 access_ace = (*dacl)->acl_aclp; 6165521Sas200622 } 6175331Samw 6185521Sas200622 if (naudit) { 6195521Sas200622 *sacl = smb_fsacl_alloc(naudit, zacl->acl_flags); 6205521Sas200622 audit_ace = (*sacl)->acl_aclp; 6215521Sas200622 } 6225331Samw 6235521Sas200622 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 6245521Sas200622 if (get_dacl && smb_ace_is_access(zace->a_type)) { 6255521Sas200622 *access_ace = *zace; 6265521Sas200622 access_ace++; 6275521Sas200622 } else if (get_sacl && smb_ace_is_audit(zace->a_type)) { 6285521Sas200622 *audit_ace = *zace; 6295521Sas200622 audit_ace++; 6305331Samw } 6315331Samw } 6325331Samw } 6335331Samw 6345331Samw /* 6355521Sas200622 * ACE Inheritance Rules 6365521Sas200622 * 6375521Sas200622 * The system propagates inheritable ACEs to child objects according to a 6385521Sas200622 * set of inheritance rules. The system places inherited ACEs in the child's 6395521Sas200622 * DACL according to the preferred order of ACEs in a DACL. For Windows 6405521Sas200622 * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs. 6415521Sas200622 * 6425521Sas200622 * The following table shows the ACEs inherited by container and noncontainer 6435521Sas200622 * child objects for different combinations of inheritance flags. These 6445521Sas200622 * inheritance rules work the same for both DACLs and SACLs. 6455521Sas200622 * 6465521Sas200622 * Parent ACE type Effect on Child ACL 6475521Sas200622 * ----------------------- ------------------- 6485521Sas200622 * OBJECT_INHERIT_ACE only Noncontainer child objects: 6495521Sas200622 * Inherited as an effective ACE. 6505521Sas200622 * Container child objects: 6515521Sas200622 * Containers inherit an inherit-only ACE 6525521Sas200622 * unless the NO_PROPAGATE_INHERIT_ACE bit 6535521Sas200622 * flag is also set. 6545521Sas200622 * 6555521Sas200622 * CONTAINER_INHERIT_ACE only Noncontainer child objects: 6565521Sas200622 * No effect on the child object. 6575521Sas200622 * Container child objects: 6585521Sas200622 * The child object inherits an effective ACE. 6595521Sas200622 * The inherited ACE is inheritable unless the 6605521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set. 6615521Sas200622 * 6625521Sas200622 * CONTAINER_INHERIT_ACE and 6635521Sas200622 * OBJECT_INHERIT_ACE Noncontainer child objects: 6645521Sas200622 * Inherited as an effective ACE. 6655521Sas200622 * Container child objects: 6665521Sas200622 * The child object inherits an effective ACE. 6675521Sas200622 * The inherited ACE is inheritable unless the 6685521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set 6695521Sas200622 * 6705521Sas200622 * No inheritance flags set No effect on child container or noncontainer 6715521Sas200622 * objects. 6725521Sas200622 * 6735521Sas200622 * If an inherited ACE is an effective ACE for the child object, the system 6745521Sas200622 * maps any generic rights to the specific rights for the child object. 6755521Sas200622 * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the 6765521Sas200622 * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic 6775521Sas200622 * rights or generic SIDs are left unchanged so that they can be mapped 6785521Sas200622 * appropriately when the ACE is inherited by the next generation of child 6795521Sas200622 * objects. 6805521Sas200622 * 6815521Sas200622 * For a case in which a container object inherits an ACE that is both 6825521Sas200622 * effective on the container and inheritable by its descendants, the 6835521Sas200622 * container may inherit two ACEs. This occurs if the inheritable ACE 6845521Sas200622 * contains generic information. The container inherits an inherit-only 6855521Sas200622 * ACE containing the generic information and an effective-only ACE in 6865521Sas200622 * which the generic information has been mapped. 6875331Samw */ 6885331Samw 6895331Samw /* 6905521Sas200622 * smb_fsacl_inherit 6915331Samw * 6925331Samw * Manufacture the inherited ACL from the given ACL considering 6935331Samw * the new object type (file/dir) specified by 'is_dir'. The 6945331Samw * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions. 6955521Sas200622 * This function implements Windows inheritance rules explained above. 6965331Samw * 6975521Sas200622 * Note that the in/out ACLs are ZFS ACLs not Windows ACLs 6985331Samw */ 6995331Samw acl_t * 7005521Sas200622 smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid) 7015331Samw { 7025331Samw boolean_t use_default = B_FALSE; 7035331Samw int num_inheritable = 0; 7045331Samw int numaces; 7055331Samw ace_t *dir_zace; 7065331Samw acl_t *new_zacl; 7075331Samw ace_t *new_zace; 7085331Samw 7095521Sas200622 num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir); 7105331Samw 7115331Samw if (num_inheritable == 0) { 7125331Samw if (which_acl == SMB_DACL_SECINFO) { 7135331Samw /* No inheritable access ACEs -> default DACL */ 7145331Samw num_inheritable = DEFAULT_DACL_ACENUM; 7155331Samw use_default = B_TRUE; 7165331Samw } else { 7175331Samw return (NULL); 7185331Samw } 7195331Samw } 7205331Samw 7215521Sas200622 new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT); 7225331Samw new_zace = new_zacl->acl_aclp; 7235331Samw 7245331Samw if (use_default) { 7255331Samw bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl)); 7265331Samw new_zace->a_who = owner_uid; 7275331Samw return (new_zacl); 7285331Samw } 7295331Samw 7305331Samw for (numaces = 0, dir_zace = dir_zacl->acl_aclp; 7315331Samw numaces < dir_zacl->acl_cnt; 7325331Samw dir_zace++, numaces++) { 7335331Samw switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) { 7345331Samw case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE): 7355331Samw /* 7365331Samw * Files inherit an effective ACE. 7375331Samw * 7385331Samw * Dirs inherit an effective ACE. 7395331Samw * The inherited ACE is inheritable unless the 7405331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set 7415331Samw */ 7425331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 7435331Samw new_zace++; 7445331Samw 7455331Samw if (is_dir && ZACE_IS_CREATOR(dir_zace) && 7465331Samw (ZACE_IS_PROPAGATE(dir_zace))) { 7475331Samw *new_zace = *dir_zace; 7485331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 7495331Samw ACE_INHERITED_ACE); 7505331Samw new_zace++; 7515331Samw } 7525331Samw break; 7535331Samw 7545331Samw case ACE_FILE_INHERIT_ACE: 7555331Samw /* 7565331Samw * Files inherit as an effective ACE. 7575331Samw * 7585331Samw * Dirs inherit an inherit-only ACE 7595331Samw * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit 7605331Samw * flag is also set. 7615331Samw */ 7625331Samw if (is_dir == 0) { 7635331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 7645331Samw new_zace++; 7655331Samw } else if (ZACE_IS_PROPAGATE(dir_zace)) { 7665331Samw *new_zace = *dir_zace; 7675331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 7685331Samw ACE_INHERITED_ACE); 7695331Samw new_zace++; 7705331Samw } 7715331Samw break; 7725331Samw 7735331Samw case ACE_DIRECTORY_INHERIT_ACE: 7745331Samw /* 7755331Samw * No effect on files 7765331Samw * 7775331Samw * Dirs inherit an effective ACE. 7785331Samw * The inherited ACE is inheritable unless the 7795331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set. 7805331Samw */ 7815331Samw if (is_dir == 0) 7825331Samw break; 7835331Samw 7845331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 7855331Samw new_zace++; 7865331Samw 7875331Samw if (ZACE_IS_CREATOR(dir_zace) && 7885331Samw (ZACE_IS_PROPAGATE(dir_zace))) { 7895331Samw *new_zace = *dir_zace; 7905331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 7915331Samw ACE_INHERITED_ACE); 7925331Samw new_zace++; 7935331Samw } 7945331Samw 7955331Samw break; 7965331Samw 7975331Samw default: 7985331Samw break; 7995331Samw } 8005331Samw } 8015331Samw 8025331Samw return (new_zacl); 8035331Samw } 8045331Samw 8055521Sas200622 /* 8065521Sas200622 * smb_fsacl_from_vsa 8075521Sas200622 * 8085521Sas200622 * Converts given vsecattr_t structure to a acl_t structure. 8095521Sas200622 * 8105521Sas200622 * The allocated memory for retuned acl_t should be freed by 8115521Sas200622 * calling acl_free(). 8125521Sas200622 */ 8135521Sas200622 acl_t * 8145521Sas200622 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type) 8155521Sas200622 { 8165521Sas200622 int aclbsize = 0; /* size of acl list in bytes */ 8175521Sas200622 int dfaclbsize = 0; /* size of default acl list in bytes */ 8185521Sas200622 int numacls; 8195521Sas200622 acl_t *acl_info; 8205521Sas200622 8215521Sas200622 ASSERT(vsecattr); 8225521Sas200622 8235521Sas200622 acl_info = acl_alloc(acl_type); 8245521Sas200622 if (acl_info == NULL) 8255521Sas200622 return (NULL); 8265521Sas200622 8275521Sas200622 acl_info->acl_flags = 0; 8285521Sas200622 8295521Sas200622 switch (acl_type) { 8305521Sas200622 8315521Sas200622 case ACLENT_T: 8325521Sas200622 numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt; 8335521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t); 8345521Sas200622 dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t); 8355521Sas200622 8365521Sas200622 acl_info->acl_cnt = numacls; 8375521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize, 8385521Sas200622 KM_SLEEP); 8395521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 8405521Sas200622 aclbsize); 8415521Sas200622 (void) memcpy((char *)acl_info->acl_aclp + aclbsize, 8425521Sas200622 vsecattr->vsa_dfaclentp, dfaclbsize); 8435521Sas200622 8445521Sas200622 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 8455521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL; 8465521Sas200622 8475521Sas200622 break; 8485521Sas200622 8495521Sas200622 case ACE_T: 8505521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 8515521Sas200622 acl_info->acl_cnt = vsecattr->vsa_aclcnt; 8525521Sas200622 acl_info->acl_flags = vsecattr->vsa_aclflags; 8535521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP); 8545521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 8555521Sas200622 aclbsize); 8565521Sas200622 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 8575521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL; 8585521Sas200622 8595521Sas200622 break; 8605521Sas200622 8615521Sas200622 default: 8625521Sas200622 acl_free(acl_info); 8635521Sas200622 return (NULL); 8645521Sas200622 } 8655521Sas200622 8665521Sas200622 if (aclbsize && vsecattr->vsa_aclentp) 8675521Sas200622 kmem_free(vsecattr->vsa_aclentp, aclbsize); 8685521Sas200622 if (dfaclbsize && vsecattr->vsa_dfaclentp) 8695521Sas200622 kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize); 8705521Sas200622 8715521Sas200622 return (acl_info); 8725521Sas200622 } 8735521Sas200622 8745521Sas200622 /* 8755521Sas200622 * smb_fsacl_to_vsa 8765521Sas200622 * 8775521Sas200622 * Converts given acl_t structure to a vsecattr_t structure. 8785521Sas200622 * 8795521Sas200622 * IMPORTANT: 8805521Sas200622 * Upon successful return the memory allocated for vsa_aclentp 8815521Sas200622 * should be freed by calling kmem_free(). The size is returned 8825521Sas200622 * in aclbsize. 8835521Sas200622 */ 8845521Sas200622 int 8855521Sas200622 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize) 8865521Sas200622 { 8875521Sas200622 int error = 0; 8885521Sas200622 int numacls; 8895521Sas200622 aclent_t *aclp; 8905521Sas200622 8915521Sas200622 ASSERT(acl_info); 8925521Sas200622 ASSERT(vsecattr); 8935521Sas200622 ASSERT(aclbsize); 8945521Sas200622 8955521Sas200622 bzero(vsecattr, sizeof (vsecattr_t)); 8965521Sas200622 *aclbsize = 0; 8975521Sas200622 8985521Sas200622 switch (acl_info->acl_type) { 8995521Sas200622 case ACLENT_T: 9005521Sas200622 numacls = acl_info->acl_cnt; 9015521Sas200622 /* 9025521Sas200622 * Minimum ACL size is three entries so might as well 9035521Sas200622 * bail out here. Also limit request size to prevent user 9045521Sas200622 * from allocating too much kernel memory. Maximum size 9055521Sas200622 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 9065521Sas200622 * for the default ACL part. 9075521Sas200622 */ 9085521Sas200622 if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) { 9095521Sas200622 error = EINVAL; 9105521Sas200622 break; 9115521Sas200622 } 9125521Sas200622 9135521Sas200622 vsecattr->vsa_mask = VSA_ACL; 9145521Sas200622 9155521Sas200622 vsecattr->vsa_aclcnt = numacls; 9165521Sas200622 *aclbsize = numacls * sizeof (aclent_t); 9175521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 9185521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 9195521Sas200622 *aclbsize); 9205521Sas200622 9215521Sas200622 /* Sort the acl list */ 9225521Sas200622 ksort((caddr_t)vsecattr->vsa_aclentp, 9235521Sas200622 vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls); 9245521Sas200622 9255521Sas200622 /* Break into acl and default acl lists */ 9265521Sas200622 for (numacls = 0, aclp = vsecattr->vsa_aclentp; 9275521Sas200622 numacls < vsecattr->vsa_aclcnt; 9285521Sas200622 aclp++, numacls++) { 9295521Sas200622 if (aclp->a_type & ACL_DEFAULT) 9305521Sas200622 break; 9315521Sas200622 } 9325521Sas200622 9335521Sas200622 /* Find where defaults start (if any) */ 9345521Sas200622 if (numacls < vsecattr->vsa_aclcnt) { 9355521Sas200622 vsecattr->vsa_mask |= VSA_DFACL; 9365521Sas200622 vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls; 9375521Sas200622 vsecattr->vsa_dfaclentp = aclp; 9385521Sas200622 vsecattr->vsa_aclcnt = numacls; 9395521Sas200622 } 9405521Sas200622 9415521Sas200622 /* Adjust if they're all defaults */ 9425521Sas200622 if (vsecattr->vsa_aclcnt == 0) { 9435521Sas200622 vsecattr->vsa_mask &= ~VSA_ACL; 9445521Sas200622 vsecattr->vsa_aclentp = NULL; 9455521Sas200622 } 9465521Sas200622 9475521Sas200622 /* Only directories can have defaults */ 9485521Sas200622 if (vsecattr->vsa_dfaclcnt && 9495521Sas200622 (acl_info->acl_flags & ACL_IS_DIR)) { 9505521Sas200622 error = ENOTDIR; 9515521Sas200622 } 9525521Sas200622 9535521Sas200622 break; 9545521Sas200622 9555521Sas200622 case ACE_T: 9565521Sas200622 if (acl_info->acl_cnt < 1 || 9575521Sas200622 acl_info->acl_cnt > MAX_ACL_ENTRIES) { 9585521Sas200622 error = EINVAL; 9595521Sas200622 break; 9605521Sas200622 } 9615521Sas200622 9625521Sas200622 vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; 9635521Sas200622 vsecattr->vsa_aclcnt = acl_info->acl_cnt; 9645521Sas200622 vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL; 9655521Sas200622 *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 9665521Sas200622 vsecattr->vsa_aclentsz = *aclbsize; 9675521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 9685521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 9695521Sas200622 *aclbsize); 9705521Sas200622 9715521Sas200622 break; 9725521Sas200622 9735521Sas200622 default: 9745521Sas200622 error = EINVAL; 9755521Sas200622 } 9765521Sas200622 9775521Sas200622 return (error); 9785521Sas200622 } 9795521Sas200622 9805521Sas200622 /* 9815521Sas200622 * smb_fsacl_inheritable 9825521Sas200622 * 9835521Sas200622 * Checks to see if there are any inheritable ACEs in the 9845521Sas200622 * given ZFS ACL. Returns the number of inheritable ACEs. 9855521Sas200622 * 9865521Sas200622 * The inherited ACL could be different based on the type of 9875521Sas200622 * new object (file/dir) specified by 'is_dir'. 9885521Sas200622 * 9895521Sas200622 * Note that the input ACL is a ZFS ACL not Windows ACL. 9905521Sas200622 */ 9915521Sas200622 static int 9925521Sas200622 smb_fsacl_inheritable(acl_t *zacl, int is_dir) 9935521Sas200622 { 9945521Sas200622 int numaces; 9955521Sas200622 int num_inheritable = 0; 9965521Sas200622 ace_t *zace; 9975521Sas200622 9985521Sas200622 if (zacl == NULL) 9995521Sas200622 return (0); 10005521Sas200622 10015521Sas200622 for (numaces = 0, zace = zacl->acl_aclp; 10025521Sas200622 numaces < zacl->acl_cnt; 10035521Sas200622 zace++, numaces++) { 10045521Sas200622 switch (zace->a_flags & ACE_FD_INHERIT_ACE) { 10055521Sas200622 case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE): 10065521Sas200622 /* 10075521Sas200622 * Files inherit an effective ACE. 10085521Sas200622 * 10095521Sas200622 * Dirs inherit an effective ACE. 10105521Sas200622 * The inherited ACE is inheritable unless the 10115521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set 10125521Sas200622 */ 10135521Sas200622 num_inheritable++; 10145521Sas200622 10155521Sas200622 if (is_dir && ZACE_IS_CREATOR(zace) && 10165521Sas200622 (ZACE_IS_PROPAGATE(zace))) { 10175521Sas200622 num_inheritable++; 10185521Sas200622 } 10195521Sas200622 break; 10205521Sas200622 10215521Sas200622 case ACE_FILE_INHERIT_ACE: 10225521Sas200622 /* 10235521Sas200622 * Files inherit as an effective ACE. 10245521Sas200622 * 10255521Sas200622 * Dirs inherit an inherit-only ACE 10265521Sas200622 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit 10275521Sas200622 * flag is also set. 10285521Sas200622 */ 10295521Sas200622 if (is_dir == 0) 10305521Sas200622 num_inheritable++; 10315521Sas200622 else if (ZACE_IS_PROPAGATE(zace)) 10325521Sas200622 num_inheritable++; 10335521Sas200622 break; 10345521Sas200622 10355521Sas200622 case ACE_DIRECTORY_INHERIT_ACE: 10365521Sas200622 /* 10375521Sas200622 * No effect on files 10385521Sas200622 * 10395521Sas200622 * Dirs inherit an effective ACE. 10405521Sas200622 * The inherited ACE is inheritable unless the 10415521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set. 10425521Sas200622 */ 10435521Sas200622 if (is_dir == 0) 10445521Sas200622 break; 10455521Sas200622 10465521Sas200622 num_inheritable++; 10475521Sas200622 10485521Sas200622 if (ZACE_IS_CREATOR(zace) && 10495521Sas200622 (ZACE_IS_PROPAGATE(zace))) 10505521Sas200622 num_inheritable++; 10515521Sas200622 break; 10525521Sas200622 10535521Sas200622 default: 10545521Sas200622 break; 10555521Sas200622 } 10565521Sas200622 } 10575521Sas200622 10585521Sas200622 return (num_inheritable); 10595521Sas200622 } 10605521Sas200622 10615521Sas200622 10625521Sas200622 /* 10635521Sas200622 * ACE Functions 10645521Sas200622 */ 10655521Sas200622 10665521Sas200622 /* 10675521Sas200622 * This is generic (ACL version 2) vs. object-specific 10685521Sas200622 * (ACL version 4) ACE types. 10695521Sas200622 */ 10705521Sas200622 boolean_t 10715521Sas200622 smb_ace_is_generic(int type) 10725521Sas200622 { 10735521Sas200622 switch (type) { 10745521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE: 10755521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE: 10765521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE: 10775521Sas200622 case ACE_SYSTEM_ALARM_ACE_TYPE: 10785521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE: 10795521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE: 10805521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE: 10815521Sas200622 case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE: 10825521Sas200622 return (B_TRUE); 10835521Sas200622 10845521Sas200622 default: 10855521Sas200622 break; 10865521Sas200622 } 10875521Sas200622 10885521Sas200622 return (B_FALSE); 10895521Sas200622 } 10905521Sas200622 10915521Sas200622 boolean_t 10925521Sas200622 smb_ace_is_access(int type) 10935521Sas200622 { 10945521Sas200622 switch (type) { 10955521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE: 10965521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE: 10975521Sas200622 case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE: 10985521Sas200622 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 10995521Sas200622 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 11005521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE: 11015521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE: 11025521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: 11035521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE: 11045521Sas200622 return (B_TRUE); 11055521Sas200622 11065521Sas200622 default: 11075521Sas200622 break; 11085521Sas200622 } 11095521Sas200622 11105521Sas200622 return (B_FALSE); 11115521Sas200622 } 11125521Sas200622 11135521Sas200622 boolean_t 11145521Sas200622 smb_ace_is_audit(int type) 11155521Sas200622 { 11165521Sas200622 switch (type) { 11175521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE: 11185521Sas200622 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 11195521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE: 11205521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE: 11215521Sas200622 return (B_TRUE); 11225521Sas200622 11235521Sas200622 default: 11245521Sas200622 break; 11255521Sas200622 } 11265521Sas200622 11275521Sas200622 return (B_FALSE); 11285521Sas200622 } 11295521Sas200622 11305521Sas200622 /* 11315521Sas200622 * smb_ace_len 11325521Sas200622 * 11335521Sas200622 * Returns the length of the given ACE as it appears in an 11345521Sas200622 * ACL on the wire (i.e. a flat buffer which contains the SID) 11355521Sas200622 */ 11365521Sas200622 static uint16_t 11375521Sas200622 smb_ace_len(smb_ace_t *ace) 11385521Sas200622 { 11395521Sas200622 ASSERT(ace); 11405521Sas200622 ASSERT(ace->se_sid); 11415521Sas200622 11425521Sas200622 if (ace == NULL) 11435521Sas200622 return (0); 11445521Sas200622 11455521Sas200622 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) + 11466432Sas200622 smb_sid_len(ace->se_sid)); 11475521Sas200622 } 11485521Sas200622 11495331Samw static void 11505331Samw smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir) 11515331Samw { 11525331Samw *zace = *dir_zace; 1153*7348SJose.Borrego@Sun.COM 1154*7348SJose.Borrego@Sun.COM /* This is an effective ACE so remove the inherit_only flag */ 1155*7348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_ONLY_ACE; 1156*7348SJose.Borrego@Sun.COM /* Mark this ACE as inherited */ 11575331Samw zace->a_flags |= ACE_INHERITED_ACE; 11585331Samw 11595331Samw /* 1160*7348SJose.Borrego@Sun.COM * If this is a file or NO_PROPAGATE is set then this inherited 1161*7348SJose.Borrego@Sun.COM * ACE is not inheritable so clear the inheritance flags 1162*7348SJose.Borrego@Sun.COM */ 1163*7348SJose.Borrego@Sun.COM if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace))) 1164*7348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 1165*7348SJose.Borrego@Sun.COM 1166*7348SJose.Borrego@Sun.COM /* 1167*7348SJose.Borrego@Sun.COM * Replace creator owner/group ACEs with actual owner/group ACEs. 1168*7348SJose.Borrego@Sun.COM * This would be an effictive ACE which is not inheritable. 11695331Samw */ 11705331Samw if (ZACE_IS_CREATOR_OWNER(dir_zace)) { 11715331Samw zace->a_who = (uid_t)-1; 11725331Samw zace->a_flags |= ACE_OWNER; 1173*7348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 11745331Samw } else if (ZACE_IS_CREATOR_GROUP(dir_zace)) { 11755331Samw zace->a_who = (uid_t)-1; 11765331Samw zace->a_flags |= ACE_GROUP; 1177*7348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 11785331Samw } 11795331Samw } 11805331Samw 11815521Sas200622 /* 11825521Sas200622 * smb_ace_mask_g2s 11835521Sas200622 * 11845521Sas200622 * Converts generic access bits in the given mask (if any) 11855521Sas200622 * to file specific bits. Generic access masks shouldn't be 11865521Sas200622 * stored in filesystem ACEs. 11875521Sas200622 */ 11885521Sas200622 static uint32_t 11895521Sas200622 smb_ace_mask_g2s(uint32_t mask) 11905521Sas200622 { 11915521Sas200622 if (mask & GENERIC_ALL) { 11925521Sas200622 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE 11935521Sas200622 | GENERIC_EXECUTE); 11945521Sas200622 11955521Sas200622 mask |= FILE_ALL_ACCESS; 11965521Sas200622 return (mask); 11975521Sas200622 } 11985521Sas200622 11995521Sas200622 if (mask & GENERIC_READ) { 12005521Sas200622 mask &= ~GENERIC_READ; 12015521Sas200622 mask |= FILE_GENERIC_READ; 12025521Sas200622 } 12035521Sas200622 12045521Sas200622 if (mask & GENERIC_WRITE) { 12055521Sas200622 mask &= ~GENERIC_WRITE; 12065521Sas200622 mask |= FILE_GENERIC_WRITE; 12075521Sas200622 } 12085521Sas200622 12095521Sas200622 if (mask & GENERIC_EXECUTE) { 12105521Sas200622 mask &= ~GENERIC_EXECUTE; 12115521Sas200622 mask |= FILE_GENERIC_EXECUTE; 12125521Sas200622 } 12135521Sas200622 12145521Sas200622 return (mask); 12155521Sas200622 } 12165521Sas200622 1217*7348SJose.Borrego@Sun.COM /* 1218*7348SJose.Borrego@Sun.COM * smb_ace_flags_tozfs 1219*7348SJose.Borrego@Sun.COM * 1220*7348SJose.Borrego@Sun.COM * This function maps the flags which have different values 1221*7348SJose.Borrego@Sun.COM * in Windows and Solaris. The ones with the same value are 1222*7348SJose.Borrego@Sun.COM * transferred untouched. 1223*7348SJose.Borrego@Sun.COM */ 12245331Samw static uint16_t 1225*7348SJose.Borrego@Sun.COM smb_ace_flags_tozfs(uint8_t c_flags) 12265331Samw { 12275331Samw uint16_t z_flags = 0; 12285331Samw 12295331Samw if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG) 12305331Samw z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 12315331Samw 12325331Samw if (c_flags & FAILED_ACCESS_ACE_FLAG) 12335331Samw z_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 12345331Samw 12355331Samw if (c_flags & INHERITED_ACE) 12365331Samw z_flags |= ACE_INHERITED_ACE; 12375331Samw 1238*7348SJose.Borrego@Sun.COM z_flags |= (c_flags & ACE_INHERIT_FLAGS); 12395331Samw 12405331Samw return (z_flags); 12415331Samw } 12425331Samw 12435331Samw static uint8_t 12445331Samw smb_ace_flags_fromzfs(uint16_t z_flags) 12455331Samw { 12465331Samw uint8_t c_flags; 12475331Samw 12485331Samw c_flags = z_flags & ACE_INHERIT_FLAGS; 12495331Samw 12505331Samw if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 12515331Samw c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 12525331Samw 12535331Samw if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG) 12545331Samw c_flags |= FAILED_ACCESS_ACE_FLAG; 12555331Samw 12565331Samw if (z_flags & ACE_INHERITED_ACE) 12575331Samw c_flags |= INHERITED_ACE; 12585331Samw 12595331Samw return (c_flags); 12605331Samw } 12615331Samw 12625521Sas200622 static boolean_t 12635521Sas200622 smb_ace_isvalid(smb_ace_t *ace, int which_acl) 12645331Samw { 12655521Sas200622 uint16_t min_len; 12665521Sas200622 12675521Sas200622 min_len = sizeof (smb_acehdr_t); 12685521Sas200622 12695521Sas200622 if (ace->se_hdr.se_bsize < min_len) 12705521Sas200622 return (B_FALSE); 12715521Sas200622 12725521Sas200622 if (smb_ace_is_access(ace->se_hdr.se_type) && 12735521Sas200622 (which_acl != SMB_DACL_SECINFO)) 12745521Sas200622 return (B_FALSE); 12755331Samw 12765521Sas200622 if (smb_ace_is_audit(ace->se_hdr.se_type) && 12775521Sas200622 (which_acl != SMB_SACL_SECINFO)) 12785521Sas200622 return (B_FALSE); 12795521Sas200622 12805521Sas200622 if (smb_ace_is_generic(ace->se_hdr.se_type)) { 12816432Sas200622 if (!smb_sid_isvalid(ace->se_sid)) 12825521Sas200622 return (B_FALSE); 12835521Sas200622 12845521Sas200622 min_len += sizeof (ace->se_mask); 12856432Sas200622 min_len += smb_sid_len(ace->se_sid); 12865521Sas200622 12875521Sas200622 if (ace->se_hdr.se_bsize < min_len) 12885521Sas200622 return (B_FALSE); 12895331Samw } 12905331Samw 12915521Sas200622 /* 12925521Sas200622 * object-specific ACE validation will be added later. 12935521Sas200622 */ 12945521Sas200622 return (B_TRUE); 12955331Samw } 1296