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 /* 22*11447Samw@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/acl.h> 275521Sas200622 #include <acl/acl_common.h> 286432Sas200622 #include <smbsrv/smb_sid.h> 295331Samw #include <smbsrv/smb_fsops.h> 305331Samw #include <smbsrv/smb_idmap.h> 315521Sas200622 #include <smbsrv/smb_kproto.h> 325331Samw 335331Samw #define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE) 345331Samw 355331Samw #define ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER) 365331Samw #define ZACE_IS_OWNGRP(zace) \ 375331Samw ((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP)) 385331Samw 395331Samw #define ZACE_IS_USER(zace) \ 405331Samw (((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace))) 415331Samw #define ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP) 425331Samw #define ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE) 435331Samw 445331Samw #define ZACE_IS_PROPAGATE(zace) \ 455331Samw ((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0) 465331Samw 475331Samw #define ZACE_IS_CREATOR_OWNER(zace) \ 485331Samw (ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID)) 495331Samw 505331Samw #define ZACE_IS_CREATOR_GROUP(zace) \ 515331Samw (ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID)) 525331Samw 535331Samw #define ZACE_IS_CREATOR(zace) \ 545331Samw (ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace)) 555331Samw 565331Samw /* 575331Samw * ACE groups within a DACL 585331Samw * 595331Samw * This is from lower to higher ACE order priority 605331Samw */ 615331Samw #define SMB_AG_START 0 625331Samw #define SMB_AG_ALW_INHRT 0 635331Samw #define SMB_AG_DNY_INHRT 1 645331Samw #define SMB_AG_ALW_DRCT 2 655331Samw #define SMB_AG_DNY_DRCT 3 665331Samw #define SMB_AG_NUM 4 675331Samw 685521Sas200622 #define DEFAULT_DACL_ACENUM 2 695521Sas200622 /* 705521Sas200622 * Default ACL: 715521Sas200622 * owner: full access 725521Sas200622 * SYSTEM: full access 735521Sas200622 */ 745521Sas200622 static ace_t default_dacl[DEFAULT_DACL_ACENUM] = { 755521Sas200622 { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE }, 765521Sas200622 { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP, 775521Sas200622 ACE_ACCESS_ALLOWED_ACE_TYPE } 785521Sas200622 }; 795521Sas200622 805521Sas200622 /* 815521Sas200622 * Note: 825331Samw * 835521Sas200622 * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format 845521Sas200622 * smb_fsacl_xxx functions work with acl_t which represents the Solaris native 855521Sas200622 * format 865521Sas200622 */ 875521Sas200622 88*11447Samw@Sun.COM static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *); 897348SJose.Borrego@Sun.COM static acl_t *smb_fsacl_null_empty(boolean_t); 905521Sas200622 static int smb_fsacl_inheritable(acl_t *, int); 915521Sas200622 925521Sas200622 static void smb_ace_inherit(ace_t *, ace_t *, int); 935521Sas200622 static boolean_t smb_ace_isvalid(smb_ace_t *, int); 945521Sas200622 static uint16_t smb_ace_len(smb_ace_t *); 955521Sas200622 static uint32_t smb_ace_mask_g2s(uint32_t); 967348SJose.Borrego@Sun.COM static uint16_t smb_ace_flags_tozfs(uint8_t); 975521Sas200622 static uint8_t smb_ace_flags_fromzfs(uint16_t); 98*11447Samw@Sun.COM static boolean_t smb_ace_wellknown_update(const char *, ace_t *); 995521Sas200622 1005521Sas200622 smb_acl_t * 1015521Sas200622 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt) 1025521Sas200622 { 1035521Sas200622 smb_acl_t *acl; 1045521Sas200622 int size; 1055521Sas200622 1065521Sas200622 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t)); 1075521Sas200622 acl = kmem_zalloc(size, KM_SLEEP); 1085521Sas200622 acl->sl_revision = revision; 1095521Sas200622 acl->sl_bsize = bsize; 1105521Sas200622 acl->sl_acecnt = acecnt; 1115521Sas200622 acl->sl_aces = (smb_ace_t *)(acl + 1); 1125521Sas200622 1135521Sas200622 list_create(&acl->sl_sorted, sizeof (smb_ace_t), 1145521Sas200622 offsetof(smb_ace_t, se_sln)); 1155521Sas200622 return (acl); 1165521Sas200622 } 1175521Sas200622 1185521Sas200622 void 1195521Sas200622 smb_acl_free(smb_acl_t *acl) 1205521Sas200622 { 1215521Sas200622 int i, size; 1225521Sas200622 void *ace; 1235521Sas200622 1245521Sas200622 if (acl == NULL) 1255521Sas200622 return; 1265521Sas200622 1276432Sas200622 for (i = 0; i < acl->sl_acecnt; i++) 1286432Sas200622 smb_sid_free(acl->sl_aces[i].se_sid); 1295521Sas200622 1305521Sas200622 while ((ace = list_head(&acl->sl_sorted)) != NULL) 1315521Sas200622 list_remove(&acl->sl_sorted, ace); 1325521Sas200622 list_destroy(&acl->sl_sorted); 1335521Sas200622 1345521Sas200622 size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t)); 1355521Sas200622 kmem_free(acl, size); 1365521Sas200622 } 1375521Sas200622 1385521Sas200622 /* 1395521Sas200622 * smb_acl_len 1405521Sas200622 * 1415521Sas200622 * Returns the size of given ACL in bytes. Note that this 1425521Sas200622 * is not an in-memory size, it's the ACL's size as it would 1435521Sas200622 * appear on the wire 1445521Sas200622 */ 1455521Sas200622 uint16_t 1465521Sas200622 smb_acl_len(smb_acl_t *acl) 1475521Sas200622 { 1487348SJose.Borrego@Sun.COM return ((acl) ? acl->sl_bsize : 0); 1495521Sas200622 } 1505521Sas200622 1515521Sas200622 boolean_t 1525521Sas200622 smb_acl_isvalid(smb_acl_t *acl, int which_acl) 1535521Sas200622 { 1545521Sas200622 int i; 1555521Sas200622 1565521Sas200622 if (acl->sl_bsize < SMB_ACL_HDRSIZE) 1575521Sas200622 return (B_FALSE); 1585521Sas200622 1595521Sas200622 if (acl->sl_revision != ACL_REVISION) { 1605521Sas200622 /* 1615521Sas200622 * we are rejecting ACLs with object-specific ACEs for now 1625521Sas200622 */ 1635521Sas200622 return (B_FALSE); 1645521Sas200622 } 1655521Sas200622 1665521Sas200622 for (i = 0; i < acl->sl_acecnt; i++) { 1675521Sas200622 if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl)) 1685521Sas200622 return (B_FALSE); 1695521Sas200622 } 1705521Sas200622 1715521Sas200622 return (B_TRUE); 1725521Sas200622 } 1735521Sas200622 1745521Sas200622 /* 1755521Sas200622 * smb_acl_sort 1765521Sas200622 * 1775521Sas200622 * Sorts the given ACL in place if it needs to be sorted. 1785331Samw * 1795331Samw * The following is an excerpt from MSDN website. 1805331Samw * 1815331Samw * Order of ACEs in a DACL 1825331Samw * 1835331Samw * For Windows NT versions 4.0 and earlier, the preferred order of ACEs 1845331Samw * is simple: In a DACL, all access-denied ACEs should precede any 1855331Samw * access-allowed ACEs. 1865331Samw * 1875331Samw * For Windows 2000 or later, the proper order of ACEs is more complicated 1885331Samw * because of the introduction of object-specific ACEs and automatic 1895331Samw * inheritance. 1905331Samw * 1915331Samw * The following describes the preferred order: 1925331Samw * 1935331Samw * To ensure that noninherited ACEs have precedence over inherited ACEs, 1945331Samw * place all noninherited ACEs in a group before any inherited ACEs. This 1955331Samw * ordering ensures, for example, that a noninherited access-denied ACE 1965331Samw * is enforced regardless of any inherited ACE that allows access. 1975331Samw * Within the groups of noninherited ACEs and inherited ACEs, order ACEs 1985331Samw * according to ACE type, as the following shows: 1995331Samw * . Access-denied ACEs that apply to the object itself 2005331Samw * . Access-denied ACEs that apply to a subobject of the 2015331Samw * object, such as a property set or property 2025331Samw * . Access-allowed ACEs that apply to the object itself 2035331Samw * . Access-allowed ACEs that apply to a subobject of the object 2045331Samw * 2055521Sas200622 * So, here is the desired ACE order 2065331Samw * 2075331Samw * deny-direct, allow-direct, deny-inherited, allow-inherited 2085331Samw * 2095521Sas200622 * Of course, not all ACE types are required in an ACL. 2105331Samw */ 2115521Sas200622 void 2125331Samw smb_acl_sort(smb_acl_t *acl) 2135331Samw { 2145521Sas200622 list_t ace_grps[SMB_AG_NUM]; 2155521Sas200622 list_t *alist; 2165331Samw smb_ace_t *ace; 2175331Samw uint8_t ace_flags; 2185521Sas200622 int ag, i; 2195331Samw 2205331Samw ASSERT(acl); 2215331Samw 2225331Samw if (acl->sl_acecnt == 0) { 2235331Samw /* 2245331Samw * ACL with no entry is a valid ACL and it means 2255331Samw * no access for anybody. 2265331Samw */ 2275521Sas200622 return; 2285331Samw } 2295331Samw 2305331Samw for (i = SMB_AG_START; i < SMB_AG_NUM; i++) { 2315521Sas200622 list_create(&ace_grps[i], sizeof (smb_ace_t), 2325521Sas200622 offsetof(smb_ace_t, se_sln)); 2335331Samw } 2345331Samw 2355521Sas200622 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) { 2365521Sas200622 ace_flags = ace->se_hdr.se_flags; 2375331Samw 2385521Sas200622 switch (ace->se_hdr.se_type) { 2395331Samw case ACCESS_DENIED_ACE_TYPE: 2405521Sas200622 ag = (ace_flags & INHERITED_ACE) ? 2415521Sas200622 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT; 2425331Samw break; 2435331Samw 2445331Samw case ACCESS_ALLOWED_ACE_TYPE: 2455521Sas200622 ag = (ace_flags & INHERITED_ACE) ? 2465521Sas200622 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT; 2475331Samw break; 2485331Samw 2495331Samw default: 2505331Samw /* 2515331Samw * This is the lowest priority group so we put 2525331Samw * evertything unknown here. 2535331Samw */ 2545331Samw ag = SMB_AG_ALW_INHRT; 2555331Samw break; 2565331Samw } 2575331Samw 2585521Sas200622 /* Add the ACE to the selected group */ 2595521Sas200622 list_insert_tail(&ace_grps[ag], ace); 2605331Samw } 2615331Samw 2625521Sas200622 /* 2635521Sas200622 * start with highest priority ACE group and append 2645521Sas200622 * the ACEs to the ACL. 2655521Sas200622 */ 2665521Sas200622 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) { 2675521Sas200622 alist = &ace_grps[i]; 2685521Sas200622 while ((ace = list_head(alist)) != NULL) { 2695521Sas200622 list_remove(alist, ace); 2705521Sas200622 list_insert_tail(&acl->sl_sorted, ace); 2715521Sas200622 } 2725521Sas200622 list_destroy(alist); 2735331Samw } 2745331Samw } 2755331Samw 2765521Sas200622 /* 2775521Sas200622 * smb_acl_from_zfs 2785521Sas200622 * 2795521Sas200622 * Converts given ZFS ACL to a Windows ACL. 2805521Sas200622 * 2815521Sas200622 * A pointer to allocated memory for the Win ACL will be 2825521Sas200622 * returned upon successful conversion. 2835521Sas200622 */ 2845521Sas200622 smb_acl_t * 285*11447Samw@Sun.COM smb_acl_from_zfs(acl_t *zacl) 2865331Samw { 2875521Sas200622 ace_t *zace; 2885521Sas200622 int numaces; 2895521Sas200622 smb_acl_t *acl; 2905331Samw smb_ace_t *ace; 2915521Sas200622 smb_idmap_batch_t sib; 2925521Sas200622 smb_idmap_t *sim; 2935521Sas200622 idmap_stat idm_stat; 2945331Samw 2955521Sas200622 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt, 2965521Sas200622 SMB_IDMAP_ID2SID); 2975521Sas200622 if (idm_stat != IDMAP_SUCCESS) 2985331Samw return (NULL); 2995331Samw 300*11447Samw@Sun.COM if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) { 3015521Sas200622 smb_idmap_batch_destroy(&sib); 3025521Sas200622 return (NULL); 3035331Samw } 3045331Samw 3055521Sas200622 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt); 3065331Samw 3075521Sas200622 sim = sib.sib_maps; 3085521Sas200622 for (numaces = 0, zace = zacl->acl_aclp; 3095521Sas200622 numaces < zacl->acl_cnt; 3105521Sas200622 zace++, numaces++, sim++) { 3115521Sas200622 ASSERT(sim->sim_sid); 3125521Sas200622 if (sim->sim_sid == NULL) { 3135521Sas200622 smb_acl_free(acl); 3145521Sas200622 acl = NULL; 3155521Sas200622 break; 3165521Sas200622 } 3175331Samw 3185521Sas200622 ace = &acl->sl_aces[numaces]; 3195521Sas200622 ace->se_hdr.se_type = zace->a_type; 3205521Sas200622 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags); 3215521Sas200622 ace->se_mask = zace->a_access_mask; 3226432Sas200622 ace->se_sid = smb_sid_dup(sim->sim_sid); 3235521Sas200622 ace->se_hdr.se_bsize = smb_ace_len(ace); 3245521Sas200622 3255521Sas200622 acl->sl_bsize += ace->se_hdr.se_bsize; 3265331Samw } 3275331Samw 3285521Sas200622 smb_idmap_batch_destroy(&sib); 3295521Sas200622 return (acl); 3305331Samw } 3315331Samw 3325331Samw /* 3335521Sas200622 * smb_acl_to_zfs 3345331Samw * 3355521Sas200622 * Converts given Windows ACL to a ZFS ACL. 3365331Samw * 3375521Sas200622 * fs_acl will contain a pointer to the created ZFS ACL. 3385521Sas200622 * The allocated memory should be freed by calling 3395521Sas200622 * smb_fsacl_free(). 3405331Samw * 3415521Sas200622 * Since the output parameter, fs_acl, is allocated in this 3425521Sas200622 * function, the caller has to make sure *fs_acl is NULL which 3435521Sas200622 * means it's not pointing to any memory. 3445331Samw */ 3455331Samw uint32_t 3465521Sas200622 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl) 3475331Samw { 3485521Sas200622 smb_ace_t *ace; 3495521Sas200622 acl_t *zacl; 3505521Sas200622 ace_t *zace; 3515521Sas200622 smb_idmap_batch_t sib; 3525521Sas200622 smb_idmap_t *sim; 3535521Sas200622 idmap_stat idm_stat; 354*11447Samw@Sun.COM char *sidstr; 3557348SJose.Borrego@Sun.COM int i; 3565331Samw 3575521Sas200622 ASSERT(fs_acl); 3585521Sas200622 ASSERT(*fs_acl == NULL); 3595521Sas200622 3605521Sas200622 if (acl && !smb_acl_isvalid(acl, which_acl)) 3615521Sas200622 return (NT_STATUS_INVALID_ACL); 3625521Sas200622 3635521Sas200622 if ((acl == NULL) || (acl->sl_acecnt == 0)) { 3645521Sas200622 if (which_acl == SMB_DACL_SECINFO) { 3657348SJose.Borrego@Sun.COM *fs_acl = smb_fsacl_null_empty(acl == NULL); 3665521Sas200622 } 3675521Sas200622 3685521Sas200622 return (NT_STATUS_SUCCESS); 3695331Samw } 3705331Samw 3715521Sas200622 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt, 3725521Sas200622 SMB_IDMAP_SID2ID); 3735521Sas200622 if (idm_stat != IDMAP_SUCCESS) 3745521Sas200622 return (NT_STATUS_INTERNAL_ERROR); 3755521Sas200622 376*11447Samw@Sun.COM sidstr = kmem_alloc(SMB_SID_STRSZ, KM_SLEEP); 3775521Sas200622 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags); 3785521Sas200622 3795521Sas200622 zace = zacl->acl_aclp; 3805521Sas200622 ace = acl->sl_aces; 3815521Sas200622 sim = sib.sib_maps; 3825521Sas200622 3835521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 3845521Sas200622 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES; 3855521Sas200622 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask); 3867348SJose.Borrego@Sun.COM zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags); 387*11447Samw@Sun.COM zace->a_who = (uid_t)-1; 3885521Sas200622 389*11447Samw@Sun.COM smb_sid_tostr(ace->se_sid, sidstr); 390*11447Samw@Sun.COM 391*11447Samw@Sun.COM if (!smb_ace_wellknown_update(sidstr, zace)) { 3925521Sas200622 sim->sim_id = &zace->a_who; 3935521Sas200622 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, 394*11447Samw@Sun.COM ace->se_sid, SMB_IDMAP_UNKNOWN); 3955521Sas200622 3965521Sas200622 if (idm_stat != IDMAP_SUCCESS) { 397*11447Samw@Sun.COM kmem_free(sidstr, SMB_SID_STRSZ); 3985521Sas200622 smb_fsacl_free(zacl); 3995521Sas200622 smb_idmap_batch_destroy(&sib); 4005521Sas200622 return (NT_STATUS_INTERNAL_ERROR); 4015521Sas200622 } 4025521Sas200622 } 4035331Samw } 4045331Samw 405*11447Samw@Sun.COM kmem_free(sidstr, SMB_SID_STRSZ); 406*11447Samw@Sun.COM 4075521Sas200622 idm_stat = smb_idmap_batch_getmappings(&sib); 4085521Sas200622 if (idm_stat != IDMAP_SUCCESS) { 4095521Sas200622 smb_fsacl_free(zacl); 4105521Sas200622 smb_idmap_batch_destroy(&sib); 4115521Sas200622 return (NT_STATUS_NONE_MAPPED); 4125331Samw } 4135331Samw 4145521Sas200622 /* 4155521Sas200622 * Set the ACEs group flag based on the type of ID returned. 4165521Sas200622 */ 4175521Sas200622 zace = zacl->acl_aclp; 4185521Sas200622 ace = acl->sl_aces; 4195521Sas200622 sim = sib.sib_maps; 4205521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) { 421*11447Samw@Sun.COM if (zace->a_who == (uid_t)-1) 4225521Sas200622 continue; 4235521Sas200622 4245521Sas200622 if (sim->sim_idtype == SMB_IDMAP_GROUP) 4255521Sas200622 zace->a_flags |= ACE_IDENTIFIER_GROUP; 4265331Samw } 4275331Samw 4285521Sas200622 smb_idmap_batch_destroy(&sib); 4295521Sas200622 4305521Sas200622 *fs_acl = zacl; 4315521Sas200622 return (NT_STATUS_SUCCESS); 4325331Samw } 4335331Samw 434*11447Samw@Sun.COM static boolean_t 435*11447Samw@Sun.COM smb_ace_wellknown_update(const char *sid, ace_t *zace) 436*11447Samw@Sun.COM { 437*11447Samw@Sun.COM struct { 438*11447Samw@Sun.COM char *sid; 439*11447Samw@Sun.COM uint16_t flags; 440*11447Samw@Sun.COM } map[] = { 441*11447Samw@Sun.COM { NT_WORLD_SIDSTR, ACE_EVERYONE }, 442*11447Samw@Sun.COM { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER }, 443*11447Samw@Sun.COM { NT_BUILTIN_CURRENT_GROUP_SIDSTR, 444*11447Samw@Sun.COM (ACE_GROUP | ACE_IDENTIFIER_GROUP) }, 445*11447Samw@Sun.COM }; 446*11447Samw@Sun.COM 447*11447Samw@Sun.COM int i; 448*11447Samw@Sun.COM 449*11447Samw@Sun.COM for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) { 450*11447Samw@Sun.COM if (strcmp(sid, map[i].sid) == 0) { 451*11447Samw@Sun.COM zace->a_flags |= map[i].flags; 452*11447Samw@Sun.COM return (B_TRUE); 453*11447Samw@Sun.COM } 454*11447Samw@Sun.COM } 455*11447Samw@Sun.COM 456*11447Samw@Sun.COM return (B_FALSE); 457*11447Samw@Sun.COM } 458*11447Samw@Sun.COM 4595331Samw /* 4607348SJose.Borrego@Sun.COM * smb_fsacl_getsids 4615331Samw * 4625331Samw * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs. 4635331Samw */ 4645331Samw static idmap_stat 465*11447Samw@Sun.COM smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl) 4665331Samw { 4675331Samw ace_t *zace; 4685331Samw idmap_stat idm_stat; 4695331Samw smb_idmap_t *sim; 4705331Samw uid_t id; 4715331Samw int i, idtype; 4725331Samw 4735331Samw sim = sib->sib_maps; 4745331Samw 4755331Samw for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; 4765331Samw zace++, i++, sim++) { 4775331Samw switch (zace->a_flags & ACE_TYPE_FLAGS) { 4785331Samw case ACE_OWNER: 479*11447Samw@Sun.COM idtype = SMB_IDMAP_OWNERAT; 4805331Samw break; 4815331Samw 4825331Samw case (ACE_GROUP | ACE_IDENTIFIER_GROUP): 4835331Samw /* owning group */ 484*11447Samw@Sun.COM idtype = SMB_IDMAP_GROUPAT; 4855331Samw break; 4865331Samw 4875331Samw case ACE_IDENTIFIER_GROUP: 4885331Samw /* regular group */ 4895331Samw id = zace->a_who; 4905331Samw idtype = SMB_IDMAP_GROUP; 4915331Samw break; 4925331Samw 4935331Samw case ACE_EVERYONE: 4945331Samw idtype = SMB_IDMAP_EVERYONE; 4955331Samw break; 4965331Samw 4975331Samw default: 4985331Samw /* user entry */ 4995331Samw id = zace->a_who; 5005331Samw idtype = SMB_IDMAP_USER; 5015331Samw } 5025331Samw 5035331Samw idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim, 5045331Samw id, idtype); 5055331Samw 5065331Samw if (idm_stat != IDMAP_SUCCESS) { 5075331Samw return (idm_stat); 5085331Samw } 5095331Samw } 5105331Samw 5115331Samw idm_stat = smb_idmap_batch_getmappings(sib); 5125331Samw return (idm_stat); 5135331Samw } 5145331Samw 5155331Samw /* 5167348SJose.Borrego@Sun.COM * smb_fsacl_null_empty 5175331Samw * 5185331Samw * NULL DACL means everyone full-access 5195331Samw * Empty DACL means everyone full-deny 5205331Samw * 5215331Samw * ZFS ACL must have at least one entry so smb server has 5225331Samw * to simulate the aforementioned expected behavior by adding 5235331Samw * an entry in case the requested DACL is null or empty. Adding 5245331Samw * a everyone full-deny entry has proved to be problematic in 5255331Samw * tests since a deny entry takes precedence over allow entries. 5265331Samw * So, instead of adding a everyone full-deny, an owner ACE with 5275331Samw * owner implicit permissions will be set. 5285331Samw */ 5295521Sas200622 static acl_t * 5307348SJose.Borrego@Sun.COM smb_fsacl_null_empty(boolean_t null) 5315331Samw { 5325331Samw acl_t *zacl; 5335331Samw ace_t *zace; 5345331Samw 5355521Sas200622 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT); 5365331Samw zace = zacl->acl_aclp; 5375331Samw 5385331Samw zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 5395331Samw if (null) { 5405331Samw zace->a_access_mask = ACE_ALL_PERMS; 5415331Samw zace->a_flags = ACE_EVERYONE; 5425331Samw } else { 5435331Samw zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL | 5445331Samw ACE_READ_ATTRIBUTES; 5455331Samw zace->a_flags = ACE_OWNER; 5465331Samw } 5475331Samw 5485331Samw return (zacl); 5495331Samw } 5505331Samw 5515331Samw /* 5525521Sas200622 * FS ACL (acl_t) Functions 5535331Samw */ 5545521Sas200622 acl_t * 5555521Sas200622 smb_fsacl_alloc(int acenum, int flags) 5565331Samw { 5575521Sas200622 acl_t *acl; 5585331Samw 5595521Sas200622 acl = acl_alloc(ACE_T); 5605521Sas200622 acl->acl_cnt = acenum; 5615521Sas200622 acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP); 5625521Sas200622 acl->acl_flags = flags; 5635521Sas200622 return (acl); 5645521Sas200622 } 5655331Samw 5665521Sas200622 void 5675521Sas200622 smb_fsacl_free(acl_t *acl) 5685521Sas200622 { 5695521Sas200622 if (acl) 5705521Sas200622 acl_free(acl); 5715521Sas200622 } 5725331Samw 5735521Sas200622 /* 5745521Sas200622 * smb_fsop_aclmerge 5755521Sas200622 * 5765521Sas200622 * smb_fsop_aclread/write routines which interact with filesystem 5775521Sas200622 * work with single ACL. This routine merges given DACL and SACL 5785521Sas200622 * which might have been created during CIFS to FS conversion into 5795521Sas200622 * one single ACL. 5805521Sas200622 */ 5815521Sas200622 acl_t * 5825521Sas200622 smb_fsacl_merge(acl_t *dacl, acl_t *sacl) 5835521Sas200622 { 5845521Sas200622 acl_t *acl; 5855521Sas200622 int dacl_size; 5865331Samw 5875521Sas200622 ASSERT(dacl); 5885521Sas200622 ASSERT(sacl); 5895331Samw 5905521Sas200622 acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags); 5915521Sas200622 dacl_size = dacl->acl_cnt * dacl->acl_entry_size; 5925521Sas200622 bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size); 5935521Sas200622 bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size, 5945521Sas200622 sacl->acl_cnt * sacl->acl_entry_size); 5955331Samw 5965521Sas200622 return (acl); 5975331Samw } 5985331Samw 5995331Samw /* 6005521Sas200622 * smb_fsacl_split 6015331Samw * 6025521Sas200622 * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on 6035521Sas200622 * the 'which_acl' parameter. Note that output dacl/sacl parameters could be 6045521Sas200622 * NULL even if they're specified in 'which_acl', which means the target 6055521Sas200622 * doesn't have any access and/or audit ACEs. 6065331Samw */ 6075521Sas200622 void 6085521Sas200622 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl) 6095331Samw { 6105331Samw ace_t *zace; 6115521Sas200622 ace_t *access_ace; 6125521Sas200622 ace_t *audit_ace; 6135521Sas200622 int naccess, naudit; 6145521Sas200622 int get_dacl, get_sacl; 6155521Sas200622 int i; 6165521Sas200622 6175521Sas200622 *dacl = *sacl = NULL; 6185521Sas200622 naccess = naudit = 0; 6195521Sas200622 get_dacl = (which_acl & SMB_DACL_SECINFO); 6205521Sas200622 get_sacl = (which_acl & SMB_SACL_SECINFO); 6215331Samw 6225521Sas200622 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 6235521Sas200622 if (get_dacl && smb_ace_is_access(zace->a_type)) 6245521Sas200622 naccess++; 6255521Sas200622 else if (get_sacl && smb_ace_is_audit(zace->a_type)) 6265521Sas200622 naudit++; 6275521Sas200622 } 6285331Samw 6295521Sas200622 if (naccess) { 6305521Sas200622 *dacl = smb_fsacl_alloc(naccess, zacl->acl_flags); 6315521Sas200622 access_ace = (*dacl)->acl_aclp; 6325521Sas200622 } 6335331Samw 6345521Sas200622 if (naudit) { 6355521Sas200622 *sacl = smb_fsacl_alloc(naudit, zacl->acl_flags); 6365521Sas200622 audit_ace = (*sacl)->acl_aclp; 6375521Sas200622 } 6385331Samw 6395521Sas200622 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) { 6405521Sas200622 if (get_dacl && smb_ace_is_access(zace->a_type)) { 6415521Sas200622 *access_ace = *zace; 6425521Sas200622 access_ace++; 6435521Sas200622 } else if (get_sacl && smb_ace_is_audit(zace->a_type)) { 6445521Sas200622 *audit_ace = *zace; 6455521Sas200622 audit_ace++; 6465331Samw } 6475331Samw } 6485331Samw } 6495331Samw 6505331Samw /* 6515521Sas200622 * ACE Inheritance Rules 6525521Sas200622 * 6535521Sas200622 * The system propagates inheritable ACEs to child objects according to a 6545521Sas200622 * set of inheritance rules. The system places inherited ACEs in the child's 6555521Sas200622 * DACL according to the preferred order of ACEs in a DACL. For Windows 6565521Sas200622 * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs. 6575521Sas200622 * 6585521Sas200622 * The following table shows the ACEs inherited by container and noncontainer 6595521Sas200622 * child objects for different combinations of inheritance flags. These 6605521Sas200622 * inheritance rules work the same for both DACLs and SACLs. 6615521Sas200622 * 6625521Sas200622 * Parent ACE type Effect on Child ACL 6635521Sas200622 * ----------------------- ------------------- 6645521Sas200622 * OBJECT_INHERIT_ACE only Noncontainer child objects: 6655521Sas200622 * Inherited as an effective ACE. 6665521Sas200622 * Container child objects: 6675521Sas200622 * Containers inherit an inherit-only ACE 6685521Sas200622 * unless the NO_PROPAGATE_INHERIT_ACE bit 6695521Sas200622 * flag is also set. 6705521Sas200622 * 6715521Sas200622 * CONTAINER_INHERIT_ACE only Noncontainer child objects: 6725521Sas200622 * No effect on the child object. 6735521Sas200622 * Container child objects: 6745521Sas200622 * The child object inherits an effective ACE. 6755521Sas200622 * The inherited ACE is inheritable unless the 6765521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set. 6775521Sas200622 * 6785521Sas200622 * CONTAINER_INHERIT_ACE and 6795521Sas200622 * OBJECT_INHERIT_ACE Noncontainer child objects: 6805521Sas200622 * Inherited as an effective ACE. 6815521Sas200622 * Container child objects: 6825521Sas200622 * The child object inherits an effective ACE. 6835521Sas200622 * The inherited ACE is inheritable unless the 6845521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set 6855521Sas200622 * 6865521Sas200622 * No inheritance flags set No effect on child container or noncontainer 6875521Sas200622 * objects. 6885521Sas200622 * 6895521Sas200622 * If an inherited ACE is an effective ACE for the child object, the system 6905521Sas200622 * maps any generic rights to the specific rights for the child object. 6915521Sas200622 * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the 6925521Sas200622 * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic 6935521Sas200622 * rights or generic SIDs are left unchanged so that they can be mapped 6945521Sas200622 * appropriately when the ACE is inherited by the next generation of child 6955521Sas200622 * objects. 6965521Sas200622 * 6975521Sas200622 * For a case in which a container object inherits an ACE that is both 6985521Sas200622 * effective on the container and inheritable by its descendants, the 6995521Sas200622 * container may inherit two ACEs. This occurs if the inheritable ACE 7005521Sas200622 * contains generic information. The container inherits an inherit-only 7015521Sas200622 * ACE containing the generic information and an effective-only ACE in 7025521Sas200622 * which the generic information has been mapped. 7035331Samw */ 7045331Samw 7055331Samw /* 7065521Sas200622 * smb_fsacl_inherit 7075331Samw * 7085331Samw * Manufacture the inherited ACL from the given ACL considering 7095331Samw * the new object type (file/dir) specified by 'is_dir'. The 7105331Samw * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions. 7115521Sas200622 * This function implements Windows inheritance rules explained above. 7125331Samw * 7135521Sas200622 * Note that the in/out ACLs are ZFS ACLs not Windows ACLs 7145331Samw */ 7155331Samw acl_t * 7165521Sas200622 smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid) 7175331Samw { 7185331Samw boolean_t use_default = B_FALSE; 7195331Samw int num_inheritable = 0; 7205331Samw int numaces; 7215331Samw ace_t *dir_zace; 7225331Samw acl_t *new_zacl; 7235331Samw ace_t *new_zace; 7245331Samw 7255521Sas200622 num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir); 7265331Samw 7275331Samw if (num_inheritable == 0) { 7285331Samw if (which_acl == SMB_DACL_SECINFO) { 7295331Samw /* No inheritable access ACEs -> default DACL */ 7305331Samw num_inheritable = DEFAULT_DACL_ACENUM; 7315331Samw use_default = B_TRUE; 7325331Samw } else { 7335331Samw return (NULL); 7345331Samw } 7355331Samw } 7365331Samw 7375521Sas200622 new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT); 7385331Samw new_zace = new_zacl->acl_aclp; 7395331Samw 7405331Samw if (use_default) { 7415331Samw bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl)); 7425331Samw new_zace->a_who = owner_uid; 7435331Samw return (new_zacl); 7445331Samw } 7455331Samw 7465331Samw for (numaces = 0, dir_zace = dir_zacl->acl_aclp; 7475331Samw numaces < dir_zacl->acl_cnt; 7485331Samw dir_zace++, numaces++) { 7495331Samw switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) { 7505331Samw case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE): 7515331Samw /* 7525331Samw * Files inherit an effective ACE. 7535331Samw * 7545331Samw * Dirs inherit an effective ACE. 7555331Samw * The inherited ACE is inheritable unless the 7565331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set 7575331Samw */ 7585331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 7595331Samw new_zace++; 7605331Samw 7615331Samw if (is_dir && ZACE_IS_CREATOR(dir_zace) && 7625331Samw (ZACE_IS_PROPAGATE(dir_zace))) { 7635331Samw *new_zace = *dir_zace; 7645331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 7655331Samw ACE_INHERITED_ACE); 7665331Samw new_zace++; 7675331Samw } 7685331Samw break; 7695331Samw 7705331Samw case ACE_FILE_INHERIT_ACE: 7715331Samw /* 7725331Samw * Files inherit as an effective ACE. 7735331Samw * 7745331Samw * Dirs inherit an inherit-only ACE 7755331Samw * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit 7765331Samw * flag is also set. 7775331Samw */ 7785331Samw if (is_dir == 0) { 7795331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 7805331Samw new_zace++; 7815331Samw } else if (ZACE_IS_PROPAGATE(dir_zace)) { 7825331Samw *new_zace = *dir_zace; 7835331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 7845331Samw ACE_INHERITED_ACE); 7855331Samw new_zace++; 7865331Samw } 7875331Samw break; 7885331Samw 7895331Samw case ACE_DIRECTORY_INHERIT_ACE: 7905331Samw /* 7915331Samw * No effect on files 7925331Samw * 7935331Samw * Dirs inherit an effective ACE. 7945331Samw * The inherited ACE is inheritable unless the 7955331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set. 7965331Samw */ 7975331Samw if (is_dir == 0) 7985331Samw break; 7995331Samw 8005331Samw smb_ace_inherit(dir_zace, new_zace, is_dir); 8015331Samw new_zace++; 8025331Samw 8035331Samw if (ZACE_IS_CREATOR(dir_zace) && 8045331Samw (ZACE_IS_PROPAGATE(dir_zace))) { 8055331Samw *new_zace = *dir_zace; 8065331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE | 8075331Samw ACE_INHERITED_ACE); 8085331Samw new_zace++; 8095331Samw } 8105331Samw 8115331Samw break; 8125331Samw 8135331Samw default: 8145331Samw break; 8155331Samw } 8165331Samw } 8175331Samw 8185331Samw return (new_zacl); 8195331Samw } 8205331Samw 8215521Sas200622 /* 8225521Sas200622 * smb_fsacl_from_vsa 8235521Sas200622 * 8245521Sas200622 * Converts given vsecattr_t structure to a acl_t structure. 8255521Sas200622 * 8265521Sas200622 * The allocated memory for retuned acl_t should be freed by 8275521Sas200622 * calling acl_free(). 8285521Sas200622 */ 8295521Sas200622 acl_t * 8305521Sas200622 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type) 8315521Sas200622 { 8325521Sas200622 int aclbsize = 0; /* size of acl list in bytes */ 8335521Sas200622 int dfaclbsize = 0; /* size of default acl list in bytes */ 8345521Sas200622 int numacls; 8355521Sas200622 acl_t *acl_info; 8365521Sas200622 8375521Sas200622 ASSERT(vsecattr); 8385521Sas200622 8395521Sas200622 acl_info = acl_alloc(acl_type); 8405521Sas200622 if (acl_info == NULL) 8415521Sas200622 return (NULL); 8425521Sas200622 8435521Sas200622 acl_info->acl_flags = 0; 8445521Sas200622 8455521Sas200622 switch (acl_type) { 8465521Sas200622 8475521Sas200622 case ACLENT_T: 8485521Sas200622 numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt; 8495521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t); 8505521Sas200622 dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t); 8515521Sas200622 8525521Sas200622 acl_info->acl_cnt = numacls; 8535521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize, 8545521Sas200622 KM_SLEEP); 8555521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 8565521Sas200622 aclbsize); 8575521Sas200622 (void) memcpy((char *)acl_info->acl_aclp + aclbsize, 8585521Sas200622 vsecattr->vsa_dfaclentp, dfaclbsize); 8595521Sas200622 8605521Sas200622 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 8615521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL; 8625521Sas200622 8635521Sas200622 break; 8645521Sas200622 8655521Sas200622 case ACE_T: 8665521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 8675521Sas200622 acl_info->acl_cnt = vsecattr->vsa_aclcnt; 8685521Sas200622 acl_info->acl_flags = vsecattr->vsa_aclflags; 8695521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP); 8705521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 8715521Sas200622 aclbsize); 8725521Sas200622 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 8735521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL; 8745521Sas200622 8755521Sas200622 break; 8765521Sas200622 8775521Sas200622 default: 8785521Sas200622 acl_free(acl_info); 8795521Sas200622 return (NULL); 8805521Sas200622 } 8815521Sas200622 8825521Sas200622 if (aclbsize && vsecattr->vsa_aclentp) 8835521Sas200622 kmem_free(vsecattr->vsa_aclentp, aclbsize); 8845521Sas200622 if (dfaclbsize && vsecattr->vsa_dfaclentp) 8855521Sas200622 kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize); 8865521Sas200622 8875521Sas200622 return (acl_info); 8885521Sas200622 } 8895521Sas200622 8905521Sas200622 /* 8915521Sas200622 * smb_fsacl_to_vsa 8925521Sas200622 * 8935521Sas200622 * Converts given acl_t structure to a vsecattr_t structure. 8945521Sas200622 * 8955521Sas200622 * IMPORTANT: 8965521Sas200622 * Upon successful return the memory allocated for vsa_aclentp 8975521Sas200622 * should be freed by calling kmem_free(). The size is returned 8985521Sas200622 * in aclbsize. 8995521Sas200622 */ 9005521Sas200622 int 9015521Sas200622 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize) 9025521Sas200622 { 9035521Sas200622 int error = 0; 9045521Sas200622 int numacls; 9055521Sas200622 aclent_t *aclp; 9065521Sas200622 9075521Sas200622 ASSERT(acl_info); 9085521Sas200622 ASSERT(vsecattr); 9095521Sas200622 ASSERT(aclbsize); 9105521Sas200622 9115521Sas200622 bzero(vsecattr, sizeof (vsecattr_t)); 9125521Sas200622 *aclbsize = 0; 9135521Sas200622 9145521Sas200622 switch (acl_info->acl_type) { 9155521Sas200622 case ACLENT_T: 9165521Sas200622 numacls = acl_info->acl_cnt; 9175521Sas200622 /* 9185521Sas200622 * Minimum ACL size is three entries so might as well 9195521Sas200622 * bail out here. Also limit request size to prevent user 9205521Sas200622 * from allocating too much kernel memory. Maximum size 9215521Sas200622 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 9225521Sas200622 * for the default ACL part. 9235521Sas200622 */ 9245521Sas200622 if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) { 9255521Sas200622 error = EINVAL; 9265521Sas200622 break; 9275521Sas200622 } 9285521Sas200622 9295521Sas200622 vsecattr->vsa_mask = VSA_ACL; 9305521Sas200622 9315521Sas200622 vsecattr->vsa_aclcnt = numacls; 9325521Sas200622 *aclbsize = numacls * sizeof (aclent_t); 9335521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 9345521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 9355521Sas200622 *aclbsize); 9365521Sas200622 9375521Sas200622 /* Sort the acl list */ 9385521Sas200622 ksort((caddr_t)vsecattr->vsa_aclentp, 9395521Sas200622 vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls); 9405521Sas200622 9415521Sas200622 /* Break into acl and default acl lists */ 9425521Sas200622 for (numacls = 0, aclp = vsecattr->vsa_aclentp; 9435521Sas200622 numacls < vsecattr->vsa_aclcnt; 9445521Sas200622 aclp++, numacls++) { 9455521Sas200622 if (aclp->a_type & ACL_DEFAULT) 9465521Sas200622 break; 9475521Sas200622 } 9485521Sas200622 9495521Sas200622 /* Find where defaults start (if any) */ 9505521Sas200622 if (numacls < vsecattr->vsa_aclcnt) { 9515521Sas200622 vsecattr->vsa_mask |= VSA_DFACL; 9525521Sas200622 vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls; 9535521Sas200622 vsecattr->vsa_dfaclentp = aclp; 9545521Sas200622 vsecattr->vsa_aclcnt = numacls; 9555521Sas200622 } 9565521Sas200622 9575521Sas200622 /* Adjust if they're all defaults */ 9585521Sas200622 if (vsecattr->vsa_aclcnt == 0) { 9595521Sas200622 vsecattr->vsa_mask &= ~VSA_ACL; 9605521Sas200622 vsecattr->vsa_aclentp = NULL; 9615521Sas200622 } 9625521Sas200622 9635521Sas200622 /* Only directories can have defaults */ 9645521Sas200622 if (vsecattr->vsa_dfaclcnt && 9655521Sas200622 (acl_info->acl_flags & ACL_IS_DIR)) { 9665521Sas200622 error = ENOTDIR; 9675521Sas200622 } 9685521Sas200622 9695521Sas200622 break; 9705521Sas200622 9715521Sas200622 case ACE_T: 9725521Sas200622 if (acl_info->acl_cnt < 1 || 9735521Sas200622 acl_info->acl_cnt > MAX_ACL_ENTRIES) { 9745521Sas200622 error = EINVAL; 9755521Sas200622 break; 9765521Sas200622 } 9775521Sas200622 9785521Sas200622 vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; 9795521Sas200622 vsecattr->vsa_aclcnt = acl_info->acl_cnt; 9805521Sas200622 vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL; 9815521Sas200622 *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 9825521Sas200622 vsecattr->vsa_aclentsz = *aclbsize; 9835521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 9845521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 9855521Sas200622 *aclbsize); 9865521Sas200622 9875521Sas200622 break; 9885521Sas200622 9895521Sas200622 default: 9905521Sas200622 error = EINVAL; 9915521Sas200622 } 9925521Sas200622 9935521Sas200622 return (error); 9945521Sas200622 } 9955521Sas200622 9965521Sas200622 /* 9975521Sas200622 * smb_fsacl_inheritable 9985521Sas200622 * 9995521Sas200622 * Checks to see if there are any inheritable ACEs in the 10005521Sas200622 * given ZFS ACL. Returns the number of inheritable ACEs. 10015521Sas200622 * 10025521Sas200622 * The inherited ACL could be different based on the type of 10035521Sas200622 * new object (file/dir) specified by 'is_dir'. 10045521Sas200622 * 10055521Sas200622 * Note that the input ACL is a ZFS ACL not Windows ACL. 10065521Sas200622 */ 10075521Sas200622 static int 10085521Sas200622 smb_fsacl_inheritable(acl_t *zacl, int is_dir) 10095521Sas200622 { 10105521Sas200622 int numaces; 10115521Sas200622 int num_inheritable = 0; 10125521Sas200622 ace_t *zace; 10135521Sas200622 10145521Sas200622 if (zacl == NULL) 10155521Sas200622 return (0); 10165521Sas200622 10175521Sas200622 for (numaces = 0, zace = zacl->acl_aclp; 10185521Sas200622 numaces < zacl->acl_cnt; 10195521Sas200622 zace++, numaces++) { 10205521Sas200622 switch (zace->a_flags & ACE_FD_INHERIT_ACE) { 10215521Sas200622 case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE): 10225521Sas200622 /* 10235521Sas200622 * Files inherit an effective ACE. 10245521Sas200622 * 10255521Sas200622 * Dirs inherit an effective ACE. 10265521Sas200622 * The inherited ACE is inheritable unless the 10275521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set 10285521Sas200622 */ 10295521Sas200622 num_inheritable++; 10305521Sas200622 10315521Sas200622 if (is_dir && ZACE_IS_CREATOR(zace) && 10325521Sas200622 (ZACE_IS_PROPAGATE(zace))) { 10335521Sas200622 num_inheritable++; 10345521Sas200622 } 10355521Sas200622 break; 10365521Sas200622 10375521Sas200622 case ACE_FILE_INHERIT_ACE: 10385521Sas200622 /* 10395521Sas200622 * Files inherit as an effective ACE. 10405521Sas200622 * 10415521Sas200622 * Dirs inherit an inherit-only ACE 10425521Sas200622 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit 10435521Sas200622 * flag is also set. 10445521Sas200622 */ 10455521Sas200622 if (is_dir == 0) 10465521Sas200622 num_inheritable++; 10475521Sas200622 else if (ZACE_IS_PROPAGATE(zace)) 10485521Sas200622 num_inheritable++; 10495521Sas200622 break; 10505521Sas200622 10515521Sas200622 case ACE_DIRECTORY_INHERIT_ACE: 10525521Sas200622 /* 10535521Sas200622 * No effect on files 10545521Sas200622 * 10555521Sas200622 * Dirs inherit an effective ACE. 10565521Sas200622 * The inherited ACE is inheritable unless the 10575521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set. 10585521Sas200622 */ 10595521Sas200622 if (is_dir == 0) 10605521Sas200622 break; 10615521Sas200622 10625521Sas200622 num_inheritable++; 10635521Sas200622 10645521Sas200622 if (ZACE_IS_CREATOR(zace) && 10655521Sas200622 (ZACE_IS_PROPAGATE(zace))) 10665521Sas200622 num_inheritable++; 10675521Sas200622 break; 10685521Sas200622 10695521Sas200622 default: 10705521Sas200622 break; 10715521Sas200622 } 10725521Sas200622 } 10735521Sas200622 10745521Sas200622 return (num_inheritable); 10755521Sas200622 } 10765521Sas200622 10775521Sas200622 10785521Sas200622 /* 10795521Sas200622 * ACE Functions 10805521Sas200622 */ 10815521Sas200622 10825521Sas200622 /* 10835521Sas200622 * This is generic (ACL version 2) vs. object-specific 10845521Sas200622 * (ACL version 4) ACE types. 10855521Sas200622 */ 10865521Sas200622 boolean_t 10875521Sas200622 smb_ace_is_generic(int type) 10885521Sas200622 { 10895521Sas200622 switch (type) { 10905521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE: 10915521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE: 10925521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE: 10935521Sas200622 case ACE_SYSTEM_ALARM_ACE_TYPE: 10945521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE: 10955521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE: 10965521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE: 10975521Sas200622 case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE: 10985521Sas200622 return (B_TRUE); 10995521Sas200622 11005521Sas200622 default: 11015521Sas200622 break; 11025521Sas200622 } 11035521Sas200622 11045521Sas200622 return (B_FALSE); 11055521Sas200622 } 11065521Sas200622 11075521Sas200622 boolean_t 11085521Sas200622 smb_ace_is_access(int type) 11095521Sas200622 { 11105521Sas200622 switch (type) { 11115521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE: 11125521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE: 11135521Sas200622 case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE: 11145521Sas200622 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 11155521Sas200622 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 11165521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE: 11175521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE: 11185521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: 11195521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE: 11205521Sas200622 return (B_TRUE); 11215521Sas200622 11225521Sas200622 default: 11235521Sas200622 break; 11245521Sas200622 } 11255521Sas200622 11265521Sas200622 return (B_FALSE); 11275521Sas200622 } 11285521Sas200622 11295521Sas200622 boolean_t 11305521Sas200622 smb_ace_is_audit(int type) 11315521Sas200622 { 11325521Sas200622 switch (type) { 11335521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE: 11345521Sas200622 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 11355521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE: 11365521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE: 11375521Sas200622 return (B_TRUE); 11385521Sas200622 11395521Sas200622 default: 11405521Sas200622 break; 11415521Sas200622 } 11425521Sas200622 11435521Sas200622 return (B_FALSE); 11445521Sas200622 } 11455521Sas200622 11465521Sas200622 /* 11475521Sas200622 * smb_ace_len 11485521Sas200622 * 11495521Sas200622 * Returns the length of the given ACE as it appears in an 11505521Sas200622 * ACL on the wire (i.e. a flat buffer which contains the SID) 11515521Sas200622 */ 11525521Sas200622 static uint16_t 11535521Sas200622 smb_ace_len(smb_ace_t *ace) 11545521Sas200622 { 11555521Sas200622 ASSERT(ace); 11565521Sas200622 ASSERT(ace->se_sid); 11575521Sas200622 11585521Sas200622 if (ace == NULL) 11595521Sas200622 return (0); 11605521Sas200622 11615521Sas200622 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) + 11626432Sas200622 smb_sid_len(ace->se_sid)); 11635521Sas200622 } 11645521Sas200622 11655331Samw static void 11665331Samw smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir) 11675331Samw { 11685331Samw *zace = *dir_zace; 11697348SJose.Borrego@Sun.COM 11707348SJose.Borrego@Sun.COM /* This is an effective ACE so remove the inherit_only flag */ 11717348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_ONLY_ACE; 11727348SJose.Borrego@Sun.COM /* Mark this ACE as inherited */ 11735331Samw zace->a_flags |= ACE_INHERITED_ACE; 11745331Samw 11755331Samw /* 11767348SJose.Borrego@Sun.COM * If this is a file or NO_PROPAGATE is set then this inherited 11777348SJose.Borrego@Sun.COM * ACE is not inheritable so clear the inheritance flags 11787348SJose.Borrego@Sun.COM */ 11797348SJose.Borrego@Sun.COM if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace))) 11807348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 11817348SJose.Borrego@Sun.COM 11827348SJose.Borrego@Sun.COM /* 11837348SJose.Borrego@Sun.COM * Replace creator owner/group ACEs with actual owner/group ACEs. 11847348SJose.Borrego@Sun.COM * This would be an effictive ACE which is not inheritable. 11855331Samw */ 11865331Samw if (ZACE_IS_CREATOR_OWNER(dir_zace)) { 11875331Samw zace->a_who = (uid_t)-1; 11885331Samw zace->a_flags |= ACE_OWNER; 11897348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 11905331Samw } else if (ZACE_IS_CREATOR_GROUP(dir_zace)) { 11915331Samw zace->a_who = (uid_t)-1; 11925331Samw zace->a_flags |= ACE_GROUP; 11937348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS; 11945331Samw } 11955331Samw } 11965331Samw 11975521Sas200622 /* 11985521Sas200622 * smb_ace_mask_g2s 11995521Sas200622 * 12005521Sas200622 * Converts generic access bits in the given mask (if any) 12015521Sas200622 * to file specific bits. Generic access masks shouldn't be 12025521Sas200622 * stored in filesystem ACEs. 12035521Sas200622 */ 12045521Sas200622 static uint32_t 12055521Sas200622 smb_ace_mask_g2s(uint32_t mask) 12065521Sas200622 { 12075521Sas200622 if (mask & GENERIC_ALL) { 12085521Sas200622 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE 12095521Sas200622 | GENERIC_EXECUTE); 12105521Sas200622 12115521Sas200622 mask |= FILE_ALL_ACCESS; 12125521Sas200622 return (mask); 12135521Sas200622 } 12145521Sas200622 12155521Sas200622 if (mask & GENERIC_READ) { 12165521Sas200622 mask &= ~GENERIC_READ; 12175521Sas200622 mask |= FILE_GENERIC_READ; 12185521Sas200622 } 12195521Sas200622 12205521Sas200622 if (mask & GENERIC_WRITE) { 12215521Sas200622 mask &= ~GENERIC_WRITE; 12225521Sas200622 mask |= FILE_GENERIC_WRITE; 12235521Sas200622 } 12245521Sas200622 12255521Sas200622 if (mask & GENERIC_EXECUTE) { 12265521Sas200622 mask &= ~GENERIC_EXECUTE; 12275521Sas200622 mask |= FILE_GENERIC_EXECUTE; 12285521Sas200622 } 12295521Sas200622 12305521Sas200622 return (mask); 12315521Sas200622 } 12325521Sas200622 12337348SJose.Borrego@Sun.COM /* 12347348SJose.Borrego@Sun.COM * smb_ace_flags_tozfs 12357348SJose.Borrego@Sun.COM * 12367348SJose.Borrego@Sun.COM * This function maps the flags which have different values 12377348SJose.Borrego@Sun.COM * in Windows and Solaris. The ones with the same value are 12387348SJose.Borrego@Sun.COM * transferred untouched. 12397348SJose.Borrego@Sun.COM */ 12405331Samw static uint16_t 12417348SJose.Borrego@Sun.COM smb_ace_flags_tozfs(uint8_t c_flags) 12425331Samw { 12435331Samw uint16_t z_flags = 0; 12445331Samw 12455331Samw if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG) 12465331Samw z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; 12475331Samw 12485331Samw if (c_flags & FAILED_ACCESS_ACE_FLAG) 12495331Samw z_flags |= ACE_FAILED_ACCESS_ACE_FLAG; 12505331Samw 12515331Samw if (c_flags & INHERITED_ACE) 12525331Samw z_flags |= ACE_INHERITED_ACE; 12535331Samw 12547348SJose.Borrego@Sun.COM z_flags |= (c_flags & ACE_INHERIT_FLAGS); 12555331Samw 12565331Samw return (z_flags); 12575331Samw } 12585331Samw 12595331Samw static uint8_t 12605331Samw smb_ace_flags_fromzfs(uint16_t z_flags) 12615331Samw { 12625331Samw uint8_t c_flags; 12635331Samw 12645331Samw c_flags = z_flags & ACE_INHERIT_FLAGS; 12655331Samw 12665331Samw if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 12675331Samw c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 12685331Samw 12695331Samw if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG) 12705331Samw c_flags |= FAILED_ACCESS_ACE_FLAG; 12715331Samw 12725331Samw if (z_flags & ACE_INHERITED_ACE) 12735331Samw c_flags |= INHERITED_ACE; 12745331Samw 12755331Samw return (c_flags); 12765331Samw } 12775331Samw 12785521Sas200622 static boolean_t 12795521Sas200622 smb_ace_isvalid(smb_ace_t *ace, int which_acl) 12805331Samw { 12815521Sas200622 uint16_t min_len; 12825521Sas200622 12835521Sas200622 min_len = sizeof (smb_acehdr_t); 12845521Sas200622 12855521Sas200622 if (ace->se_hdr.se_bsize < min_len) 12865521Sas200622 return (B_FALSE); 12875521Sas200622 12885521Sas200622 if (smb_ace_is_access(ace->se_hdr.se_type) && 12895521Sas200622 (which_acl != SMB_DACL_SECINFO)) 12905521Sas200622 return (B_FALSE); 12915331Samw 12925521Sas200622 if (smb_ace_is_audit(ace->se_hdr.se_type) && 12935521Sas200622 (which_acl != SMB_SACL_SECINFO)) 12945521Sas200622 return (B_FALSE); 12955521Sas200622 12965521Sas200622 if (smb_ace_is_generic(ace->se_hdr.se_type)) { 12976432Sas200622 if (!smb_sid_isvalid(ace->se_sid)) 12985521Sas200622 return (B_FALSE); 12995521Sas200622 13005521Sas200622 min_len += sizeof (ace->se_mask); 13016432Sas200622 min_len += smb_sid_len(ace->se_sid); 13025521Sas200622 13035521Sas200622 if (ace->se_hdr.se_bsize < min_len) 13045521Sas200622 return (B_FALSE); 13055331Samw } 13065331Samw 13075521Sas200622 /* 13085521Sas200622 * object-specific ACE validation will be added later. 13095521Sas200622 */ 13105521Sas200622 return (B_TRUE); 13115331Samw } 1312