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 /*
2211447Samw@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
235331Samw * Use is subject to license terms.
245331Samw */
255331Samw
26*11963SAfshin.Ardakani@Sun.COM #include <sys/sid.h>
275331Samw #include <sys/acl.h>
285521Sas200622 #include <acl/acl_common.h>
296432Sas200622 #include <smbsrv/smb_sid.h>
305331Samw #include <smbsrv/smb_fsops.h>
315331Samw #include <smbsrv/smb_idmap.h>
325521Sas200622 #include <smbsrv/smb_kproto.h>
335331Samw
345331Samw #define ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
355331Samw
365331Samw #define ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
375331Samw #define ZACE_IS_OWNGRP(zace) \
385331Samw ((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
395331Samw
405331Samw #define ZACE_IS_USER(zace) \
415331Samw (((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
425331Samw #define ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
435331Samw #define ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
445331Samw
455331Samw #define ZACE_IS_PROPAGATE(zace) \
465331Samw ((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
475331Samw
485331Samw #define ZACE_IS_CREATOR_OWNER(zace) \
495331Samw (ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
505331Samw
515331Samw #define ZACE_IS_CREATOR_GROUP(zace) \
525331Samw (ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
535331Samw
545331Samw #define ZACE_IS_CREATOR(zace) \
555331Samw (ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
565331Samw
575331Samw /*
585331Samw * ACE groups within a DACL
595331Samw *
605331Samw * This is from lower to higher ACE order priority
615331Samw */
625331Samw #define SMB_AG_START 0
635331Samw #define SMB_AG_ALW_INHRT 0
645331Samw #define SMB_AG_DNY_INHRT 1
655331Samw #define SMB_AG_ALW_DRCT 2
665331Samw #define SMB_AG_DNY_DRCT 3
675331Samw #define SMB_AG_NUM 4
685331Samw
695521Sas200622 #define DEFAULT_DACL_ACENUM 2
705521Sas200622 /*
715521Sas200622 * Default ACL:
725521Sas200622 * owner: full access
735521Sas200622 * SYSTEM: full access
745521Sas200622 */
755521Sas200622 static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
765521Sas200622 { (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
775521Sas200622 { IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
785521Sas200622 ACE_ACCESS_ALLOWED_ACE_TYPE }
795521Sas200622 };
805521Sas200622
815521Sas200622 /*
825521Sas200622 * Note:
835331Samw *
845521Sas200622 * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
855521Sas200622 * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
865521Sas200622 * format
875521Sas200622 */
885521Sas200622
8911447Samw@Sun.COM static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
907348SJose.Borrego@Sun.COM static acl_t *smb_fsacl_null_empty(boolean_t);
915521Sas200622 static int smb_fsacl_inheritable(acl_t *, int);
925521Sas200622
93*11963SAfshin.Ardakani@Sun.COM static void smb_ace_inherit(ace_t *, ace_t *, int, uid_t, gid_t);
945521Sas200622 static boolean_t smb_ace_isvalid(smb_ace_t *, int);
955521Sas200622 static uint16_t smb_ace_len(smb_ace_t *);
965521Sas200622 static uint32_t smb_ace_mask_g2s(uint32_t);
977348SJose.Borrego@Sun.COM static uint16_t smb_ace_flags_tozfs(uint8_t);
985521Sas200622 static uint8_t smb_ace_flags_fromzfs(uint16_t);
9911447Samw@Sun.COM static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
1005521Sas200622
1015521Sas200622 smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)1025521Sas200622 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
1035521Sas200622 {
1045521Sas200622 smb_acl_t *acl;
1055521Sas200622 int size;
1065521Sas200622
1075521Sas200622 size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
1085521Sas200622 acl = kmem_zalloc(size, KM_SLEEP);
1095521Sas200622 acl->sl_revision = revision;
1105521Sas200622 acl->sl_bsize = bsize;
1115521Sas200622 acl->sl_acecnt = acecnt;
1125521Sas200622 acl->sl_aces = (smb_ace_t *)(acl + 1);
1135521Sas200622
1145521Sas200622 list_create(&acl->sl_sorted, sizeof (smb_ace_t),
1155521Sas200622 offsetof(smb_ace_t, se_sln));
1165521Sas200622 return (acl);
1175521Sas200622 }
1185521Sas200622
1195521Sas200622 void
smb_acl_free(smb_acl_t * acl)1205521Sas200622 smb_acl_free(smb_acl_t *acl)
1215521Sas200622 {
1225521Sas200622 int i, size;
1235521Sas200622 void *ace;
1245521Sas200622
1255521Sas200622 if (acl == NULL)
1265521Sas200622 return;
1275521Sas200622
1286432Sas200622 for (i = 0; i < acl->sl_acecnt; i++)
1296432Sas200622 smb_sid_free(acl->sl_aces[i].se_sid);
1305521Sas200622
1315521Sas200622 while ((ace = list_head(&acl->sl_sorted)) != NULL)
1325521Sas200622 list_remove(&acl->sl_sorted, ace);
1335521Sas200622 list_destroy(&acl->sl_sorted);
1345521Sas200622
1355521Sas200622 size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
1365521Sas200622 kmem_free(acl, size);
1375521Sas200622 }
1385521Sas200622
1395521Sas200622 /*
1405521Sas200622 * smb_acl_len
1415521Sas200622 *
1425521Sas200622 * Returns the size of given ACL in bytes. Note that this
1435521Sas200622 * is not an in-memory size, it's the ACL's size as it would
1445521Sas200622 * appear on the wire
1455521Sas200622 */
1465521Sas200622 uint16_t
smb_acl_len(smb_acl_t * acl)1475521Sas200622 smb_acl_len(smb_acl_t *acl)
1485521Sas200622 {
1497348SJose.Borrego@Sun.COM return ((acl) ? acl->sl_bsize : 0);
1505521Sas200622 }
1515521Sas200622
1525521Sas200622 boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)1535521Sas200622 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
1545521Sas200622 {
1555521Sas200622 int i;
1565521Sas200622
1575521Sas200622 if (acl->sl_bsize < SMB_ACL_HDRSIZE)
1585521Sas200622 return (B_FALSE);
1595521Sas200622
1605521Sas200622 if (acl->sl_revision != ACL_REVISION) {
1615521Sas200622 /*
1625521Sas200622 * we are rejecting ACLs with object-specific ACEs for now
1635521Sas200622 */
1645521Sas200622 return (B_FALSE);
1655521Sas200622 }
1665521Sas200622
1675521Sas200622 for (i = 0; i < acl->sl_acecnt; i++) {
1685521Sas200622 if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
1695521Sas200622 return (B_FALSE);
1705521Sas200622 }
1715521Sas200622
1725521Sas200622 return (B_TRUE);
1735521Sas200622 }
1745521Sas200622
1755521Sas200622 /*
1765521Sas200622 * smb_acl_sort
1775521Sas200622 *
1785521Sas200622 * Sorts the given ACL in place if it needs to be sorted.
1795331Samw *
1805331Samw * The following is an excerpt from MSDN website.
1815331Samw *
1825331Samw * Order of ACEs in a DACL
1835331Samw *
1845331Samw * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
1855331Samw * is simple: In a DACL, all access-denied ACEs should precede any
1865331Samw * access-allowed ACEs.
1875331Samw *
1885331Samw * For Windows 2000 or later, the proper order of ACEs is more complicated
1895331Samw * because of the introduction of object-specific ACEs and automatic
1905331Samw * inheritance.
1915331Samw *
1925331Samw * The following describes the preferred order:
1935331Samw *
1945331Samw * To ensure that noninherited ACEs have precedence over inherited ACEs,
1955331Samw * place all noninherited ACEs in a group before any inherited ACEs. This
1965331Samw * ordering ensures, for example, that a noninherited access-denied ACE
1975331Samw * is enforced regardless of any inherited ACE that allows access.
1985331Samw * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
1995331Samw * according to ACE type, as the following shows:
2005331Samw * . Access-denied ACEs that apply to the object itself
2015331Samw * . Access-denied ACEs that apply to a subobject of the
2025331Samw * object, such as a property set or property
2035331Samw * . Access-allowed ACEs that apply to the object itself
2045331Samw * . Access-allowed ACEs that apply to a subobject of the object
2055331Samw *
2065521Sas200622 * So, here is the desired ACE order
2075331Samw *
2085331Samw * deny-direct, allow-direct, deny-inherited, allow-inherited
2095331Samw *
2105521Sas200622 * Of course, not all ACE types are required in an ACL.
2115331Samw */
2125521Sas200622 void
smb_acl_sort(smb_acl_t * acl)2135331Samw smb_acl_sort(smb_acl_t *acl)
2145331Samw {
2155521Sas200622 list_t ace_grps[SMB_AG_NUM];
2165521Sas200622 list_t *alist;
2175331Samw smb_ace_t *ace;
2185331Samw uint8_t ace_flags;
2195521Sas200622 int ag, i;
2205331Samw
2215331Samw ASSERT(acl);
2225331Samw
2235331Samw if (acl->sl_acecnt == 0) {
2245331Samw /*
2255331Samw * ACL with no entry is a valid ACL and it means
2265331Samw * no access for anybody.
2275331Samw */
2285521Sas200622 return;
2295331Samw }
2305331Samw
2315331Samw for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
2325521Sas200622 list_create(&ace_grps[i], sizeof (smb_ace_t),
2335521Sas200622 offsetof(smb_ace_t, se_sln));
2345331Samw }
2355331Samw
2365521Sas200622 for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
2375521Sas200622 ace_flags = ace->se_hdr.se_flags;
2385331Samw
2395521Sas200622 switch (ace->se_hdr.se_type) {
2405331Samw case ACCESS_DENIED_ACE_TYPE:
2415521Sas200622 ag = (ace_flags & INHERITED_ACE) ?
2425521Sas200622 SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
2435331Samw break;
2445331Samw
2455331Samw case ACCESS_ALLOWED_ACE_TYPE:
2465521Sas200622 ag = (ace_flags & INHERITED_ACE) ?
2475521Sas200622 SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
2485331Samw break;
2495331Samw
2505331Samw default:
2515331Samw /*
2525331Samw * This is the lowest priority group so we put
2535331Samw * evertything unknown here.
2545331Samw */
2555331Samw ag = SMB_AG_ALW_INHRT;
2565331Samw break;
2575331Samw }
2585331Samw
2595521Sas200622 /* Add the ACE to the selected group */
2605521Sas200622 list_insert_tail(&ace_grps[ag], ace);
2615331Samw }
2625331Samw
2635521Sas200622 /*
2645521Sas200622 * start with highest priority ACE group and append
2655521Sas200622 * the ACEs to the ACL.
2665521Sas200622 */
2675521Sas200622 for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
2685521Sas200622 alist = &ace_grps[i];
2695521Sas200622 while ((ace = list_head(alist)) != NULL) {
2705521Sas200622 list_remove(alist, ace);
2715521Sas200622 list_insert_tail(&acl->sl_sorted, ace);
2725521Sas200622 }
2735521Sas200622 list_destroy(alist);
2745331Samw }
2755331Samw }
2765331Samw
2775521Sas200622 /*
2785521Sas200622 * smb_acl_from_zfs
2795521Sas200622 *
2805521Sas200622 * Converts given ZFS ACL to a Windows ACL.
2815521Sas200622 *
2825521Sas200622 * A pointer to allocated memory for the Win ACL will be
2835521Sas200622 * returned upon successful conversion.
2845521Sas200622 */
2855521Sas200622 smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)28611447Samw@Sun.COM smb_acl_from_zfs(acl_t *zacl)
2875331Samw {
2885521Sas200622 ace_t *zace;
2895521Sas200622 int numaces;
2905521Sas200622 smb_acl_t *acl;
2915331Samw smb_ace_t *ace;
2925521Sas200622 smb_idmap_batch_t sib;
2935521Sas200622 smb_idmap_t *sim;
2945521Sas200622 idmap_stat idm_stat;
2955331Samw
2965521Sas200622 idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
2975521Sas200622 SMB_IDMAP_ID2SID);
2985521Sas200622 if (idm_stat != IDMAP_SUCCESS)
2995331Samw return (NULL);
3005331Samw
30111447Samw@Sun.COM if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
3025521Sas200622 smb_idmap_batch_destroy(&sib);
3035521Sas200622 return (NULL);
3045331Samw }
3055331Samw
3065521Sas200622 acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
3075331Samw
3085521Sas200622 sim = sib.sib_maps;
3095521Sas200622 for (numaces = 0, zace = zacl->acl_aclp;
3105521Sas200622 numaces < zacl->acl_cnt;
3115521Sas200622 zace++, numaces++, sim++) {
3125521Sas200622 ASSERT(sim->sim_sid);
3135521Sas200622 if (sim->sim_sid == NULL) {
3145521Sas200622 smb_acl_free(acl);
3155521Sas200622 acl = NULL;
3165521Sas200622 break;
3175521Sas200622 }
3185331Samw
3195521Sas200622 ace = &acl->sl_aces[numaces];
3205521Sas200622 ace->se_hdr.se_type = zace->a_type;
3215521Sas200622 ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
3225521Sas200622 ace->se_mask = zace->a_access_mask;
3236432Sas200622 ace->se_sid = smb_sid_dup(sim->sim_sid);
3245521Sas200622 ace->se_hdr.se_bsize = smb_ace_len(ace);
3255521Sas200622
3265521Sas200622 acl->sl_bsize += ace->se_hdr.se_bsize;
3275331Samw }
3285331Samw
3295521Sas200622 smb_idmap_batch_destroy(&sib);
3305521Sas200622 return (acl);
3315331Samw }
3325331Samw
3335331Samw /*
3345521Sas200622 * smb_acl_to_zfs
3355331Samw *
3365521Sas200622 * Converts given Windows ACL to a ZFS ACL.
3375331Samw *
3385521Sas200622 * fs_acl will contain a pointer to the created ZFS ACL.
3395521Sas200622 * The allocated memory should be freed by calling
3405521Sas200622 * smb_fsacl_free().
3415331Samw *
3425521Sas200622 * Since the output parameter, fs_acl, is allocated in this
3435521Sas200622 * function, the caller has to make sure *fs_acl is NULL which
3445521Sas200622 * means it's not pointing to any memory.
3455331Samw */
3465331Samw uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)3475521Sas200622 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
3485331Samw {
3495521Sas200622 smb_ace_t *ace;
3505521Sas200622 acl_t *zacl;
3515521Sas200622 ace_t *zace;
3525521Sas200622 smb_idmap_batch_t sib;
3535521Sas200622 smb_idmap_t *sim;
3545521Sas200622 idmap_stat idm_stat;
35511447Samw@Sun.COM char *sidstr;
3567348SJose.Borrego@Sun.COM int i;
3575331Samw
3585521Sas200622 ASSERT(fs_acl);
3595521Sas200622 ASSERT(*fs_acl == NULL);
3605521Sas200622
3615521Sas200622 if (acl && !smb_acl_isvalid(acl, which_acl))
3625521Sas200622 return (NT_STATUS_INVALID_ACL);
3635521Sas200622
3645521Sas200622 if ((acl == NULL) || (acl->sl_acecnt == 0)) {
3655521Sas200622 if (which_acl == SMB_DACL_SECINFO) {
3667348SJose.Borrego@Sun.COM *fs_acl = smb_fsacl_null_empty(acl == NULL);
3675521Sas200622 }
3685521Sas200622
3695521Sas200622 return (NT_STATUS_SUCCESS);
3705331Samw }
3715331Samw
3725521Sas200622 idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
3735521Sas200622 SMB_IDMAP_SID2ID);
3745521Sas200622 if (idm_stat != IDMAP_SUCCESS)
3755521Sas200622 return (NT_STATUS_INTERNAL_ERROR);
3765521Sas200622
37711447Samw@Sun.COM sidstr = kmem_alloc(SMB_SID_STRSZ, KM_SLEEP);
3785521Sas200622 zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
3795521Sas200622
3805521Sas200622 zace = zacl->acl_aclp;
3815521Sas200622 ace = acl->sl_aces;
3825521Sas200622 sim = sib.sib_maps;
3835521Sas200622
3845521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
3855521Sas200622 zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
3865521Sas200622 zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
3877348SJose.Borrego@Sun.COM zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
38811447Samw@Sun.COM zace->a_who = (uid_t)-1;
3895521Sas200622
39011447Samw@Sun.COM smb_sid_tostr(ace->se_sid, sidstr);
39111447Samw@Sun.COM
39211447Samw@Sun.COM if (!smb_ace_wellknown_update(sidstr, zace)) {
3935521Sas200622 sim->sim_id = &zace->a_who;
3945521Sas200622 idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
39511447Samw@Sun.COM ace->se_sid, SMB_IDMAP_UNKNOWN);
3965521Sas200622
3975521Sas200622 if (idm_stat != IDMAP_SUCCESS) {
39811447Samw@Sun.COM kmem_free(sidstr, SMB_SID_STRSZ);
3995521Sas200622 smb_fsacl_free(zacl);
4005521Sas200622 smb_idmap_batch_destroy(&sib);
4015521Sas200622 return (NT_STATUS_INTERNAL_ERROR);
4025521Sas200622 }
4035521Sas200622 }
4045331Samw }
4055331Samw
40611447Samw@Sun.COM kmem_free(sidstr, SMB_SID_STRSZ);
40711447Samw@Sun.COM
4085521Sas200622 idm_stat = smb_idmap_batch_getmappings(&sib);
4095521Sas200622 if (idm_stat != IDMAP_SUCCESS) {
4105521Sas200622 smb_fsacl_free(zacl);
4115521Sas200622 smb_idmap_batch_destroy(&sib);
4125521Sas200622 return (NT_STATUS_NONE_MAPPED);
4135331Samw }
4145331Samw
4155521Sas200622 /*
4165521Sas200622 * Set the ACEs group flag based on the type of ID returned.
4175521Sas200622 */
4185521Sas200622 zace = zacl->acl_aclp;
4195521Sas200622 ace = acl->sl_aces;
4205521Sas200622 sim = sib.sib_maps;
4215521Sas200622 for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
42211447Samw@Sun.COM if (zace->a_who == (uid_t)-1)
4235521Sas200622 continue;
4245521Sas200622
4255521Sas200622 if (sim->sim_idtype == SMB_IDMAP_GROUP)
4265521Sas200622 zace->a_flags |= ACE_IDENTIFIER_GROUP;
4275331Samw }
4285331Samw
4295521Sas200622 smb_idmap_batch_destroy(&sib);
4305521Sas200622
4315521Sas200622 *fs_acl = zacl;
4325521Sas200622 return (NT_STATUS_SUCCESS);
4335331Samw }
4345331Samw
43511447Samw@Sun.COM static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)43611447Samw@Sun.COM smb_ace_wellknown_update(const char *sid, ace_t *zace)
43711447Samw@Sun.COM {
43811447Samw@Sun.COM struct {
43911447Samw@Sun.COM char *sid;
44011447Samw@Sun.COM uint16_t flags;
44111447Samw@Sun.COM } map[] = {
44211447Samw@Sun.COM { NT_WORLD_SIDSTR, ACE_EVERYONE },
44311447Samw@Sun.COM { NT_BUILTIN_CURRENT_OWNER_SIDSTR, ACE_OWNER },
44411447Samw@Sun.COM { NT_BUILTIN_CURRENT_GROUP_SIDSTR,
44511447Samw@Sun.COM (ACE_GROUP | ACE_IDENTIFIER_GROUP) },
44611447Samw@Sun.COM };
44711447Samw@Sun.COM
44811447Samw@Sun.COM int i;
44911447Samw@Sun.COM
45011447Samw@Sun.COM for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
45111447Samw@Sun.COM if (strcmp(sid, map[i].sid) == 0) {
45211447Samw@Sun.COM zace->a_flags |= map[i].flags;
45311447Samw@Sun.COM return (B_TRUE);
45411447Samw@Sun.COM }
45511447Samw@Sun.COM }
45611447Samw@Sun.COM
45711447Samw@Sun.COM return (B_FALSE);
45811447Samw@Sun.COM }
45911447Samw@Sun.COM
4605331Samw /*
4617348SJose.Borrego@Sun.COM * smb_fsacl_getsids
4625331Samw *
4635331Samw * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
4645331Samw */
4655331Samw static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)46611447Samw@Sun.COM smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
4675331Samw {
4685331Samw ace_t *zace;
4695331Samw idmap_stat idm_stat;
4705331Samw smb_idmap_t *sim;
4715331Samw uid_t id;
4725331Samw int i, idtype;
4735331Samw
4745331Samw sim = sib->sib_maps;
4755331Samw
4765331Samw for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
4775331Samw zace++, i++, sim++) {
4785331Samw switch (zace->a_flags & ACE_TYPE_FLAGS) {
4795331Samw case ACE_OWNER:
48011447Samw@Sun.COM idtype = SMB_IDMAP_OWNERAT;
4815331Samw break;
4825331Samw
4835331Samw case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
4845331Samw /* owning group */
48511447Samw@Sun.COM idtype = SMB_IDMAP_GROUPAT;
4865331Samw break;
4875331Samw
4885331Samw case ACE_IDENTIFIER_GROUP:
4895331Samw /* regular group */
4905331Samw id = zace->a_who;
4915331Samw idtype = SMB_IDMAP_GROUP;
4925331Samw break;
4935331Samw
4945331Samw case ACE_EVERYONE:
4955331Samw idtype = SMB_IDMAP_EVERYONE;
4965331Samw break;
4975331Samw
4985331Samw default:
4995331Samw /* user entry */
5005331Samw id = zace->a_who;
5015331Samw idtype = SMB_IDMAP_USER;
5025331Samw }
5035331Samw
5045331Samw idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
5055331Samw id, idtype);
5065331Samw
5075331Samw if (idm_stat != IDMAP_SUCCESS) {
5085331Samw return (idm_stat);
5095331Samw }
5105331Samw }
5115331Samw
5125331Samw idm_stat = smb_idmap_batch_getmappings(sib);
5135331Samw return (idm_stat);
5145331Samw }
5155331Samw
5165331Samw /*
5177348SJose.Borrego@Sun.COM * smb_fsacl_null_empty
5185331Samw *
5195331Samw * NULL DACL means everyone full-access
5205331Samw * Empty DACL means everyone full-deny
5215331Samw *
5225331Samw * ZFS ACL must have at least one entry so smb server has
5235331Samw * to simulate the aforementioned expected behavior by adding
5245331Samw * an entry in case the requested DACL is null or empty. Adding
5255331Samw * a everyone full-deny entry has proved to be problematic in
5265331Samw * tests since a deny entry takes precedence over allow entries.
5275331Samw * So, instead of adding a everyone full-deny, an owner ACE with
5285331Samw * owner implicit permissions will be set.
5295331Samw */
5305521Sas200622 static acl_t *
smb_fsacl_null_empty(boolean_t null)5317348SJose.Borrego@Sun.COM smb_fsacl_null_empty(boolean_t null)
5325331Samw {
5335331Samw acl_t *zacl;
5345331Samw ace_t *zace;
5355331Samw
5365521Sas200622 zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
5375331Samw zace = zacl->acl_aclp;
5385331Samw
5395331Samw zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
5405331Samw if (null) {
5415331Samw zace->a_access_mask = ACE_ALL_PERMS;
5425331Samw zace->a_flags = ACE_EVERYONE;
5435331Samw } else {
5445331Samw zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
5455331Samw ACE_READ_ATTRIBUTES;
5465331Samw zace->a_flags = ACE_OWNER;
5475331Samw }
5485331Samw
5495331Samw return (zacl);
5505331Samw }
5515331Samw
5525331Samw /*
5535521Sas200622 * FS ACL (acl_t) Functions
5545331Samw */
5555521Sas200622 acl_t *
smb_fsacl_alloc(int acenum,int flags)5565521Sas200622 smb_fsacl_alloc(int acenum, int flags)
5575331Samw {
5585521Sas200622 acl_t *acl;
5595331Samw
5605521Sas200622 acl = acl_alloc(ACE_T);
5615521Sas200622 acl->acl_cnt = acenum;
5625521Sas200622 acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
5635521Sas200622 acl->acl_flags = flags;
5645521Sas200622 return (acl);
5655521Sas200622 }
5665331Samw
5675521Sas200622 void
smb_fsacl_free(acl_t * acl)5685521Sas200622 smb_fsacl_free(acl_t *acl)
5695521Sas200622 {
5705521Sas200622 if (acl)
5715521Sas200622 acl_free(acl);
5725521Sas200622 }
5735331Samw
5745521Sas200622 /*
5755521Sas200622 * smb_fsop_aclmerge
5765521Sas200622 *
5775521Sas200622 * smb_fsop_aclread/write routines which interact with filesystem
5785521Sas200622 * work with single ACL. This routine merges given DACL and SACL
5795521Sas200622 * which might have been created during CIFS to FS conversion into
5805521Sas200622 * one single ACL.
5815521Sas200622 */
5825521Sas200622 acl_t *
smb_fsacl_merge(acl_t * dacl,acl_t * sacl)5835521Sas200622 smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
5845521Sas200622 {
5855521Sas200622 acl_t *acl;
5865521Sas200622 int dacl_size;
5875331Samw
5885521Sas200622 ASSERT(dacl);
5895521Sas200622 ASSERT(sacl);
5905331Samw
5915521Sas200622 acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
5925521Sas200622 dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
5935521Sas200622 bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
5945521Sas200622 bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
5955521Sas200622 sacl->acl_cnt * sacl->acl_entry_size);
5965331Samw
5975521Sas200622 return (acl);
5985331Samw }
5995331Samw
6005331Samw /*
6015521Sas200622 * smb_fsacl_split
6025331Samw *
6035521Sas200622 * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
6045521Sas200622 * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
6055521Sas200622 * NULL even if they're specified in 'which_acl', which means the target
6065521Sas200622 * doesn't have any access and/or audit ACEs.
6075331Samw */
6085521Sas200622 void
smb_fsacl_split(acl_t * zacl,acl_t ** dacl,acl_t ** sacl,int which_acl)6095521Sas200622 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
6105331Samw {
6115331Samw ace_t *zace;
6125521Sas200622 ace_t *access_ace;
6135521Sas200622 ace_t *audit_ace;
6145521Sas200622 int naccess, naudit;
6155521Sas200622 int get_dacl, get_sacl;
6165521Sas200622 int i;
6175521Sas200622
6185521Sas200622 *dacl = *sacl = NULL;
6195521Sas200622 naccess = naudit = 0;
6205521Sas200622 get_dacl = (which_acl & SMB_DACL_SECINFO);
6215521Sas200622 get_sacl = (which_acl & SMB_SACL_SECINFO);
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 naccess++;
6265521Sas200622 else if (get_sacl && smb_ace_is_audit(zace->a_type))
6275521Sas200622 naudit++;
6285521Sas200622 }
6295331Samw
6305521Sas200622 if (naccess) {
6315521Sas200622 *dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
6325521Sas200622 access_ace = (*dacl)->acl_aclp;
6335521Sas200622 }
6345331Samw
6355521Sas200622 if (naudit) {
6365521Sas200622 *sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
6375521Sas200622 audit_ace = (*sacl)->acl_aclp;
6385521Sas200622 }
6395331Samw
6405521Sas200622 for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
6415521Sas200622 if (get_dacl && smb_ace_is_access(zace->a_type)) {
6425521Sas200622 *access_ace = *zace;
6435521Sas200622 access_ace++;
6445521Sas200622 } else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
6455521Sas200622 *audit_ace = *zace;
6465521Sas200622 audit_ace++;
6475331Samw }
6485331Samw }
6495331Samw }
6505331Samw
6515331Samw /*
6525521Sas200622 * ACE Inheritance Rules
6535521Sas200622 *
6545521Sas200622 * The system propagates inheritable ACEs to child objects according to a
6555521Sas200622 * set of inheritance rules. The system places inherited ACEs in the child's
6565521Sas200622 * DACL according to the preferred order of ACEs in a DACL. For Windows
6575521Sas200622 * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
6585521Sas200622 *
6595521Sas200622 * The following table shows the ACEs inherited by container and noncontainer
6605521Sas200622 * child objects for different combinations of inheritance flags. These
6615521Sas200622 * inheritance rules work the same for both DACLs and SACLs.
6625521Sas200622 *
6635521Sas200622 * Parent ACE type Effect on Child ACL
6645521Sas200622 * ----------------------- -------------------
6655521Sas200622 * OBJECT_INHERIT_ACE only Noncontainer child objects:
6665521Sas200622 * Inherited as an effective ACE.
6675521Sas200622 * Container child objects:
6685521Sas200622 * Containers inherit an inherit-only ACE
6695521Sas200622 * unless the NO_PROPAGATE_INHERIT_ACE bit
6705521Sas200622 * flag is also set.
6715521Sas200622 *
6725521Sas200622 * CONTAINER_INHERIT_ACE only Noncontainer child objects:
6735521Sas200622 * No effect on the child object.
6745521Sas200622 * Container child objects:
6755521Sas200622 * The child object inherits an effective ACE.
6765521Sas200622 * The inherited ACE is inheritable unless the
6775521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set.
6785521Sas200622 *
6795521Sas200622 * CONTAINER_INHERIT_ACE and
6805521Sas200622 * OBJECT_INHERIT_ACE Noncontainer child objects:
6815521Sas200622 * Inherited as an effective ACE.
6825521Sas200622 * Container child objects:
6835521Sas200622 * The child object inherits an effective ACE.
6845521Sas200622 * The inherited ACE is inheritable unless the
6855521Sas200622 * NO_PROPAGATE_INHERIT_ACE bit flag is also set
6865521Sas200622 *
6875521Sas200622 * No inheritance flags set No effect on child container or noncontainer
6885521Sas200622 * objects.
6895521Sas200622 *
6905521Sas200622 * If an inherited ACE is an effective ACE for the child object, the system
6915521Sas200622 * maps any generic rights to the specific rights for the child object.
6925521Sas200622 * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
6935521Sas200622 * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
6945521Sas200622 * rights or generic SIDs are left unchanged so that they can be mapped
6955521Sas200622 * appropriately when the ACE is inherited by the next generation of child
6965521Sas200622 * objects.
6975521Sas200622 *
6985521Sas200622 * For a case in which a container object inherits an ACE that is both
6995521Sas200622 * effective on the container and inheritable by its descendants, the
7005521Sas200622 * container may inherit two ACEs. This occurs if the inheritable ACE
7015521Sas200622 * contains generic information. The container inherits an inherit-only
7025521Sas200622 * ACE containing the generic information and an effective-only ACE in
7035521Sas200622 * which the generic information has been mapped.
7045331Samw */
7055331Samw
7065331Samw /*
7075521Sas200622 * smb_fsacl_inherit
7085331Samw *
7095331Samw * Manufacture the inherited ACL from the given ACL considering
7105331Samw * the new object type (file/dir) specified by 'is_dir'. The
7115331Samw * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
7125521Sas200622 * This function implements Windows inheritance rules explained above.
7135331Samw *
7145521Sas200622 * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
7155331Samw */
7165331Samw acl_t *
smb_fsacl_inherit(acl_t * dir_zacl,int is_dir,int which_acl,cred_t * cr)717*11963SAfshin.Ardakani@Sun.COM smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, cred_t *cr)
7185331Samw {
7195331Samw boolean_t use_default = B_FALSE;
7205331Samw int num_inheritable = 0;
7215331Samw int numaces;
7225331Samw ace_t *dir_zace;
7235331Samw acl_t *new_zacl;
7245331Samw ace_t *new_zace;
725*11963SAfshin.Ardakani@Sun.COM ksid_t *owner_sid;
726*11963SAfshin.Ardakani@Sun.COM ksid_t *group_sid;
727*11963SAfshin.Ardakani@Sun.COM uid_t uid;
728*11963SAfshin.Ardakani@Sun.COM gid_t gid;
729*11963SAfshin.Ardakani@Sun.COM
730*11963SAfshin.Ardakani@Sun.COM owner_sid = crgetsid(cr, KSID_OWNER);
731*11963SAfshin.Ardakani@Sun.COM group_sid = crgetsid(cr, KSID_GROUP);
732*11963SAfshin.Ardakani@Sun.COM ASSERT(owner_sid);
733*11963SAfshin.Ardakani@Sun.COM ASSERT(group_sid);
734*11963SAfshin.Ardakani@Sun.COM uid = owner_sid->ks_id;
735*11963SAfshin.Ardakani@Sun.COM gid = group_sid->ks_id;
7365331Samw
7375521Sas200622 num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
7385331Samw
7395331Samw if (num_inheritable == 0) {
7405331Samw if (which_acl == SMB_DACL_SECINFO) {
7415331Samw /* No inheritable access ACEs -> default DACL */
7425331Samw num_inheritable = DEFAULT_DACL_ACENUM;
7435331Samw use_default = B_TRUE;
7445331Samw } else {
7455331Samw return (NULL);
7465331Samw }
7475331Samw }
7485331Samw
7495521Sas200622 new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
7505331Samw new_zace = new_zacl->acl_aclp;
7515331Samw
7525331Samw if (use_default) {
7535331Samw bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
754*11963SAfshin.Ardakani@Sun.COM new_zace->a_who = uid;
7555331Samw return (new_zacl);
7565331Samw }
7575331Samw
7585331Samw for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
7595331Samw numaces < dir_zacl->acl_cnt;
7605331Samw dir_zace++, numaces++) {
7615331Samw switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
7625331Samw case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
7635331Samw /*
7645331Samw * Files inherit an effective ACE.
7655331Samw *
7665331Samw * Dirs inherit an effective ACE.
7675331Samw * The inherited ACE is inheritable unless the
7685331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
7695331Samw */
770*11963SAfshin.Ardakani@Sun.COM smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
7715331Samw new_zace++;
7725331Samw
7735331Samw if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
7745331Samw (ZACE_IS_PROPAGATE(dir_zace))) {
7755331Samw *new_zace = *dir_zace;
7765331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
7775331Samw ACE_INHERITED_ACE);
7785331Samw new_zace++;
7795331Samw }
7805331Samw break;
7815331Samw
7825331Samw case ACE_FILE_INHERIT_ACE:
7835331Samw /*
7845331Samw * Files inherit as an effective ACE.
7855331Samw *
7865331Samw * Dirs inherit an inherit-only ACE
7875331Samw * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
7885331Samw * flag is also set.
7895331Samw */
7905331Samw if (is_dir == 0) {
791*11963SAfshin.Ardakani@Sun.COM smb_ace_inherit(dir_zace, new_zace, is_dir,
792*11963SAfshin.Ardakani@Sun.COM uid, gid);
7935331Samw new_zace++;
7945331Samw } else if (ZACE_IS_PROPAGATE(dir_zace)) {
7955331Samw *new_zace = *dir_zace;
7965331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
7975331Samw ACE_INHERITED_ACE);
7985331Samw new_zace++;
7995331Samw }
8005331Samw break;
8015331Samw
8025331Samw case ACE_DIRECTORY_INHERIT_ACE:
8035331Samw /*
8045331Samw * No effect on files
8055331Samw *
8065331Samw * Dirs inherit an effective ACE.
8075331Samw * The inherited ACE is inheritable unless the
8085331Samw * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
8095331Samw */
8105331Samw if (is_dir == 0)
8115331Samw break;
8125331Samw
813*11963SAfshin.Ardakani@Sun.COM smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
8145331Samw new_zace++;
8155331Samw
8165331Samw if (ZACE_IS_CREATOR(dir_zace) &&
8175331Samw (ZACE_IS_PROPAGATE(dir_zace))) {
8185331Samw *new_zace = *dir_zace;
8195331Samw new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
8205331Samw ACE_INHERITED_ACE);
8215331Samw new_zace++;
8225331Samw }
8235331Samw
8245331Samw break;
8255331Samw
8265331Samw default:
8275331Samw break;
8285331Samw }
8295331Samw }
8305331Samw
8315331Samw return (new_zacl);
8325331Samw }
8335331Samw
8345521Sas200622 /*
8355521Sas200622 * smb_fsacl_from_vsa
8365521Sas200622 *
8375521Sas200622 * Converts given vsecattr_t structure to a acl_t structure.
8385521Sas200622 *
8395521Sas200622 * The allocated memory for retuned acl_t should be freed by
8405521Sas200622 * calling acl_free().
8415521Sas200622 */
8425521Sas200622 acl_t *
smb_fsacl_from_vsa(vsecattr_t * vsecattr,acl_type_t acl_type)8435521Sas200622 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
8445521Sas200622 {
8455521Sas200622 int aclbsize = 0; /* size of acl list in bytes */
8465521Sas200622 int dfaclbsize = 0; /* size of default acl list in bytes */
8475521Sas200622 int numacls;
8485521Sas200622 acl_t *acl_info;
8495521Sas200622
8505521Sas200622 ASSERT(vsecattr);
8515521Sas200622
8525521Sas200622 acl_info = acl_alloc(acl_type);
8535521Sas200622 if (acl_info == NULL)
8545521Sas200622 return (NULL);
8555521Sas200622
8565521Sas200622 acl_info->acl_flags = 0;
8575521Sas200622
8585521Sas200622 switch (acl_type) {
8595521Sas200622
8605521Sas200622 case ACLENT_T:
8615521Sas200622 numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
8625521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
8635521Sas200622 dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
8645521Sas200622
8655521Sas200622 acl_info->acl_cnt = numacls;
8665521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
8675521Sas200622 KM_SLEEP);
8685521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
8695521Sas200622 aclbsize);
8705521Sas200622 (void) memcpy((char *)acl_info->acl_aclp + aclbsize,
8715521Sas200622 vsecattr->vsa_dfaclentp, dfaclbsize);
8725521Sas200622
8735521Sas200622 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
8745521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL;
8755521Sas200622
8765521Sas200622 break;
8775521Sas200622
8785521Sas200622 case ACE_T:
8795521Sas200622 aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
8805521Sas200622 acl_info->acl_cnt = vsecattr->vsa_aclcnt;
8815521Sas200622 acl_info->acl_flags = vsecattr->vsa_aclflags;
8825521Sas200622 acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
8835521Sas200622 (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
8845521Sas200622 aclbsize);
8855521Sas200622 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
8865521Sas200622 acl_info->acl_flags |= ACL_IS_TRIVIAL;
8875521Sas200622
8885521Sas200622 break;
8895521Sas200622
8905521Sas200622 default:
8915521Sas200622 acl_free(acl_info);
8925521Sas200622 return (NULL);
8935521Sas200622 }
8945521Sas200622
8955521Sas200622 if (aclbsize && vsecattr->vsa_aclentp)
8965521Sas200622 kmem_free(vsecattr->vsa_aclentp, aclbsize);
8975521Sas200622 if (dfaclbsize && vsecattr->vsa_dfaclentp)
8985521Sas200622 kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
8995521Sas200622
9005521Sas200622 return (acl_info);
9015521Sas200622 }
9025521Sas200622
9035521Sas200622 /*
9045521Sas200622 * smb_fsacl_to_vsa
9055521Sas200622 *
9065521Sas200622 * Converts given acl_t structure to a vsecattr_t structure.
9075521Sas200622 *
9085521Sas200622 * IMPORTANT:
9095521Sas200622 * Upon successful return the memory allocated for vsa_aclentp
9105521Sas200622 * should be freed by calling kmem_free(). The size is returned
9115521Sas200622 * in aclbsize.
9125521Sas200622 */
9135521Sas200622 int
smb_fsacl_to_vsa(acl_t * acl_info,vsecattr_t * vsecattr,int * aclbsize)9145521Sas200622 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
9155521Sas200622 {
9165521Sas200622 int error = 0;
9175521Sas200622 int numacls;
9185521Sas200622 aclent_t *aclp;
9195521Sas200622
9205521Sas200622 ASSERT(acl_info);
9215521Sas200622 ASSERT(vsecattr);
9225521Sas200622 ASSERT(aclbsize);
9235521Sas200622
9245521Sas200622 bzero(vsecattr, sizeof (vsecattr_t));
9255521Sas200622 *aclbsize = 0;
9265521Sas200622
9275521Sas200622 switch (acl_info->acl_type) {
9285521Sas200622 case ACLENT_T:
9295521Sas200622 numacls = acl_info->acl_cnt;
9305521Sas200622 /*
9315521Sas200622 * Minimum ACL size is three entries so might as well
9325521Sas200622 * bail out here. Also limit request size to prevent user
9335521Sas200622 * from allocating too much kernel memory. Maximum size
9345521Sas200622 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
9355521Sas200622 * for the default ACL part.
9365521Sas200622 */
9375521Sas200622 if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
9385521Sas200622 error = EINVAL;
9395521Sas200622 break;
9405521Sas200622 }
9415521Sas200622
9425521Sas200622 vsecattr->vsa_mask = VSA_ACL;
9435521Sas200622
9445521Sas200622 vsecattr->vsa_aclcnt = numacls;
9455521Sas200622 *aclbsize = numacls * sizeof (aclent_t);
9465521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
9475521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
9485521Sas200622 *aclbsize);
9495521Sas200622
9505521Sas200622 /* Sort the acl list */
9515521Sas200622 ksort((caddr_t)vsecattr->vsa_aclentp,
9525521Sas200622 vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
9535521Sas200622
9545521Sas200622 /* Break into acl and default acl lists */
9555521Sas200622 for (numacls = 0, aclp = vsecattr->vsa_aclentp;
9565521Sas200622 numacls < vsecattr->vsa_aclcnt;
9575521Sas200622 aclp++, numacls++) {
9585521Sas200622 if (aclp->a_type & ACL_DEFAULT)
9595521Sas200622 break;
9605521Sas200622 }
9615521Sas200622
9625521Sas200622 /* Find where defaults start (if any) */
9635521Sas200622 if (numacls < vsecattr->vsa_aclcnt) {
9645521Sas200622 vsecattr->vsa_mask |= VSA_DFACL;
9655521Sas200622 vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
9665521Sas200622 vsecattr->vsa_dfaclentp = aclp;
9675521Sas200622 vsecattr->vsa_aclcnt = numacls;
9685521Sas200622 }
9695521Sas200622
9705521Sas200622 /* Adjust if they're all defaults */
9715521Sas200622 if (vsecattr->vsa_aclcnt == 0) {
9725521Sas200622 vsecattr->vsa_mask &= ~VSA_ACL;
9735521Sas200622 vsecattr->vsa_aclentp = NULL;
9745521Sas200622 }
9755521Sas200622
9765521Sas200622 /* Only directories can have defaults */
9775521Sas200622 if (vsecattr->vsa_dfaclcnt &&
9785521Sas200622 (acl_info->acl_flags & ACL_IS_DIR)) {
9795521Sas200622 error = ENOTDIR;
9805521Sas200622 }
9815521Sas200622
9825521Sas200622 break;
9835521Sas200622
9845521Sas200622 case ACE_T:
9855521Sas200622 if (acl_info->acl_cnt < 1 ||
9865521Sas200622 acl_info->acl_cnt > MAX_ACL_ENTRIES) {
9875521Sas200622 error = EINVAL;
9885521Sas200622 break;
9895521Sas200622 }
9905521Sas200622
9915521Sas200622 vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
9925521Sas200622 vsecattr->vsa_aclcnt = acl_info->acl_cnt;
9935521Sas200622 vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
9945521Sas200622 *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
9955521Sas200622 vsecattr->vsa_aclentsz = *aclbsize;
9965521Sas200622 vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
9975521Sas200622 (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
9985521Sas200622 *aclbsize);
9995521Sas200622
10005521Sas200622 break;
10015521Sas200622
10025521Sas200622 default:
10035521Sas200622 error = EINVAL;
10045521Sas200622 }
10055521Sas200622
10065521Sas200622 return (error);
10075521Sas200622 }
10085521Sas200622
10095521Sas200622 /*
10105521Sas200622 * smb_fsacl_inheritable
10115521Sas200622 *
10125521Sas200622 * Checks to see if there are any inheritable ACEs in the
10135521Sas200622 * given ZFS ACL. Returns the number of inheritable ACEs.
10145521Sas200622 *
10155521Sas200622 * The inherited ACL could be different based on the type of
10165521Sas200622 * new object (file/dir) specified by 'is_dir'.
10175521Sas200622 *
10185521Sas200622 * Note that the input ACL is a ZFS ACL not Windows ACL.
10195521Sas200622 */
10205521Sas200622 static int
smb_fsacl_inheritable(acl_t * zacl,int is_dir)10215521Sas200622 smb_fsacl_inheritable(acl_t *zacl, int is_dir)
10225521Sas200622 {
10235521Sas200622 int numaces;
10245521Sas200622 int num_inheritable = 0;
10255521Sas200622 ace_t *zace;
10265521Sas200622
10275521Sas200622 if (zacl == NULL)
10285521Sas200622 return (0);
10295521Sas200622
10305521Sas200622 for (numaces = 0, zace = zacl->acl_aclp;
10315521Sas200622 numaces < zacl->acl_cnt;
10325521Sas200622 zace++, numaces++) {
10335521Sas200622 switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
10345521Sas200622 case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
10355521Sas200622 /*
10365521Sas200622 * Files inherit an effective ACE.
10375521Sas200622 *
10385521Sas200622 * Dirs inherit an effective ACE.
10395521Sas200622 * The inherited ACE is inheritable unless the
10405521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
10415521Sas200622 */
10425521Sas200622 num_inheritable++;
10435521Sas200622
10445521Sas200622 if (is_dir && ZACE_IS_CREATOR(zace) &&
10455521Sas200622 (ZACE_IS_PROPAGATE(zace))) {
10465521Sas200622 num_inheritable++;
10475521Sas200622 }
10485521Sas200622 break;
10495521Sas200622
10505521Sas200622 case ACE_FILE_INHERIT_ACE:
10515521Sas200622 /*
10525521Sas200622 * Files inherit as an effective ACE.
10535521Sas200622 *
10545521Sas200622 * Dirs inherit an inherit-only ACE
10555521Sas200622 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
10565521Sas200622 * flag is also set.
10575521Sas200622 */
10585521Sas200622 if (is_dir == 0)
10595521Sas200622 num_inheritable++;
10605521Sas200622 else if (ZACE_IS_PROPAGATE(zace))
10615521Sas200622 num_inheritable++;
10625521Sas200622 break;
10635521Sas200622
10645521Sas200622 case ACE_DIRECTORY_INHERIT_ACE:
10655521Sas200622 /*
10665521Sas200622 * No effect on files
10675521Sas200622 *
10685521Sas200622 * Dirs inherit an effective ACE.
10695521Sas200622 * The inherited ACE is inheritable unless the
10705521Sas200622 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
10715521Sas200622 */
10725521Sas200622 if (is_dir == 0)
10735521Sas200622 break;
10745521Sas200622
10755521Sas200622 num_inheritable++;
10765521Sas200622
10775521Sas200622 if (ZACE_IS_CREATOR(zace) &&
10785521Sas200622 (ZACE_IS_PROPAGATE(zace)))
10795521Sas200622 num_inheritable++;
10805521Sas200622 break;
10815521Sas200622
10825521Sas200622 default:
10835521Sas200622 break;
10845521Sas200622 }
10855521Sas200622 }
10865521Sas200622
10875521Sas200622 return (num_inheritable);
10885521Sas200622 }
10895521Sas200622
10905521Sas200622
10915521Sas200622 /*
10925521Sas200622 * ACE Functions
10935521Sas200622 */
10945521Sas200622
10955521Sas200622 /*
10965521Sas200622 * This is generic (ACL version 2) vs. object-specific
10975521Sas200622 * (ACL version 4) ACE types.
10985521Sas200622 */
10995521Sas200622 boolean_t
smb_ace_is_generic(int type)11005521Sas200622 smb_ace_is_generic(int type)
11015521Sas200622 {
11025521Sas200622 switch (type) {
11035521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE:
11045521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE:
11055521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE:
11065521Sas200622 case ACE_SYSTEM_ALARM_ACE_TYPE:
11075521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
11085521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
11095521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
11105521Sas200622 case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
11115521Sas200622 return (B_TRUE);
11125521Sas200622
11135521Sas200622 default:
11145521Sas200622 break;
11155521Sas200622 }
11165521Sas200622
11175521Sas200622 return (B_FALSE);
11185521Sas200622 }
11195521Sas200622
11205521Sas200622 boolean_t
smb_ace_is_access(int type)11215521Sas200622 smb_ace_is_access(int type)
11225521Sas200622 {
11235521Sas200622 switch (type) {
11245521Sas200622 case ACE_ACCESS_ALLOWED_ACE_TYPE:
11255521Sas200622 case ACE_ACCESS_DENIED_ACE_TYPE:
11265521Sas200622 case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
11275521Sas200622 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
11285521Sas200622 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
11295521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
11305521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
11315521Sas200622 case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
11325521Sas200622 case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
11335521Sas200622 return (B_TRUE);
11345521Sas200622
11355521Sas200622 default:
11365521Sas200622 break;
11375521Sas200622 }
11385521Sas200622
11395521Sas200622 return (B_FALSE);
11405521Sas200622 }
11415521Sas200622
11425521Sas200622 boolean_t
smb_ace_is_audit(int type)11435521Sas200622 smb_ace_is_audit(int type)
11445521Sas200622 {
11455521Sas200622 switch (type) {
11465521Sas200622 case ACE_SYSTEM_AUDIT_ACE_TYPE:
11475521Sas200622 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
11485521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
11495521Sas200622 case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
11505521Sas200622 return (B_TRUE);
11515521Sas200622
11525521Sas200622 default:
11535521Sas200622 break;
11545521Sas200622 }
11555521Sas200622
11565521Sas200622 return (B_FALSE);
11575521Sas200622 }
11585521Sas200622
11595521Sas200622 /*
11605521Sas200622 * smb_ace_len
11615521Sas200622 *
11625521Sas200622 * Returns the length of the given ACE as it appears in an
11635521Sas200622 * ACL on the wire (i.e. a flat buffer which contains the SID)
11645521Sas200622 */
11655521Sas200622 static uint16_t
smb_ace_len(smb_ace_t * ace)11665521Sas200622 smb_ace_len(smb_ace_t *ace)
11675521Sas200622 {
11685521Sas200622 ASSERT(ace);
11695521Sas200622 ASSERT(ace->se_sid);
11705521Sas200622
11715521Sas200622 if (ace == NULL)
11725521Sas200622 return (0);
11735521Sas200622
11745521Sas200622 return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
11756432Sas200622 smb_sid_len(ace->se_sid));
11765521Sas200622 }
11775521Sas200622
11785331Samw static void
smb_ace_inherit(ace_t * dir_zace,ace_t * zace,int is_dir,uid_t uid,gid_t gid)1179*11963SAfshin.Ardakani@Sun.COM smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir, uid_t uid, gid_t gid)
11805331Samw {
11815331Samw *zace = *dir_zace;
11827348SJose.Borrego@Sun.COM
11837348SJose.Borrego@Sun.COM /* This is an effective ACE so remove the inherit_only flag */
11847348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_ONLY_ACE;
11857348SJose.Borrego@Sun.COM /* Mark this ACE as inherited */
11865331Samw zace->a_flags |= ACE_INHERITED_ACE;
11875331Samw
11885331Samw /*
11897348SJose.Borrego@Sun.COM * If this is a file or NO_PROPAGATE is set then this inherited
11907348SJose.Borrego@Sun.COM * ACE is not inheritable so clear the inheritance flags
11917348SJose.Borrego@Sun.COM */
11927348SJose.Borrego@Sun.COM if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
11937348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS;
11947348SJose.Borrego@Sun.COM
11957348SJose.Borrego@Sun.COM /*
11967348SJose.Borrego@Sun.COM * Replace creator owner/group ACEs with actual owner/group ACEs.
1197*11963SAfshin.Ardakani@Sun.COM * This is a non-inheritable effective ACE.
11985331Samw */
11995331Samw if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
1200*11963SAfshin.Ardakani@Sun.COM zace->a_who = uid;
12017348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS;
12025331Samw } else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
1203*11963SAfshin.Ardakani@Sun.COM zace->a_who = gid;
1204*11963SAfshin.Ardakani@Sun.COM zace->a_flags |= ACE_IDENTIFIER_GROUP;
12057348SJose.Borrego@Sun.COM zace->a_flags &= ~ACE_INHERIT_FLAGS;
12065331Samw }
12075331Samw }
12085331Samw
12095521Sas200622 /*
12105521Sas200622 * smb_ace_mask_g2s
12115521Sas200622 *
12125521Sas200622 * Converts generic access bits in the given mask (if any)
12135521Sas200622 * to file specific bits. Generic access masks shouldn't be
12145521Sas200622 * stored in filesystem ACEs.
12155521Sas200622 */
12165521Sas200622 static uint32_t
smb_ace_mask_g2s(uint32_t mask)12175521Sas200622 smb_ace_mask_g2s(uint32_t mask)
12185521Sas200622 {
12195521Sas200622 if (mask & GENERIC_ALL) {
12205521Sas200622 mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
12215521Sas200622 | GENERIC_EXECUTE);
12225521Sas200622
12235521Sas200622 mask |= FILE_ALL_ACCESS;
12245521Sas200622 return (mask);
12255521Sas200622 }
12265521Sas200622
12275521Sas200622 if (mask & GENERIC_READ) {
12285521Sas200622 mask &= ~GENERIC_READ;
12295521Sas200622 mask |= FILE_GENERIC_READ;
12305521Sas200622 }
12315521Sas200622
12325521Sas200622 if (mask & GENERIC_WRITE) {
12335521Sas200622 mask &= ~GENERIC_WRITE;
12345521Sas200622 mask |= FILE_GENERIC_WRITE;
12355521Sas200622 }
12365521Sas200622
12375521Sas200622 if (mask & GENERIC_EXECUTE) {
12385521Sas200622 mask &= ~GENERIC_EXECUTE;
12395521Sas200622 mask |= FILE_GENERIC_EXECUTE;
12405521Sas200622 }
12415521Sas200622
12425521Sas200622 return (mask);
12435521Sas200622 }
12445521Sas200622
12457348SJose.Borrego@Sun.COM /*
12467348SJose.Borrego@Sun.COM * smb_ace_flags_tozfs
12477348SJose.Borrego@Sun.COM *
12487348SJose.Borrego@Sun.COM * This function maps the flags which have different values
12497348SJose.Borrego@Sun.COM * in Windows and Solaris. The ones with the same value are
12507348SJose.Borrego@Sun.COM * transferred untouched.
12517348SJose.Borrego@Sun.COM */
12525331Samw static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)12537348SJose.Borrego@Sun.COM smb_ace_flags_tozfs(uint8_t c_flags)
12545331Samw {
12555331Samw uint16_t z_flags = 0;
12565331Samw
12575331Samw if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
12585331Samw z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
12595331Samw
12605331Samw if (c_flags & FAILED_ACCESS_ACE_FLAG)
12615331Samw z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
12625331Samw
12635331Samw if (c_flags & INHERITED_ACE)
12645331Samw z_flags |= ACE_INHERITED_ACE;
12655331Samw
12667348SJose.Borrego@Sun.COM z_flags |= (c_flags & ACE_INHERIT_FLAGS);
12675331Samw
12685331Samw return (z_flags);
12695331Samw }
12705331Samw
12715331Samw static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)12725331Samw smb_ace_flags_fromzfs(uint16_t z_flags)
12735331Samw {
12745331Samw uint8_t c_flags;
12755331Samw
12765331Samw c_flags = z_flags & ACE_INHERIT_FLAGS;
12775331Samw
12785331Samw if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
12795331Samw c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
12805331Samw
12815331Samw if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
12825331Samw c_flags |= FAILED_ACCESS_ACE_FLAG;
12835331Samw
12845331Samw if (z_flags & ACE_INHERITED_ACE)
12855331Samw c_flags |= INHERITED_ACE;
12865331Samw
12875331Samw return (c_flags);
12885331Samw }
12895331Samw
12905521Sas200622 static boolean_t
smb_ace_isvalid(smb_ace_t * ace,int which_acl)12915521Sas200622 smb_ace_isvalid(smb_ace_t *ace, int which_acl)
12925331Samw {
12935521Sas200622 uint16_t min_len;
12945521Sas200622
12955521Sas200622 min_len = sizeof (smb_acehdr_t);
12965521Sas200622
12975521Sas200622 if (ace->se_hdr.se_bsize < min_len)
12985521Sas200622 return (B_FALSE);
12995521Sas200622
13005521Sas200622 if (smb_ace_is_access(ace->se_hdr.se_type) &&
13015521Sas200622 (which_acl != SMB_DACL_SECINFO))
13025521Sas200622 return (B_FALSE);
13035331Samw
13045521Sas200622 if (smb_ace_is_audit(ace->se_hdr.se_type) &&
13055521Sas200622 (which_acl != SMB_SACL_SECINFO))
13065521Sas200622 return (B_FALSE);
13075521Sas200622
13085521Sas200622 if (smb_ace_is_generic(ace->se_hdr.se_type)) {
13096432Sas200622 if (!smb_sid_isvalid(ace->se_sid))
13105521Sas200622 return (B_FALSE);
13115521Sas200622
13125521Sas200622 min_len += sizeof (ace->se_mask);
13136432Sas200622 min_len += smb_sid_len(ace->se_sid);
13145521Sas200622
13155521Sas200622 if (ace->se_hdr.se_bsize < min_len)
13165521Sas200622 return (B_FALSE);
13175331Samw }
13185331Samw
13195521Sas200622 /*
13205521Sas200622 * object-specific ACE validation will be added later.
13215521Sas200622 */
13225521Sas200622 return (B_TRUE);
13235331Samw }
1324