xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_acl.c (revision 7206bf49b1fe641544165ee97f63856da95e0868)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24*7206bf49SGordon Ross  *
25*7206bf49SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <sys/sid.h>
29da6c28aaSamw #include <sys/acl.h>
3055bf511dSas200622 #include <acl/acl_common.h>
316537f381Sas200622 #include <smbsrv/smb_sid.h>
32da6c28aaSamw #include <smbsrv/smb_fsops.h>
33da6c28aaSamw #include <smbsrv/smb_idmap.h>
3455bf511dSas200622 #include <smbsrv/smb_kproto.h>
35da6c28aaSamw 
36da6c28aaSamw #define	ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
37da6c28aaSamw 
38da6c28aaSamw #define	ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
39da6c28aaSamw #define	ZACE_IS_OWNGRP(zace) \
40da6c28aaSamw 	((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
41da6c28aaSamw 
42da6c28aaSamw #define	ZACE_IS_USER(zace) \
43da6c28aaSamw 	(((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
44da6c28aaSamw #define	ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
45da6c28aaSamw #define	ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
46da6c28aaSamw 
47da6c28aaSamw #define	ZACE_IS_PROPAGATE(zace) \
48da6c28aaSamw 	((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
49da6c28aaSamw 
50da6c28aaSamw #define	ZACE_IS_CREATOR_OWNER(zace) \
51da6c28aaSamw 	(ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
52da6c28aaSamw 
53da6c28aaSamw #define	ZACE_IS_CREATOR_GROUP(zace) \
54da6c28aaSamw 	(ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
55da6c28aaSamw 
56da6c28aaSamw #define	ZACE_IS_CREATOR(zace) \
57da6c28aaSamw 	(ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
58da6c28aaSamw 
59da6c28aaSamw /*
60da6c28aaSamw  * ACE groups within a DACL
61da6c28aaSamw  *
62da6c28aaSamw  * This is from lower to higher ACE order priority
63da6c28aaSamw  */
64da6c28aaSamw #define	SMB_AG_START		0
65da6c28aaSamw #define	SMB_AG_ALW_INHRT	0
66da6c28aaSamw #define	SMB_AG_DNY_INHRT	1
67da6c28aaSamw #define	SMB_AG_ALW_DRCT		2
68da6c28aaSamw #define	SMB_AG_DNY_DRCT		3
69da6c28aaSamw #define	SMB_AG_NUM		4
70da6c28aaSamw 
7155bf511dSas200622 #define	DEFAULT_DACL_ACENUM	2
7255bf511dSas200622 /*
7355bf511dSas200622  * Default ACL:
7455bf511dSas200622  *    owner: full access
7555bf511dSas200622  *    SYSTEM: full access
7655bf511dSas200622  */
77*7206bf49SGordon Ross #ifdef	_KERNEL
78ae240eb8SGordon Ross static const ace_t const default_dacl[DEFAULT_DACL_ACENUM] = {
7955bf511dSas200622 	{ (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
8055bf511dSas200622 	{ IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
8155bf511dSas200622 	    ACE_ACCESS_ALLOWED_ACE_TYPE }
8255bf511dSas200622 };
83*7206bf49SGordon Ross #endif	/* _KERNEL */
8455bf511dSas200622 
8555bf511dSas200622 /*
8655bf511dSas200622  * Note:
87da6c28aaSamw  *
8855bf511dSas200622  * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
8955bf511dSas200622  * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
9055bf511dSas200622  * format
9155bf511dSas200622  */
9255bf511dSas200622 
93f96bd5c8SAlan Wright static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
94c8ec8eeaSjose borrego static acl_t *smb_fsacl_null_empty(boolean_t);
95*7206bf49SGordon Ross #ifdef	_KERNEL
9655bf511dSas200622 static int smb_fsacl_inheritable(acl_t *, int);
979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_ace_inherit(ace_t *, ace_t *, int, uid_t, gid_t);
98*7206bf49SGordon Ross #endif	/* _KERNEL */
99*7206bf49SGordon Ross 
10055bf511dSas200622 static boolean_t smb_ace_isvalid(smb_ace_t *, int);
10155bf511dSas200622 static uint16_t smb_ace_len(smb_ace_t *);
10255bf511dSas200622 static uint32_t smb_ace_mask_g2s(uint32_t);
103c8ec8eeaSjose borrego static uint16_t smb_ace_flags_tozfs(uint8_t);
10455bf511dSas200622 static uint8_t smb_ace_flags_fromzfs(uint16_t);
105f96bd5c8SAlan Wright static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
10655bf511dSas200622 
10755bf511dSas200622 smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)10855bf511dSas200622 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
10955bf511dSas200622 {
11055bf511dSas200622 	smb_acl_t *acl;
11155bf511dSas200622 	int size;
11255bf511dSas200622 
11355bf511dSas200622 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
11455bf511dSas200622 	acl = kmem_zalloc(size, KM_SLEEP);
11555bf511dSas200622 	acl->sl_revision = revision;
11655bf511dSas200622 	acl->sl_bsize = bsize;
11755bf511dSas200622 	acl->sl_acecnt = acecnt;
11855bf511dSas200622 	acl->sl_aces = (smb_ace_t *)(acl + 1);
11955bf511dSas200622 
12055bf511dSas200622 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
12155bf511dSas200622 	    offsetof(smb_ace_t, se_sln));
12255bf511dSas200622 	return (acl);
12355bf511dSas200622 }
12455bf511dSas200622 
12555bf511dSas200622 void
smb_acl_free(smb_acl_t * acl)12655bf511dSas200622 smb_acl_free(smb_acl_t *acl)
12755bf511dSas200622 {
12855bf511dSas200622 	int i, size;
12955bf511dSas200622 	void *ace;
13055bf511dSas200622 
13155bf511dSas200622 	if (acl == NULL)
13255bf511dSas200622 		return;
13355bf511dSas200622 
1346537f381Sas200622 	for (i = 0; i < acl->sl_acecnt; i++)
1356537f381Sas200622 		smb_sid_free(acl->sl_aces[i].se_sid);
13655bf511dSas200622 
13755bf511dSas200622 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
13855bf511dSas200622 		list_remove(&acl->sl_sorted, ace);
13955bf511dSas200622 	list_destroy(&acl->sl_sorted);
14055bf511dSas200622 
14155bf511dSas200622 	size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
14255bf511dSas200622 	kmem_free(acl, size);
14355bf511dSas200622 }
14455bf511dSas200622 
14555bf511dSas200622 /*
14655bf511dSas200622  * smb_acl_len
14755bf511dSas200622  *
14855bf511dSas200622  * Returns the size of given ACL in bytes. Note that this
14955bf511dSas200622  * is not an in-memory size, it's the ACL's size as it would
15055bf511dSas200622  * appear on the wire
15155bf511dSas200622  */
15255bf511dSas200622 uint16_t
smb_acl_len(smb_acl_t * acl)15355bf511dSas200622 smb_acl_len(smb_acl_t *acl)
15455bf511dSas200622 {
155c8ec8eeaSjose borrego 	return ((acl) ? acl->sl_bsize : 0);
15655bf511dSas200622 }
15755bf511dSas200622 
15855bf511dSas200622 boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)15955bf511dSas200622 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
16055bf511dSas200622 {
16155bf511dSas200622 	int i;
16255bf511dSas200622 
16355bf511dSas200622 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
16455bf511dSas200622 		return (B_FALSE);
16555bf511dSas200622 
16655bf511dSas200622 	if (acl->sl_revision != ACL_REVISION) {
16755bf511dSas200622 		/*
16855bf511dSas200622 		 * we are rejecting ACLs with object-specific ACEs for now
16955bf511dSas200622 		 */
17055bf511dSas200622 		return (B_FALSE);
17155bf511dSas200622 	}
17255bf511dSas200622 
17355bf511dSas200622 	for (i = 0; i < acl->sl_acecnt; i++) {
17455bf511dSas200622 		if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
17555bf511dSas200622 			return (B_FALSE);
17655bf511dSas200622 	}
17755bf511dSas200622 
17855bf511dSas200622 	return (B_TRUE);
17955bf511dSas200622 }
18055bf511dSas200622 
18155bf511dSas200622 /*
18255bf511dSas200622  * smb_acl_sort
18355bf511dSas200622  *
18455bf511dSas200622  * Sorts the given ACL in place if it needs to be sorted.
185da6c28aaSamw  *
186da6c28aaSamw  * The following is an excerpt from MSDN website.
187da6c28aaSamw  *
188da6c28aaSamw  * Order of ACEs in a DACL
189da6c28aaSamw  *
190da6c28aaSamw  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
191da6c28aaSamw  * is simple: In a DACL, all access-denied ACEs should precede any
192da6c28aaSamw  * access-allowed ACEs.
193da6c28aaSamw  *
194da6c28aaSamw  * For Windows 2000 or later, the proper order of ACEs is more complicated
195da6c28aaSamw  * because of the introduction of object-specific ACEs and automatic
196da6c28aaSamw  * inheritance.
197da6c28aaSamw  *
198da6c28aaSamw  * The following describes the preferred order:
199da6c28aaSamw  *
200da6c28aaSamw  * To ensure that noninherited ACEs have precedence over inherited ACEs,
201da6c28aaSamw  * place all noninherited ACEs in a group before any inherited ACEs. This
202da6c28aaSamw  * ordering ensures, for example, that a noninherited access-denied ACE
203da6c28aaSamw  * is enforced regardless of any inherited ACE that allows access.
204da6c28aaSamw  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
205da6c28aaSamw  * according to ACE type, as the following shows:
206da6c28aaSamw  * 	. Access-denied ACEs that apply to the object itself
207da6c28aaSamw  * 	. Access-denied ACEs that apply to a subobject of the
208da6c28aaSamw  *	  object, such as a property set or property
209da6c28aaSamw  * 	. Access-allowed ACEs that apply to the object itself
210da6c28aaSamw  * 	. Access-allowed ACEs that apply to a subobject of the object
211da6c28aaSamw  *
21255bf511dSas200622  * So, here is the desired ACE order
213da6c28aaSamw  *
214da6c28aaSamw  * deny-direct, allow-direct, deny-inherited, allow-inherited
215da6c28aaSamw  *
21655bf511dSas200622  * Of course, not all ACE types are required in an ACL.
217da6c28aaSamw  */
21855bf511dSas200622 void
smb_acl_sort(smb_acl_t * acl)219da6c28aaSamw smb_acl_sort(smb_acl_t *acl)
220da6c28aaSamw {
221da6c28aaSamw 	list_t ace_grps[SMB_AG_NUM];
22255bf511dSas200622 	list_t *alist;
22355bf511dSas200622 	smb_ace_t *ace;
224da6c28aaSamw 	uint8_t ace_flags;
22555bf511dSas200622 	int ag, i;
226da6c28aaSamw 
227da6c28aaSamw 	ASSERT(acl);
228da6c28aaSamw 
229da6c28aaSamw 	if (acl->sl_acecnt == 0) {
230da6c28aaSamw 		/*
231da6c28aaSamw 		 * ACL with no entry is a valid ACL and it means
232da6c28aaSamw 		 * no access for anybody.
233da6c28aaSamw 		 */
23455bf511dSas200622 		return;
235da6c28aaSamw 	}
236da6c28aaSamw 
237da6c28aaSamw 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
23855bf511dSas200622 		list_create(&ace_grps[i], sizeof (smb_ace_t),
23955bf511dSas200622 		    offsetof(smb_ace_t, se_sln));
240da6c28aaSamw 	}
241da6c28aaSamw 
24255bf511dSas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
24355bf511dSas200622 		ace_flags = ace->se_hdr.se_flags;
244da6c28aaSamw 
24555bf511dSas200622 		switch (ace->se_hdr.se_type) {
246da6c28aaSamw 		case ACCESS_DENIED_ACE_TYPE:
24755bf511dSas200622 			ag = (ace_flags & INHERITED_ACE) ?
24855bf511dSas200622 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
249da6c28aaSamw 			break;
250da6c28aaSamw 
251da6c28aaSamw 		case ACCESS_ALLOWED_ACE_TYPE:
25255bf511dSas200622 			ag = (ace_flags & INHERITED_ACE) ?
25355bf511dSas200622 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
254da6c28aaSamw 			break;
255da6c28aaSamw 
256da6c28aaSamw 		default:
257da6c28aaSamw 			/*
258da6c28aaSamw 			 * This is the lowest priority group so we put
259da6c28aaSamw 			 * evertything unknown here.
260da6c28aaSamw 			 */
261da6c28aaSamw 			ag = SMB_AG_ALW_INHRT;
262da6c28aaSamw 			break;
263da6c28aaSamw 		}
264da6c28aaSamw 
26555bf511dSas200622 		/* Add the ACE to the selected group */
26655bf511dSas200622 		list_insert_tail(&ace_grps[ag], ace);
267da6c28aaSamw 	}
268da6c28aaSamw 
26955bf511dSas200622 	/*
27055bf511dSas200622 	 * start with highest priority ACE group and append
27155bf511dSas200622 	 * the ACEs to the ACL.
27255bf511dSas200622 	 */
27355bf511dSas200622 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
27455bf511dSas200622 		alist = &ace_grps[i];
27555bf511dSas200622 		while ((ace = list_head(alist)) != NULL) {
27655bf511dSas200622 			list_remove(alist, ace);
27755bf511dSas200622 			list_insert_tail(&acl->sl_sorted, ace);
27855bf511dSas200622 		}
279da6c28aaSamw 		list_destroy(alist);
280da6c28aaSamw 	}
281da6c28aaSamw }
282da6c28aaSamw 
283da6c28aaSamw /*
28455bf511dSas200622  * smb_acl_from_zfs
285da6c28aaSamw  *
28655bf511dSas200622  * Converts given ZFS ACL to a Windows ACL.
287da6c28aaSamw  *
28855bf511dSas200622  * A pointer to allocated memory for the Win ACL will be
28955bf511dSas200622  * returned upon successful conversion.
290da6c28aaSamw  */
29155bf511dSas200622 smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)292f96bd5c8SAlan Wright smb_acl_from_zfs(acl_t *zacl)
293da6c28aaSamw {
29455bf511dSas200622 	ace_t *zace;
29555bf511dSas200622 	int numaces;
29655bf511dSas200622 	smb_acl_t *acl;
29755bf511dSas200622 	smb_ace_t *ace;
29855bf511dSas200622 	smb_idmap_batch_t sib;
29955bf511dSas200622 	smb_idmap_t *sim;
30055bf511dSas200622 	idmap_stat idm_stat;
301da6c28aaSamw 
30255bf511dSas200622 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
30355bf511dSas200622 	    SMB_IDMAP_ID2SID);
30455bf511dSas200622 	if (idm_stat != IDMAP_SUCCESS)
30555bf511dSas200622 		return (NULL);
30655bf511dSas200622 
307f96bd5c8SAlan Wright 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
30855bf511dSas200622 		smb_idmap_batch_destroy(&sib);
30955bf511dSas200622 		return (NULL);
31055bf511dSas200622 	}
31155bf511dSas200622 
31255bf511dSas200622 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
31355bf511dSas200622 
31455bf511dSas200622 	sim = sib.sib_maps;
31555bf511dSas200622 	for (numaces = 0, zace = zacl->acl_aclp;
31655bf511dSas200622 	    numaces < zacl->acl_cnt;
31755bf511dSas200622 	    zace++, numaces++, sim++) {
31855bf511dSas200622 		ASSERT(sim->sim_sid);
31955bf511dSas200622 		if (sim->sim_sid == NULL) {
32055bf511dSas200622 			smb_acl_free(acl);
32155bf511dSas200622 			acl = NULL;
32255bf511dSas200622 			break;
32355bf511dSas200622 		}
32455bf511dSas200622 
32555bf511dSas200622 		ace = &acl->sl_aces[numaces];
32655bf511dSas200622 		ace->se_hdr.se_type = zace->a_type;
32755bf511dSas200622 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
32855bf511dSas200622 		ace->se_mask = zace->a_access_mask;
3296537f381Sas200622 		ace->se_sid = smb_sid_dup(sim->sim_sid);
33055bf511dSas200622 		ace->se_hdr.se_bsize = smb_ace_len(ace);
33155bf511dSas200622 
33255bf511dSas200622 		acl->sl_bsize += ace->se_hdr.se_bsize;
33355bf511dSas200622 	}
33455bf511dSas200622 
33555bf511dSas200622 	smb_idmap_batch_destroy(&sib);
33655bf511dSas200622 	return (acl);
337da6c28aaSamw }
338da6c28aaSamw 
339da6c28aaSamw /*
34055bf511dSas200622  * smb_acl_to_zfs
341da6c28aaSamw  *
34255bf511dSas200622  * Converts given Windows ACL to a ZFS ACL.
34355bf511dSas200622  *
34455bf511dSas200622  * fs_acl will contain a pointer to the created ZFS ACL.
34555bf511dSas200622  * The allocated memory should be freed by calling
34655bf511dSas200622  * smb_fsacl_free().
34755bf511dSas200622  *
34855bf511dSas200622  * Since the output parameter, fs_acl, is allocated in this
34955bf511dSas200622  * function, the caller has to make sure *fs_acl is NULL which
35055bf511dSas200622  * means it's not pointing to any memory.
351da6c28aaSamw  */
352da6c28aaSamw uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)35355bf511dSas200622 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
354da6c28aaSamw {
35555bf511dSas200622 	smb_ace_t *ace;
35655bf511dSas200622 	acl_t *zacl;
35755bf511dSas200622 	ace_t *zace;
35855bf511dSas200622 	smb_idmap_batch_t sib;
35955bf511dSas200622 	smb_idmap_t *sim;
36055bf511dSas200622 	idmap_stat idm_stat;
361f96bd5c8SAlan Wright 	char *sidstr;
362c8ec8eeaSjose borrego 	int i;
363da6c28aaSamw 
36455bf511dSas200622 	ASSERT(fs_acl);
36555bf511dSas200622 	ASSERT(*fs_acl == NULL);
36655bf511dSas200622 
36755bf511dSas200622 	if (acl && !smb_acl_isvalid(acl, which_acl))
36855bf511dSas200622 		return (NT_STATUS_INVALID_ACL);
36955bf511dSas200622 
37055bf511dSas200622 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
37155bf511dSas200622 		if (which_acl == SMB_DACL_SECINFO) {
372c8ec8eeaSjose borrego 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
373da6c28aaSamw 		}
374da6c28aaSamw 
37555bf511dSas200622 		return (NT_STATUS_SUCCESS);
376da6c28aaSamw 	}
377da6c28aaSamw 
37855bf511dSas200622 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
37955bf511dSas200622 	    SMB_IDMAP_SID2ID);
38055bf511dSas200622 	if (idm_stat != IDMAP_SUCCESS)
38155bf511dSas200622 		return (NT_STATUS_INTERNAL_ERROR);
38255bf511dSas200622 
383f96bd5c8SAlan Wright 	sidstr = kmem_alloc(SMB_SID_STRSZ, KM_SLEEP);
38455bf511dSas200622 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
38555bf511dSas200622 
38655bf511dSas200622 	zace = zacl->acl_aclp;
38755bf511dSas200622 	ace = acl->sl_aces;
38855bf511dSas200622 	sim = sib.sib_maps;
38955bf511dSas200622 
39055bf511dSas200622 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
39155bf511dSas200622 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
39255bf511dSas200622 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
393c8ec8eeaSjose borrego 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
394f96bd5c8SAlan Wright 		zace->a_who = (uid_t)-1;
39555bf511dSas200622 
396f96bd5c8SAlan Wright 		smb_sid_tostr(ace->se_sid, sidstr);
397f96bd5c8SAlan Wright 
398f96bd5c8SAlan Wright 		if (!smb_ace_wellknown_update(sidstr, zace)) {
39955bf511dSas200622 			sim->sim_id = &zace->a_who;
40055bf511dSas200622 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
401f96bd5c8SAlan Wright 			    ace->se_sid, SMB_IDMAP_UNKNOWN);
40255bf511dSas200622 
40355bf511dSas200622 			if (idm_stat != IDMAP_SUCCESS) {
404f96bd5c8SAlan Wright 				kmem_free(sidstr, SMB_SID_STRSZ);
40555bf511dSas200622 				smb_fsacl_free(zacl);
40655bf511dSas200622 				smb_idmap_batch_destroy(&sib);
40755bf511dSas200622 				return (NT_STATUS_INTERNAL_ERROR);
40855bf511dSas200622 			}
40955bf511dSas200622 		}
410da6c28aaSamw 	}
411da6c28aaSamw 
412f96bd5c8SAlan Wright 	kmem_free(sidstr, SMB_SID_STRSZ);
413f96bd5c8SAlan Wright 
41455bf511dSas200622 	idm_stat = smb_idmap_batch_getmappings(&sib);
41555bf511dSas200622 	if (idm_stat != IDMAP_SUCCESS) {
41655bf511dSas200622 		smb_fsacl_free(zacl);
41755bf511dSas200622 		smb_idmap_batch_destroy(&sib);
41855bf511dSas200622 		return (NT_STATUS_NONE_MAPPED);
419da6c28aaSamw 	}
420da6c28aaSamw 
42155bf511dSas200622 	/*
42255bf511dSas200622 	 * Set the ACEs group flag based on the type of ID returned.
42355bf511dSas200622 	 */
42455bf511dSas200622 	zace = zacl->acl_aclp;
42555bf511dSas200622 	ace = acl->sl_aces;
42655bf511dSas200622 	sim = sib.sib_maps;
42755bf511dSas200622 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
428f96bd5c8SAlan Wright 		if (zace->a_who == (uid_t)-1)
42955bf511dSas200622 			continue;
43055bf511dSas200622 
43155bf511dSas200622 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
43255bf511dSas200622 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
43355bf511dSas200622 	}
43455bf511dSas200622 
43555bf511dSas200622 	smb_idmap_batch_destroy(&sib);
43655bf511dSas200622 
43755bf511dSas200622 	*fs_acl = zacl;
43855bf511dSas200622 	return (NT_STATUS_SUCCESS);
439da6c28aaSamw }
440da6c28aaSamw 
441f96bd5c8SAlan Wright static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)442f96bd5c8SAlan Wright smb_ace_wellknown_update(const char *sid, ace_t *zace)
443f96bd5c8SAlan Wright {
444f96bd5c8SAlan Wright 	struct {
445f96bd5c8SAlan Wright 		char		*sid;
446f96bd5c8SAlan Wright 		uint16_t	flags;
447f96bd5c8SAlan Wright 	} map[] = {
448f96bd5c8SAlan Wright 		{ NT_WORLD_SIDSTR,			ACE_EVERYONE },
449f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_OWNER_SIDSTR,	ACE_OWNER },
450f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_GROUP_SIDSTR,
451f96bd5c8SAlan Wright 			(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
452f96bd5c8SAlan Wright 	};
453f96bd5c8SAlan Wright 
454f96bd5c8SAlan Wright 	int	i;
455f96bd5c8SAlan Wright 
456f96bd5c8SAlan Wright 	for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
457f96bd5c8SAlan Wright 		if (strcmp(sid, map[i].sid) == 0) {
458f96bd5c8SAlan Wright 			zace->a_flags |= map[i].flags;
459f96bd5c8SAlan Wright 			return (B_TRUE);
460f96bd5c8SAlan Wright 		}
461f96bd5c8SAlan Wright 	}
462f96bd5c8SAlan Wright 
463f96bd5c8SAlan Wright 	return (B_FALSE);
464f96bd5c8SAlan Wright }
465f96bd5c8SAlan Wright 
466da6c28aaSamw /*
467c8ec8eeaSjose borrego  * smb_fsacl_getsids
468da6c28aaSamw  *
469da6c28aaSamw  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
470da6c28aaSamw  */
471da6c28aaSamw static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)472f96bd5c8SAlan Wright smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
473da6c28aaSamw {
474da6c28aaSamw 	ace_t *zace;
475da6c28aaSamw 	idmap_stat idm_stat;
476da6c28aaSamw 	smb_idmap_t *sim;
477*7206bf49SGordon Ross 	uid_t id = (uid_t)-1;
478da6c28aaSamw 	int i, idtype;
479da6c28aaSamw 
480da6c28aaSamw 	sim = sib->sib_maps;
481da6c28aaSamw 
482da6c28aaSamw 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
483da6c28aaSamw 	    zace++, i++, sim++) {
484da6c28aaSamw 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
485da6c28aaSamw 		case ACE_OWNER:
486f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_OWNERAT;
487da6c28aaSamw 			break;
488da6c28aaSamw 
489da6c28aaSamw 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
490da6c28aaSamw 			/* owning group */
491f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_GROUPAT;
492da6c28aaSamw 			break;
493da6c28aaSamw 
494da6c28aaSamw 		case ACE_IDENTIFIER_GROUP:
495da6c28aaSamw 			/* regular group */
496da6c28aaSamw 			id = zace->a_who;
497da6c28aaSamw 			idtype = SMB_IDMAP_GROUP;
498da6c28aaSamw 			break;
499da6c28aaSamw 
500da6c28aaSamw 		case ACE_EVERYONE:
501da6c28aaSamw 			idtype = SMB_IDMAP_EVERYONE;
502da6c28aaSamw 			break;
503da6c28aaSamw 
504da6c28aaSamw 		default:
505da6c28aaSamw 			/* user entry */
506da6c28aaSamw 			id = zace->a_who;
507da6c28aaSamw 			idtype = SMB_IDMAP_USER;
508da6c28aaSamw 		}
509da6c28aaSamw 
510da6c28aaSamw 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
511da6c28aaSamw 		    id, idtype);
512da6c28aaSamw 
513da6c28aaSamw 		if (idm_stat != IDMAP_SUCCESS) {
514da6c28aaSamw 			return (idm_stat);
515da6c28aaSamw 		}
516da6c28aaSamw 	}
517da6c28aaSamw 
518da6c28aaSamw 	idm_stat = smb_idmap_batch_getmappings(sib);
519da6c28aaSamw 	return (idm_stat);
520da6c28aaSamw }
521da6c28aaSamw 
522da6c28aaSamw /*
523c8ec8eeaSjose borrego  * smb_fsacl_null_empty
524da6c28aaSamw  *
525da6c28aaSamw  * NULL DACL means everyone full-access
526da6c28aaSamw  * Empty DACL means everyone full-deny
527da6c28aaSamw  *
528da6c28aaSamw  * ZFS ACL must have at least one entry so smb server has
529da6c28aaSamw  * to simulate the aforementioned expected behavior by adding
530da6c28aaSamw  * an entry in case the requested DACL is null or empty. Adding
531da6c28aaSamw  * a everyone full-deny entry has proved to be problematic in
532da6c28aaSamw  * tests since a deny entry takes precedence over allow entries.
533da6c28aaSamw  * So, instead of adding a everyone full-deny, an owner ACE with
534da6c28aaSamw  * owner implicit permissions will be set.
535da6c28aaSamw  */
53655bf511dSas200622 static acl_t *
smb_fsacl_null_empty(boolean_t null)537c8ec8eeaSjose borrego smb_fsacl_null_empty(boolean_t null)
538da6c28aaSamw {
539da6c28aaSamw 	acl_t *zacl;
540da6c28aaSamw 	ace_t *zace;
541da6c28aaSamw 
54255bf511dSas200622 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
543da6c28aaSamw 	zace = zacl->acl_aclp;
544da6c28aaSamw 
545da6c28aaSamw 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
546da6c28aaSamw 	if (null) {
547da6c28aaSamw 		zace->a_access_mask = ACE_ALL_PERMS;
548da6c28aaSamw 		zace->a_flags = ACE_EVERYONE;
549da6c28aaSamw 	} else {
550da6c28aaSamw 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
551da6c28aaSamw 		    ACE_READ_ATTRIBUTES;
552da6c28aaSamw 		zace->a_flags = ACE_OWNER;
553da6c28aaSamw 	}
554da6c28aaSamw 
555da6c28aaSamw 	return (zacl);
556da6c28aaSamw }
557da6c28aaSamw 
558da6c28aaSamw /*
55955bf511dSas200622  * FS ACL (acl_t) Functions
560da6c28aaSamw  */
56155bf511dSas200622 acl_t *
smb_fsacl_alloc(int acenum,int flags)56255bf511dSas200622 smb_fsacl_alloc(int acenum, int flags)
563da6c28aaSamw {
56455bf511dSas200622 	acl_t *acl;
565da6c28aaSamw 
56655bf511dSas200622 	acl = acl_alloc(ACE_T);
56755bf511dSas200622 	acl->acl_cnt = acenum;
56855bf511dSas200622 	acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
56955bf511dSas200622 	acl->acl_flags = flags;
57055bf511dSas200622 	return (acl);
571da6c28aaSamw }
572da6c28aaSamw 
57355bf511dSas200622 void
smb_fsacl_free(acl_t * acl)57455bf511dSas200622 smb_fsacl_free(acl_t *acl)
575da6c28aaSamw {
57655bf511dSas200622 	if (acl)
57755bf511dSas200622 		acl_free(acl);
578da6c28aaSamw }
579da6c28aaSamw 
580da6c28aaSamw /*
58155bf511dSas200622  * smb_fsop_aclmerge
582da6c28aaSamw  *
58355bf511dSas200622  * smb_fsop_aclread/write routines which interact with filesystem
58455bf511dSas200622  * work with single ACL. This routine merges given DACL and SACL
58555bf511dSas200622  * which might have been created during CIFS to FS conversion into
58655bf511dSas200622  * one single ACL.
58755bf511dSas200622  */
58855bf511dSas200622 acl_t *
smb_fsacl_merge(acl_t * dacl,acl_t * sacl)58955bf511dSas200622 smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
59055bf511dSas200622 {
59155bf511dSas200622 	acl_t *acl;
59255bf511dSas200622 	int dacl_size;
59355bf511dSas200622 
59455bf511dSas200622 	ASSERT(dacl);
59555bf511dSas200622 	ASSERT(sacl);
59655bf511dSas200622 
59755bf511dSas200622 	acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
59855bf511dSas200622 	dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
59955bf511dSas200622 	bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
60055bf511dSas200622 	bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
60155bf511dSas200622 	    sacl->acl_cnt * sacl->acl_entry_size);
60255bf511dSas200622 
60355bf511dSas200622 	return (acl);
60455bf511dSas200622 }
60555bf511dSas200622 
60655bf511dSas200622 /*
60755bf511dSas200622  * smb_fsacl_split
60855bf511dSas200622  *
60955bf511dSas200622  * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
61055bf511dSas200622  * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
61155bf511dSas200622  * NULL even if they're specified in 'which_acl', which means the target
61255bf511dSas200622  * doesn't have any access and/or audit ACEs.
61355bf511dSas200622  */
61455bf511dSas200622 void
smb_fsacl_split(acl_t * zacl,acl_t ** dacl,acl_t ** sacl,int which_acl)61555bf511dSas200622 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
61655bf511dSas200622 {
61755bf511dSas200622 	ace_t *zace;
618*7206bf49SGordon Ross 	ace_t *access_ace = NULL;
619*7206bf49SGordon Ross 	ace_t *audit_ace = NULL;
62055bf511dSas200622 	int naccess, naudit;
62155bf511dSas200622 	int get_dacl, get_sacl;
62255bf511dSas200622 	int i;
62355bf511dSas200622 
62455bf511dSas200622 	*dacl = *sacl = NULL;
62555bf511dSas200622 	naccess = naudit = 0;
62655bf511dSas200622 	get_dacl = (which_acl & SMB_DACL_SECINFO);
62755bf511dSas200622 	get_sacl = (which_acl & SMB_SACL_SECINFO);
62855bf511dSas200622 
62955bf511dSas200622 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
63055bf511dSas200622 		if (get_dacl && smb_ace_is_access(zace->a_type))
63155bf511dSas200622 			naccess++;
63255bf511dSas200622 		else if (get_sacl && smb_ace_is_audit(zace->a_type))
63355bf511dSas200622 			naudit++;
63455bf511dSas200622 	}
63555bf511dSas200622 
63655bf511dSas200622 	if (naccess) {
63755bf511dSas200622 		*dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
63855bf511dSas200622 		access_ace = (*dacl)->acl_aclp;
63955bf511dSas200622 	}
64055bf511dSas200622 
64155bf511dSas200622 	if (naudit) {
64255bf511dSas200622 		*sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
64355bf511dSas200622 		audit_ace = (*sacl)->acl_aclp;
64455bf511dSas200622 	}
64555bf511dSas200622 
64655bf511dSas200622 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
64755bf511dSas200622 		if (get_dacl && smb_ace_is_access(zace->a_type)) {
64855bf511dSas200622 			*access_ace = *zace;
64955bf511dSas200622 			access_ace++;
65055bf511dSas200622 		} else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
65155bf511dSas200622 			*audit_ace = *zace;
65255bf511dSas200622 			audit_ace++;
65355bf511dSas200622 		}
65455bf511dSas200622 	}
65555bf511dSas200622 }
65655bf511dSas200622 
65755bf511dSas200622 /*
65855bf511dSas200622  * ACE Inheritance Rules
65955bf511dSas200622  *
66055bf511dSas200622  * The system propagates inheritable ACEs to child objects according to a
66155bf511dSas200622  * set of inheritance rules. The system places inherited ACEs in the child's
66255bf511dSas200622  * DACL according to the preferred order of ACEs in a DACL. For Windows
66355bf511dSas200622  * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
66455bf511dSas200622  *
66555bf511dSas200622  * The following table shows the ACEs inherited by container and noncontainer
66655bf511dSas200622  * child objects for different combinations of inheritance flags. These
66755bf511dSas200622  * inheritance rules work the same for both DACLs and SACLs.
66855bf511dSas200622  *
66955bf511dSas200622  * Parent ACE type 			Effect on Child ACL
67055bf511dSas200622  * -----------------------		-------------------
67155bf511dSas200622  * OBJECT_INHERIT_ACE only 		Noncontainer child objects:
67255bf511dSas200622  *					Inherited as an effective ACE.
67355bf511dSas200622  *					Container child objects:
67455bf511dSas200622  *					Containers inherit an inherit-only ACE
67555bf511dSas200622  *					unless the NO_PROPAGATE_INHERIT_ACE bit
676da6c28aaSamw  *					flag is also set.
677da6c28aaSamw  *
67855bf511dSas200622  * CONTAINER_INHERIT_ACE only 		Noncontainer child objects:
67955bf511dSas200622  *					No effect on the child object.
68055bf511dSas200622  *					Container child objects:
68155bf511dSas200622  *				The child object inherits an effective ACE.
682da6c28aaSamw  *				The inherited ACE is inheritable unless the
68355bf511dSas200622  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set.
68455bf511dSas200622  *
68555bf511dSas200622  * CONTAINER_INHERIT_ACE and
68655bf511dSas200622  * OBJECT_INHERIT_ACE 			Noncontainer child objects:
68755bf511dSas200622  *					Inherited as an effective ACE.
68855bf511dSas200622  *					Container child objects:
68955bf511dSas200622  *				The child object inherits an effective ACE.
69055bf511dSas200622  *				The inherited ACE is inheritable unless the
69155bf511dSas200622  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set
69255bf511dSas200622  *
69355bf511dSas200622  * No inheritance flags set 	No effect on child container or noncontainer
69455bf511dSas200622  *				objects.
69555bf511dSas200622  *
69655bf511dSas200622  * If an inherited ACE is an effective ACE for the child object, the system
69755bf511dSas200622  * maps any generic rights to the specific rights for the child object.
69855bf511dSas200622  * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
69955bf511dSas200622  * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
70055bf511dSas200622  * rights or generic SIDs are left unchanged so that they can be mapped
70155bf511dSas200622  * appropriately when the ACE is inherited by the next generation of child
70255bf511dSas200622  * objects.
70355bf511dSas200622  *
70455bf511dSas200622  * For a case in which a container object inherits an ACE that is both
70555bf511dSas200622  * effective on the container and inheritable by its descendants, the
70655bf511dSas200622  * container may inherit two ACEs. This occurs if the inheritable ACE
70755bf511dSas200622  * contains generic information. The container inherits an inherit-only
70855bf511dSas200622  * ACE containing the generic information and an effective-only ACE in
70955bf511dSas200622  * which the generic information has been mapped.
710da6c28aaSamw  */
711da6c28aaSamw 
712*7206bf49SGordon Ross #ifdef	_KERNEL
713da6c28aaSamw /*
71455bf511dSas200622  * smb_fsacl_inherit
715da6c28aaSamw  *
716da6c28aaSamw  * Manufacture the inherited ACL from the given ACL considering
717da6c28aaSamw  * the new object type (file/dir) specified by 'is_dir'. The
718da6c28aaSamw  * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
71955bf511dSas200622  * This function implements Windows inheritance rules explained above.
720da6c28aaSamw  *
72155bf511dSas200622  * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
722da6c28aaSamw  */
723da6c28aaSamw acl_t *
smb_fsacl_inherit(acl_t * dir_zacl,int is_dir,int which_acl,cred_t * cr)7249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, cred_t *cr)
725da6c28aaSamw {
726da6c28aaSamw 	boolean_t use_default = B_FALSE;
727da6c28aaSamw 	int num_inheritable = 0;
728da6c28aaSamw 	int numaces;
729da6c28aaSamw 	ace_t *dir_zace;
730da6c28aaSamw 	acl_t *new_zacl;
731da6c28aaSamw 	ace_t *new_zace;
7329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ksid_t *owner_sid;
7339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ksid_t *group_sid;
7349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uid_t uid;
7359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	gid_t gid;
7369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	owner_sid = crgetsid(cr, KSID_OWNER);
7389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	group_sid = crgetsid(cr, KSID_GROUP);
7399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(owner_sid);
7409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(group_sid);
7419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uid = owner_sid->ks_id;
7429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	gid = group_sid->ks_id;
743da6c28aaSamw 
74455bf511dSas200622 	num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
745da6c28aaSamw 
746da6c28aaSamw 	if (num_inheritable == 0) {
747da6c28aaSamw 		if (which_acl == SMB_DACL_SECINFO) {
748da6c28aaSamw 			/* No inheritable access ACEs -> default DACL */
749da6c28aaSamw 			num_inheritable = DEFAULT_DACL_ACENUM;
750da6c28aaSamw 			use_default = B_TRUE;
751da6c28aaSamw 		} else {
752da6c28aaSamw 			return (NULL);
753da6c28aaSamw 		}
754da6c28aaSamw 	}
755da6c28aaSamw 
75655bf511dSas200622 	new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
757da6c28aaSamw 	new_zace = new_zacl->acl_aclp;
758da6c28aaSamw 
759da6c28aaSamw 	if (use_default) {
760da6c28aaSamw 		bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
7619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		new_zace->a_who = uid;
762da6c28aaSamw 		return (new_zacl);
763da6c28aaSamw 	}
764da6c28aaSamw 
765da6c28aaSamw 	for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
766da6c28aaSamw 	    numaces < dir_zacl->acl_cnt;
767da6c28aaSamw 	    dir_zace++, numaces++) {
768da6c28aaSamw 		switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
769da6c28aaSamw 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
770da6c28aaSamw 			/*
771da6c28aaSamw 			 * Files inherit an effective ACE.
772da6c28aaSamw 			 *
773da6c28aaSamw 			 * Dirs inherit an effective ACE.
774da6c28aaSamw 			 * The inherited ACE is inheritable unless the
775da6c28aaSamw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
776da6c28aaSamw 			 */
7779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
778da6c28aaSamw 			new_zace++;
779da6c28aaSamw 
780da6c28aaSamw 			if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
781da6c28aaSamw 			    (ZACE_IS_PROPAGATE(dir_zace))) {
782da6c28aaSamw 				*new_zace = *dir_zace;
783da6c28aaSamw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
784da6c28aaSamw 				    ACE_INHERITED_ACE);
785da6c28aaSamw 				new_zace++;
786da6c28aaSamw 			}
787da6c28aaSamw 			break;
788da6c28aaSamw 
789da6c28aaSamw 		case ACE_FILE_INHERIT_ACE:
790da6c28aaSamw 			/*
791da6c28aaSamw 			 * Files inherit as an effective ACE.
792da6c28aaSamw 			 *
793da6c28aaSamw 			 * Dirs inherit an inherit-only ACE
794da6c28aaSamw 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
795da6c28aaSamw 			 * flag is also set.
796da6c28aaSamw 			 */
797da6c28aaSamw 			if (is_dir == 0) {
7989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				smb_ace_inherit(dir_zace, new_zace, is_dir,
7999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				    uid, gid);
800da6c28aaSamw 				new_zace++;
801da6c28aaSamw 			} else if (ZACE_IS_PROPAGATE(dir_zace)) {
802da6c28aaSamw 				*new_zace = *dir_zace;
803da6c28aaSamw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
804da6c28aaSamw 				    ACE_INHERITED_ACE);
805da6c28aaSamw 				new_zace++;
806da6c28aaSamw 			}
807da6c28aaSamw 			break;
808da6c28aaSamw 
809da6c28aaSamw 		case ACE_DIRECTORY_INHERIT_ACE:
810da6c28aaSamw 			/*
811da6c28aaSamw 			 * No effect on files
812da6c28aaSamw 			 *
813da6c28aaSamw 			 * Dirs inherit an effective ACE.
814da6c28aaSamw 			 * The inherited ACE is inheritable unless the
815da6c28aaSamw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
816da6c28aaSamw 			 */
817da6c28aaSamw 			if (is_dir == 0)
818da6c28aaSamw 				break;
819da6c28aaSamw 
8209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
821da6c28aaSamw 			new_zace++;
822da6c28aaSamw 
823da6c28aaSamw 			if (ZACE_IS_CREATOR(dir_zace) &&
824da6c28aaSamw 			    (ZACE_IS_PROPAGATE(dir_zace))) {
825da6c28aaSamw 				*new_zace = *dir_zace;
826da6c28aaSamw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
827da6c28aaSamw 				    ACE_INHERITED_ACE);
828da6c28aaSamw 				new_zace++;
829da6c28aaSamw 			}
830da6c28aaSamw 
831da6c28aaSamw 			break;
832da6c28aaSamw 
833da6c28aaSamw 		default:
834da6c28aaSamw 			break;
835da6c28aaSamw 		}
836da6c28aaSamw 	}
837da6c28aaSamw 
838da6c28aaSamw 	return (new_zacl);
839da6c28aaSamw }
840*7206bf49SGordon Ross #endif	/* _KERNEL */
841da6c28aaSamw 
84255bf511dSas200622 /*
84355bf511dSas200622  * smb_fsacl_from_vsa
84455bf511dSas200622  *
84555bf511dSas200622  * Converts given vsecattr_t structure to a acl_t structure.
84655bf511dSas200622  *
84755bf511dSas200622  * The allocated memory for retuned acl_t should be freed by
84855bf511dSas200622  * calling acl_free().
84955bf511dSas200622  */
85055bf511dSas200622 acl_t *
smb_fsacl_from_vsa(vsecattr_t * vsecattr,acl_type_t acl_type)85155bf511dSas200622 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
85255bf511dSas200622 {
85355bf511dSas200622 	int		aclbsize = 0;	/* size of acl list in bytes */
85455bf511dSas200622 	int		dfaclbsize = 0;	/* size of default acl list in bytes */
85555bf511dSas200622 	int		numacls;
85655bf511dSas200622 	acl_t		*acl_info;
85755bf511dSas200622 
85855bf511dSas200622 	ASSERT(vsecattr);
85955bf511dSas200622 
86055bf511dSas200622 	acl_info = acl_alloc(acl_type);
86155bf511dSas200622 	if (acl_info == NULL)
86255bf511dSas200622 		return (NULL);
86355bf511dSas200622 
86455bf511dSas200622 	acl_info->acl_flags = 0;
86555bf511dSas200622 
86655bf511dSas200622 	switch (acl_type) {
86755bf511dSas200622 
86855bf511dSas200622 	case ACLENT_T:
86955bf511dSas200622 		numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
87055bf511dSas200622 		aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
87155bf511dSas200622 		dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
87255bf511dSas200622 
87355bf511dSas200622 		acl_info->acl_cnt = numacls;
87455bf511dSas200622 		acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
87555bf511dSas200622 		    KM_SLEEP);
87655bf511dSas200622 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
87755bf511dSas200622 		    aclbsize);
87855bf511dSas200622 		(void) memcpy((char *)acl_info->acl_aclp + aclbsize,
87955bf511dSas200622 		    vsecattr->vsa_dfaclentp, dfaclbsize);
88055bf511dSas200622 
88155bf511dSas200622 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
88255bf511dSas200622 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
88355bf511dSas200622 
88455bf511dSas200622 		break;
88555bf511dSas200622 
88655bf511dSas200622 	case ACE_T:
88755bf511dSas200622 		aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
88855bf511dSas200622 		acl_info->acl_cnt = vsecattr->vsa_aclcnt;
88955bf511dSas200622 		acl_info->acl_flags = vsecattr->vsa_aclflags;
89055bf511dSas200622 		acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
89155bf511dSas200622 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
89255bf511dSas200622 		    aclbsize);
89355bf511dSas200622 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
89455bf511dSas200622 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
89555bf511dSas200622 
89655bf511dSas200622 		break;
89755bf511dSas200622 
89855bf511dSas200622 	default:
89955bf511dSas200622 		acl_free(acl_info);
90055bf511dSas200622 		return (NULL);
90155bf511dSas200622 	}
90255bf511dSas200622 
90355bf511dSas200622 	if (aclbsize && vsecattr->vsa_aclentp)
90455bf511dSas200622 		kmem_free(vsecattr->vsa_aclentp, aclbsize);
90555bf511dSas200622 	if (dfaclbsize && vsecattr->vsa_dfaclentp)
90655bf511dSas200622 		kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
90755bf511dSas200622 
90855bf511dSas200622 	return (acl_info);
90955bf511dSas200622 }
91055bf511dSas200622 
91155bf511dSas200622 /*
91255bf511dSas200622  * smb_fsacl_to_vsa
91355bf511dSas200622  *
91455bf511dSas200622  * Converts given acl_t structure to a vsecattr_t structure.
91555bf511dSas200622  *
91655bf511dSas200622  * IMPORTANT:
91755bf511dSas200622  * Upon successful return the memory allocated for vsa_aclentp
91855bf511dSas200622  * should be freed by calling kmem_free(). The size is returned
91955bf511dSas200622  * in aclbsize.
92055bf511dSas200622  */
92155bf511dSas200622 int
smb_fsacl_to_vsa(acl_t * acl_info,vsecattr_t * vsecattr,int * aclbsize)92255bf511dSas200622 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
92355bf511dSas200622 {
92455bf511dSas200622 	int		error = 0;
92555bf511dSas200622 	int		numacls;
92655bf511dSas200622 	aclent_t	*aclp;
92755bf511dSas200622 
92855bf511dSas200622 	ASSERT(acl_info);
92955bf511dSas200622 	ASSERT(vsecattr);
93055bf511dSas200622 	ASSERT(aclbsize);
93155bf511dSas200622 
93255bf511dSas200622 	bzero(vsecattr, sizeof (vsecattr_t));
93355bf511dSas200622 	*aclbsize = 0;
93455bf511dSas200622 
93555bf511dSas200622 	switch (acl_info->acl_type) {
93655bf511dSas200622 	case ACLENT_T:
93755bf511dSas200622 		numacls = acl_info->acl_cnt;
93855bf511dSas200622 		/*
93955bf511dSas200622 		 * Minimum ACL size is three entries so might as well
94055bf511dSas200622 		 * bail out here.  Also limit request size to prevent user
94155bf511dSas200622 		 * from allocating too much kernel memory.  Maximum size
94255bf511dSas200622 		 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
94355bf511dSas200622 		 * for the default ACL part.
94455bf511dSas200622 		 */
94555bf511dSas200622 		if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
94655bf511dSas200622 			error = EINVAL;
94755bf511dSas200622 			break;
94855bf511dSas200622 		}
94955bf511dSas200622 
95055bf511dSas200622 		vsecattr->vsa_mask = VSA_ACL;
95155bf511dSas200622 
95255bf511dSas200622 		vsecattr->vsa_aclcnt = numacls;
95355bf511dSas200622 		*aclbsize = numacls * sizeof (aclent_t);
95455bf511dSas200622 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
95555bf511dSas200622 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
95655bf511dSas200622 		    *aclbsize);
95755bf511dSas200622 
95855bf511dSas200622 		/* Sort the acl list */
95955bf511dSas200622 		ksort((caddr_t)vsecattr->vsa_aclentp,
96055bf511dSas200622 		    vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
96155bf511dSas200622 
96255bf511dSas200622 		/* Break into acl and default acl lists */
96355bf511dSas200622 		for (numacls = 0, aclp = vsecattr->vsa_aclentp;
96455bf511dSas200622 		    numacls < vsecattr->vsa_aclcnt;
96555bf511dSas200622 		    aclp++, numacls++) {
96655bf511dSas200622 			if (aclp->a_type & ACL_DEFAULT)
96755bf511dSas200622 				break;
96855bf511dSas200622 		}
96955bf511dSas200622 
97055bf511dSas200622 		/* Find where defaults start (if any) */
97155bf511dSas200622 		if (numacls < vsecattr->vsa_aclcnt) {
97255bf511dSas200622 			vsecattr->vsa_mask |= VSA_DFACL;
97355bf511dSas200622 			vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
97455bf511dSas200622 			vsecattr->vsa_dfaclentp = aclp;
97555bf511dSas200622 			vsecattr->vsa_aclcnt = numacls;
97655bf511dSas200622 		}
97755bf511dSas200622 
97855bf511dSas200622 		/* Adjust if they're all defaults */
97955bf511dSas200622 		if (vsecattr->vsa_aclcnt == 0) {
98055bf511dSas200622 			vsecattr->vsa_mask &= ~VSA_ACL;
98155bf511dSas200622 			vsecattr->vsa_aclentp = NULL;
98255bf511dSas200622 		}
98355bf511dSas200622 
98455bf511dSas200622 		/* Only directories can have defaults */
98555bf511dSas200622 		if (vsecattr->vsa_dfaclcnt &&
98655bf511dSas200622 		    (acl_info->acl_flags & ACL_IS_DIR)) {
98755bf511dSas200622 			error = ENOTDIR;
98855bf511dSas200622 		}
98955bf511dSas200622 
99055bf511dSas200622 		break;
99155bf511dSas200622 
99255bf511dSas200622 	case ACE_T:
99355bf511dSas200622 		if (acl_info->acl_cnt < 1 ||
99455bf511dSas200622 		    acl_info->acl_cnt > MAX_ACL_ENTRIES) {
99555bf511dSas200622 			error = EINVAL;
99655bf511dSas200622 			break;
99755bf511dSas200622 		}
99855bf511dSas200622 
99955bf511dSas200622 		vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
100055bf511dSas200622 		vsecattr->vsa_aclcnt = acl_info->acl_cnt;
100155bf511dSas200622 		vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
100255bf511dSas200622 		*aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
100355bf511dSas200622 		vsecattr->vsa_aclentsz = *aclbsize;
100455bf511dSas200622 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
100555bf511dSas200622 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
100655bf511dSas200622 		    *aclbsize);
100755bf511dSas200622 
100855bf511dSas200622 		break;
100955bf511dSas200622 
101055bf511dSas200622 	default:
101155bf511dSas200622 		error = EINVAL;
101255bf511dSas200622 	}
101355bf511dSas200622 
101455bf511dSas200622 	return (error);
101555bf511dSas200622 }
101655bf511dSas200622 
1017*7206bf49SGordon Ross #ifdef	_KERNEL
101855bf511dSas200622 /*
101955bf511dSas200622  * smb_fsacl_inheritable
102055bf511dSas200622  *
102155bf511dSas200622  * Checks to see if there are any inheritable ACEs in the
102255bf511dSas200622  * given ZFS ACL. Returns the number of inheritable ACEs.
102355bf511dSas200622  *
102455bf511dSas200622  * The inherited ACL could be different based on the type of
102555bf511dSas200622  * new object (file/dir) specified by 'is_dir'.
102655bf511dSas200622  *
102755bf511dSas200622  * Note that the input ACL is a ZFS ACL not Windows ACL.
102855bf511dSas200622  */
102955bf511dSas200622 static int
smb_fsacl_inheritable(acl_t * zacl,int is_dir)103055bf511dSas200622 smb_fsacl_inheritable(acl_t *zacl, int is_dir)
103155bf511dSas200622 {
103255bf511dSas200622 	int numaces;
103355bf511dSas200622 	int num_inheritable = 0;
103455bf511dSas200622 	ace_t *zace;
103555bf511dSas200622 
103655bf511dSas200622 	if (zacl == NULL)
103755bf511dSas200622 		return (0);
103855bf511dSas200622 
103955bf511dSas200622 	for (numaces = 0, zace = zacl->acl_aclp;
104055bf511dSas200622 	    numaces < zacl->acl_cnt;
104155bf511dSas200622 	    zace++, numaces++) {
104255bf511dSas200622 		switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
104355bf511dSas200622 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
104455bf511dSas200622 			/*
104555bf511dSas200622 			 * Files inherit an effective ACE.
104655bf511dSas200622 			 *
104755bf511dSas200622 			 * Dirs inherit an effective ACE.
104855bf511dSas200622 			 * The inherited ACE is inheritable unless the
104955bf511dSas200622 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
105055bf511dSas200622 			 */
105155bf511dSas200622 			num_inheritable++;
105255bf511dSas200622 
105355bf511dSas200622 			if (is_dir && ZACE_IS_CREATOR(zace) &&
105455bf511dSas200622 			    (ZACE_IS_PROPAGATE(zace))) {
105555bf511dSas200622 				num_inheritable++;
105655bf511dSas200622 			}
105755bf511dSas200622 			break;
105855bf511dSas200622 
105955bf511dSas200622 		case ACE_FILE_INHERIT_ACE:
106055bf511dSas200622 			/*
106155bf511dSas200622 			 * Files inherit as an effective ACE.
106255bf511dSas200622 			 *
106355bf511dSas200622 			 * Dirs inherit an inherit-only ACE
106455bf511dSas200622 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
106555bf511dSas200622 			 * flag is also set.
106655bf511dSas200622 			 */
106755bf511dSas200622 			if (is_dir == 0)
106855bf511dSas200622 				num_inheritable++;
106955bf511dSas200622 			else if (ZACE_IS_PROPAGATE(zace))
107055bf511dSas200622 				num_inheritable++;
107155bf511dSas200622 			break;
107255bf511dSas200622 
107355bf511dSas200622 		case ACE_DIRECTORY_INHERIT_ACE:
107455bf511dSas200622 			/*
107555bf511dSas200622 			 * No effect on files
107655bf511dSas200622 			 *
107755bf511dSas200622 			 * Dirs inherit an effective ACE.
107855bf511dSas200622 			 * The inherited ACE is inheritable unless the
107955bf511dSas200622 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
108055bf511dSas200622 			 */
108155bf511dSas200622 			if (is_dir == 0)
108255bf511dSas200622 				break;
108355bf511dSas200622 
108455bf511dSas200622 			num_inheritable++;
108555bf511dSas200622 
108655bf511dSas200622 			if (ZACE_IS_CREATOR(zace) &&
108755bf511dSas200622 			    (ZACE_IS_PROPAGATE(zace)))
108855bf511dSas200622 				num_inheritable++;
108955bf511dSas200622 			break;
109055bf511dSas200622 
109155bf511dSas200622 		default:
109255bf511dSas200622 			break;
109355bf511dSas200622 		}
109455bf511dSas200622 	}
109555bf511dSas200622 
109655bf511dSas200622 	return (num_inheritable);
109755bf511dSas200622 }
1098*7206bf49SGordon Ross #endif	/* _KERNEL */
109955bf511dSas200622 
110055bf511dSas200622 
110155bf511dSas200622 /*
110255bf511dSas200622  * ACE Functions
110355bf511dSas200622  */
110455bf511dSas200622 
110555bf511dSas200622 /*
110655bf511dSas200622  * This is generic (ACL version 2) vs. object-specific
110755bf511dSas200622  * (ACL version 4) ACE types.
110855bf511dSas200622  */
110955bf511dSas200622 boolean_t
smb_ace_is_generic(int type)111055bf511dSas200622 smb_ace_is_generic(int type)
111155bf511dSas200622 {
111255bf511dSas200622 	switch (type) {
111355bf511dSas200622 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
111455bf511dSas200622 	case ACE_ACCESS_DENIED_ACE_TYPE:
111555bf511dSas200622 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
111655bf511dSas200622 	case ACE_SYSTEM_ALARM_ACE_TYPE:
111755bf511dSas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
111855bf511dSas200622 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
111955bf511dSas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
112055bf511dSas200622 	case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
112155bf511dSas200622 		return (B_TRUE);
112255bf511dSas200622 
112355bf511dSas200622 	default:
112455bf511dSas200622 		break;
112555bf511dSas200622 	}
112655bf511dSas200622 
112755bf511dSas200622 	return (B_FALSE);
112855bf511dSas200622 }
112955bf511dSas200622 
113055bf511dSas200622 boolean_t
smb_ace_is_access(int type)113155bf511dSas200622 smb_ace_is_access(int type)
113255bf511dSas200622 {
113355bf511dSas200622 	switch (type) {
113455bf511dSas200622 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
113555bf511dSas200622 	case ACE_ACCESS_DENIED_ACE_TYPE:
113655bf511dSas200622 	case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
113755bf511dSas200622 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
113855bf511dSas200622 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
113955bf511dSas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
114055bf511dSas200622 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
114155bf511dSas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
114255bf511dSas200622 	case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
114355bf511dSas200622 		return (B_TRUE);
114455bf511dSas200622 
114555bf511dSas200622 	default:
114655bf511dSas200622 		break;
114755bf511dSas200622 	}
114855bf511dSas200622 
114955bf511dSas200622 	return (B_FALSE);
115055bf511dSas200622 }
115155bf511dSas200622 
115255bf511dSas200622 boolean_t
smb_ace_is_audit(int type)115355bf511dSas200622 smb_ace_is_audit(int type)
115455bf511dSas200622 {
115555bf511dSas200622 	switch (type) {
115655bf511dSas200622 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
115755bf511dSas200622 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
115855bf511dSas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
115955bf511dSas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
116055bf511dSas200622 		return (B_TRUE);
116155bf511dSas200622 
116255bf511dSas200622 	default:
116355bf511dSas200622 		break;
116455bf511dSas200622 	}
116555bf511dSas200622 
116655bf511dSas200622 	return (B_FALSE);
116755bf511dSas200622 }
116855bf511dSas200622 
116955bf511dSas200622 /*
117055bf511dSas200622  * smb_ace_len
117155bf511dSas200622  *
117255bf511dSas200622  * Returns the length of the given ACE as it appears in an
117355bf511dSas200622  * ACL on the wire (i.e. a flat buffer which contains the SID)
117455bf511dSas200622  */
117555bf511dSas200622 static uint16_t
smb_ace_len(smb_ace_t * ace)117655bf511dSas200622 smb_ace_len(smb_ace_t *ace)
117755bf511dSas200622 {
117855bf511dSas200622 	ASSERT(ace);
117955bf511dSas200622 	ASSERT(ace->se_sid);
118055bf511dSas200622 
118155bf511dSas200622 	if (ace == NULL)
118255bf511dSas200622 		return (0);
118355bf511dSas200622 
118455bf511dSas200622 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
11856537f381Sas200622 	    smb_sid_len(ace->se_sid));
118655bf511dSas200622 }
118755bf511dSas200622 
1188*7206bf49SGordon Ross #ifdef	_KERNEL
1189da6c28aaSamw static void
smb_ace_inherit(ace_t * dir_zace,ace_t * zace,int is_dir,uid_t uid,gid_t gid)11909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir, uid_t uid, gid_t gid)
1191da6c28aaSamw {
1192da6c28aaSamw 	*zace = *dir_zace;
1193c8ec8eeaSjose borrego 
1194c8ec8eeaSjose borrego 	/* This is an effective ACE so remove the inherit_only flag */
1195c8ec8eeaSjose borrego 	zace->a_flags &= ~ACE_INHERIT_ONLY_ACE;
1196c8ec8eeaSjose borrego 	/* Mark this ACE as inherited */
1197da6c28aaSamw 	zace->a_flags |= ACE_INHERITED_ACE;
1198da6c28aaSamw 
1199da6c28aaSamw 	/*
1200c8ec8eeaSjose borrego 	 * If this is a file or NO_PROPAGATE is set then this inherited
1201c8ec8eeaSjose borrego 	 * ACE is not inheritable so clear the inheritance flags
1202c8ec8eeaSjose borrego 	 */
1203c8ec8eeaSjose borrego 	if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
1204c8ec8eeaSjose borrego 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1205c8ec8eeaSjose borrego 
1206c8ec8eeaSjose borrego 	/*
1207c8ec8eeaSjose borrego 	 * Replace creator owner/group ACEs with actual owner/group ACEs.
12089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * This is a non-inheritable effective ACE.
1209da6c28aaSamw 	 */
1210da6c28aaSamw 	if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
12119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_who = uid;
1212c8ec8eeaSjose borrego 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1213da6c28aaSamw 	} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
12149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_who = gid;
12159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_flags |= ACE_IDENTIFIER_GROUP;
1216c8ec8eeaSjose borrego 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1217da6c28aaSamw 	}
1218da6c28aaSamw }
1219*7206bf49SGordon Ross #endif	/* _KERNEL */
1220da6c28aaSamw 
122155bf511dSas200622 /*
122255bf511dSas200622  * smb_ace_mask_g2s
122355bf511dSas200622  *
122455bf511dSas200622  * Converts generic access bits in the given mask (if any)
122555bf511dSas200622  * to file specific bits. Generic access masks shouldn't be
122655bf511dSas200622  * stored in filesystem ACEs.
122755bf511dSas200622  */
122855bf511dSas200622 static uint32_t
smb_ace_mask_g2s(uint32_t mask)122955bf511dSas200622 smb_ace_mask_g2s(uint32_t mask)
123055bf511dSas200622 {
123155bf511dSas200622 	if (mask & GENERIC_ALL) {
123255bf511dSas200622 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
123355bf511dSas200622 		    | GENERIC_EXECUTE);
123455bf511dSas200622 
123555bf511dSas200622 		mask |= FILE_ALL_ACCESS;
123655bf511dSas200622 		return (mask);
123755bf511dSas200622 	}
123855bf511dSas200622 
123955bf511dSas200622 	if (mask & GENERIC_READ) {
124055bf511dSas200622 		mask &= ~GENERIC_READ;
124155bf511dSas200622 		mask |= FILE_GENERIC_READ;
124255bf511dSas200622 	}
124355bf511dSas200622 
124455bf511dSas200622 	if (mask & GENERIC_WRITE) {
124555bf511dSas200622 		mask &= ~GENERIC_WRITE;
124655bf511dSas200622 		mask |= FILE_GENERIC_WRITE;
124755bf511dSas200622 	}
124855bf511dSas200622 
124955bf511dSas200622 	if (mask & GENERIC_EXECUTE) {
125055bf511dSas200622 		mask &= ~GENERIC_EXECUTE;
125155bf511dSas200622 		mask |= FILE_GENERIC_EXECUTE;
125255bf511dSas200622 	}
125355bf511dSas200622 
125455bf511dSas200622 	return (mask);
125555bf511dSas200622 }
125655bf511dSas200622 
1257c8ec8eeaSjose borrego /*
1258c8ec8eeaSjose borrego  * smb_ace_flags_tozfs
1259c8ec8eeaSjose borrego  *
1260c8ec8eeaSjose borrego  * This function maps the flags which have different values
1261c8ec8eeaSjose borrego  * in Windows and Solaris. The ones with the same value are
1262c8ec8eeaSjose borrego  * transferred untouched.
1263c8ec8eeaSjose borrego  */
1264da6c28aaSamw static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)1265c8ec8eeaSjose borrego smb_ace_flags_tozfs(uint8_t c_flags)
1266da6c28aaSamw {
1267da6c28aaSamw 	uint16_t z_flags = 0;
1268da6c28aaSamw 
1269da6c28aaSamw 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
1270da6c28aaSamw 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
1271da6c28aaSamw 
1272da6c28aaSamw 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
1273da6c28aaSamw 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
1274da6c28aaSamw 
1275da6c28aaSamw 	if (c_flags & INHERITED_ACE)
1276da6c28aaSamw 		z_flags |= ACE_INHERITED_ACE;
1277da6c28aaSamw 
1278da6c28aaSamw 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
1279da6c28aaSamw 
1280da6c28aaSamw 	return (z_flags);
1281da6c28aaSamw }
1282da6c28aaSamw 
1283da6c28aaSamw static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)1284da6c28aaSamw smb_ace_flags_fromzfs(uint16_t z_flags)
1285da6c28aaSamw {
1286da6c28aaSamw 	uint8_t c_flags;
1287da6c28aaSamw 
1288da6c28aaSamw 	c_flags = z_flags & ACE_INHERIT_FLAGS;
1289da6c28aaSamw 
1290da6c28aaSamw 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
1291da6c28aaSamw 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
1292da6c28aaSamw 
1293da6c28aaSamw 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
1294da6c28aaSamw 		c_flags |= FAILED_ACCESS_ACE_FLAG;
1295da6c28aaSamw 
1296da6c28aaSamw 	if (z_flags & ACE_INHERITED_ACE)
1297da6c28aaSamw 		c_flags |= INHERITED_ACE;
1298da6c28aaSamw 
1299da6c28aaSamw 	return (c_flags);
1300da6c28aaSamw }
1301da6c28aaSamw 
130255bf511dSas200622 static boolean_t
smb_ace_isvalid(smb_ace_t * ace,int which_acl)130355bf511dSas200622 smb_ace_isvalid(smb_ace_t *ace, int which_acl)
130455bf511dSas200622 {
130555bf511dSas200622 	uint16_t min_len;
130655bf511dSas200622 
130755bf511dSas200622 	min_len = sizeof (smb_acehdr_t);
130855bf511dSas200622 
130955bf511dSas200622 	if (ace->se_hdr.se_bsize < min_len)
131055bf511dSas200622 		return (B_FALSE);
131155bf511dSas200622 
131255bf511dSas200622 	if (smb_ace_is_access(ace->se_hdr.se_type) &&
131355bf511dSas200622 	    (which_acl != SMB_DACL_SECINFO))
131455bf511dSas200622 		return (B_FALSE);
131555bf511dSas200622 
131655bf511dSas200622 	if (smb_ace_is_audit(ace->se_hdr.se_type) &&
131755bf511dSas200622 	    (which_acl != SMB_SACL_SECINFO))
131855bf511dSas200622 		return (B_FALSE);
131955bf511dSas200622 
132055bf511dSas200622 	if (smb_ace_is_generic(ace->se_hdr.se_type)) {
13216537f381Sas200622 		if (!smb_sid_isvalid(ace->se_sid))
132255bf511dSas200622 			return (B_FALSE);
132355bf511dSas200622 
132455bf511dSas200622 		min_len += sizeof (ace->se_mask);
13256537f381Sas200622 		min_len += smb_sid_len(ace->se_sid);
132655bf511dSas200622 
132755bf511dSas200622 		if (ace->se_hdr.se_bsize < min_len)
132855bf511dSas200622 			return (B_FALSE);
132955bf511dSas200622 	}
133055bf511dSas200622 
1331da6c28aaSamw 	/*
133255bf511dSas200622 	 * object-specific ACE validation will be added later.
1333da6c28aaSamw 	 */
133455bf511dSas200622 	return (B_TRUE);
1335da6c28aaSamw }
1336