xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_acl.c (revision 11447:b5b2a9bd508f)
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