xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_acl.c (revision f920d1d1)
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.
24b819cea2SGordon Ross  *
25b819cea2SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
26*f920d1d1SGordon Ross  * Copyright 2023 RackTop Systems, Inc.
27*f920d1d1SGordon Ross  */
28*f920d1d1SGordon Ross 
29*f920d1d1SGordon Ross /*
30*f920d1d1SGordon Ross  * SMB server interfaces for ACL conversion (smb_acl_...)
31*f920d1d1SGordon Ross  *
32*f920d1d1SGordon Ross  * There are two variants of this interface:
33*f920d1d1SGordon Ross  * This is the kernel version.  See also:
34*f920d1d1SGordon Ross  * $SRC/lib/smbsrv/libsmb/common/smb_acl.c
35da6c28aaSamw  */
36da6c28aaSamw 
379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <sys/sid.h>
38da6c28aaSamw #include <sys/acl.h>
3955bf511dSas #include <acl/acl_common.h>
406537f381Sas #include <smbsrv/smb_sid.h>
41da6c28aaSamw #include <smbsrv/smb_fsops.h>
42da6c28aaSamw #include <smbsrv/smb_idmap.h>
4355bf511dSas #include <smbsrv/smb_kproto.h>
44da6c28aaSamw 
45da6c28aaSamw #define	ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
46da6c28aaSamw 
47da6c28aaSamw #define	ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
48da6c28aaSamw #define	ZACE_IS_OWNGRP(zace) \
49da6c28aaSamw 	((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
50da6c28aaSamw 
51da6c28aaSamw #define	ZACE_IS_USER(zace) \
52da6c28aaSamw 	(((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
53da6c28aaSamw #define	ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
54da6c28aaSamw #define	ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
55da6c28aaSamw 
56da6c28aaSamw #define	ZACE_IS_PROPAGATE(zace) \
57da6c28aaSamw 	((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
58da6c28aaSamw 
59da6c28aaSamw #define	ZACE_IS_CREATOR_OWNER(zace) \
60da6c28aaSamw 	(ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
61da6c28aaSamw 
62da6c28aaSamw #define	ZACE_IS_CREATOR_GROUP(zace) \
63da6c28aaSamw 	(ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
64da6c28aaSamw 
65da6c28aaSamw #define	ZACE_IS_CREATOR(zace) \
66da6c28aaSamw 	(ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
67da6c28aaSamw 
6855bf511dSas /*
6955bf511dSas  * ACE groups within a DACL
7055bf511dSas  *
7155bf511dSas  * This is from lower to higher ACE order priority
7255bf511dSas  */
7355bf511dSas #define	SMB_AG_START		0
7455bf511dSas #define	SMB_AG_ALW_INHRT	0
7555bf511dSas #define	SMB_AG_DNY_INHRT	1
7655bf511dSas #define	SMB_AG_ALW_DRCT		2
7755bf511dSas #define	SMB_AG_DNY_DRCT		3
7855bf511dSas #define	SMB_AG_NUM		4
79da6c28aaSamw 
8055bf511dSas #define	DEFAULT_DACL_ACENUM	2
8155bf511dSas /*
8255bf511dSas  * Default ACL:
8355bf511dSas  *    owner: full access
8455bf511dSas  *    SYSTEM: full access
8555bf511dSas  */
86b819cea2SGordon Ross #ifdef	_KERNEL
87adb064afSToomas Soome static const ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
8855bf511dSas 	{ (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
8955bf511dSas 	{ IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
9055bf511dSas 	    ACE_ACCESS_ALLOWED_ACE_TYPE }
9155bf511dSas };
92b819cea2SGordon Ross #endif	/* _KERNEL */
93da6c28aaSamw 
9455bf511dSas /*
9555bf511dSas  * Note:
9655bf511dSas  *
9755bf511dSas  * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
9855bf511dSas  * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
9955bf511dSas  * format
10055bf511dSas  */
101da6c28aaSamw 
102f96bd5c8SAlan Wright static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
103c8ec8eeaSjose borrego static acl_t *smb_fsacl_null_empty(boolean_t);
104b819cea2SGordon Ross #ifdef	_KERNEL
10555bf511dSas static int smb_fsacl_inheritable(acl_t *, int);
1069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_ace_inherit(ace_t *, ace_t *, int, uid_t, gid_t);
107b819cea2SGordon Ross #endif	/* _KERNEL */
108b819cea2SGordon Ross 
10955bf511dSas static boolean_t smb_ace_isvalid(smb_ace_t *, int);
11055bf511dSas static uint16_t smb_ace_len(smb_ace_t *);
11155bf511dSas static uint32_t smb_ace_mask_g2s(uint32_t);
112c8ec8eeaSjose borrego static uint16_t smb_ace_flags_tozfs(uint8_t);
11355bf511dSas static uint8_t smb_ace_flags_fromzfs(uint16_t);
114f96bd5c8SAlan Wright static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
115da6c28aaSamw 
11655bf511dSas smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)11755bf511dSas smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
11855bf511dSas {
11955bf511dSas 	smb_acl_t *acl;
12055bf511dSas 	int size;
121da6c28aaSamw 
12255bf511dSas 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
12355bf511dSas 	acl = kmem_zalloc(size, KM_SLEEP);
12455bf511dSas 	acl->sl_revision = revision;
12555bf511dSas 	acl->sl_bsize = bsize;
12655bf511dSas 	acl->sl_acecnt = acecnt;
12755bf511dSas 	acl->sl_aces = (smb_ace_t *)(acl + 1);
128da6c28aaSamw 
12955bf511dSas 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
13055bf511dSas 	    offsetof(smb_ace_t, se_sln));
13155bf511dSas 	return (acl);
132da6c28aaSamw }
133da6c28aaSamw 
13455bf511dSas void
smb_acl_free(smb_acl_t * acl)13555bf511dSas smb_acl_free(smb_acl_t *acl)
136da6c28aaSamw {
13755bf511dSas 	int i, size;
13855bf511dSas 	void *ace;
139da6c28aaSamw 
14055bf511dSas 	if (acl == NULL)
14155bf511dSas 		return;
142da6c28aaSamw 
1436537f381Sas 	for (i = 0; i < acl->sl_acecnt; i++)
1446537f381Sas 		smb_sid_free(acl->sl_aces[i].se_sid);
145da6c28aaSamw 
14655bf511dSas 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
14755bf511dSas 		list_remove(&acl->sl_sorted, ace);
14855bf511dSas 	list_destroy(&acl->sl_sorted);
149da6c28aaSamw 
15055bf511dSas 	size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
15155bf511dSas 	kmem_free(acl, size);
152da6c28aaSamw }
153da6c28aaSamw 
15455bf511dSas /*
15555bf511dSas  * smb_acl_len
15655bf511dSas  *
15755bf511dSas  * Returns the size of given ACL in bytes. Note that this
15855bf511dSas  * is not an in-memory size, it's the ACL's size as it would
15955bf511dSas  * appear on the wire
16055bf511dSas  */
161da6c28aaSamw uint16_t
smb_acl_len(smb_acl_t * acl)162da6c28aaSamw smb_acl_len(smb_acl_t *acl)
163da6c28aaSamw {
164c8ec8eeaSjose borrego 	return ((acl) ? acl->sl_bsize : 0);
165da6c28aaSamw }
166da6c28aaSamw 
16755bf511dSas boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)16855bf511dSas smb_acl_isvalid(smb_acl_t *acl, int which_acl)
169da6c28aaSamw {
17055bf511dSas 	int i;
171da6c28aaSamw 
17255bf511dSas 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
17355bf511dSas 		return (B_FALSE);
17455bf511dSas 
17555bf511dSas 	if (acl->sl_revision != ACL_REVISION) {
17655bf511dSas 		/*
17755bf511dSas 		 * we are rejecting ACLs with object-specific ACEs for now
17855bf511dSas 		 */
17955bf511dSas 		return (B_FALSE);
180da6c28aaSamw 	}
181da6c28aaSamw 
18255bf511dSas 	for (i = 0; i < acl->sl_acecnt; i++) {
18355bf511dSas 		if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
18455bf511dSas 			return (B_FALSE);
18555bf511dSas 	}
186da6c28aaSamw 
18755bf511dSas 	return (B_TRUE);
188da6c28aaSamw }
189da6c28aaSamw 
190da6c28aaSamw /*
19155bf511dSas  * smb_acl_sort
192da6c28aaSamw  *
19355bf511dSas  * Sorts the given ACL in place if it needs to be sorted.
194da6c28aaSamw  *
195da6c28aaSamw  * The following is an excerpt from MSDN website.
196da6c28aaSamw  *
197da6c28aaSamw  * Order of ACEs in a DACL
198da6c28aaSamw  *
199da6c28aaSamw  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
200da6c28aaSamw  * is simple: In a DACL, all access-denied ACEs should precede any
201da6c28aaSamw  * access-allowed ACEs.
202da6c28aaSamw  *
203da6c28aaSamw  * For Windows 2000 or later, the proper order of ACEs is more complicated
204da6c28aaSamw  * because of the introduction of object-specific ACEs and automatic
205da6c28aaSamw  * inheritance.
206da6c28aaSamw  *
207da6c28aaSamw  * The following describes the preferred order:
208da6c28aaSamw  *
209da6c28aaSamw  * To ensure that noninherited ACEs have precedence over inherited ACEs,
210da6c28aaSamw  * place all noninherited ACEs in a group before any inherited ACEs. This
211da6c28aaSamw  * ordering ensures, for example, that a noninherited access-denied ACE
212da6c28aaSamw  * is enforced regardless of any inherited ACE that allows access.
213da6c28aaSamw  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
214da6c28aaSamw  * according to ACE type, as the following shows:
215*f920d1d1SGordon Ross  *	. Access-denied ACEs that apply to the object itself
216*f920d1d1SGordon Ross  *	. Access-denied ACEs that apply to a subobject of the
217da6c28aaSamw  *	  object, such as a property set or property
218*f920d1d1SGordon Ross  *	. Access-allowed ACEs that apply to the object itself
219*f920d1d1SGordon Ross  *	. Access-allowed ACEs that apply to a subobject of the object
220da6c28aaSamw  *
22155bf511dSas  * So, here is the desired ACE order
222da6c28aaSamw  *
223da6c28aaSamw  * deny-direct, allow-direct, deny-inherited, allow-inherited
224da6c28aaSamw  *
22555bf511dSas  * Of course, not all ACE types are required in an ACL.
226da6c28aaSamw  */
22755bf511dSas void
smb_acl_sort(smb_acl_t * acl)228da6c28aaSamw smb_acl_sort(smb_acl_t *acl)
229da6c28aaSamw {
230da6c28aaSamw 	list_t ace_grps[SMB_AG_NUM];
23155bf511dSas 	list_t *alist;
23255bf511dSas 	smb_ace_t *ace;
233da6c28aaSamw 	uint8_t ace_flags;
23455bf511dSas 	int ag, i;
235da6c28aaSamw 
236da6c28aaSamw 	ASSERT(acl);
237da6c28aaSamw 
238da6c28aaSamw 	if (acl->sl_acecnt == 0) {
239da6c28aaSamw 		/*
240da6c28aaSamw 		 * ACL with no entry is a valid ACL and it means
241da6c28aaSamw 		 * no access for anybody.
242da6c28aaSamw 		 */
24355bf511dSas 		return;
244da6c28aaSamw 	}
245da6c28aaSamw 
246da6c28aaSamw 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
24755bf511dSas 		list_create(&ace_grps[i], sizeof (smb_ace_t),
24855bf511dSas 		    offsetof(smb_ace_t, se_sln));
249da6c28aaSamw 	}
250da6c28aaSamw 
25155bf511dSas 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
25255bf511dSas 		ace_flags = ace->se_hdr.se_flags;
253da6c28aaSamw 
25455bf511dSas 		switch (ace->se_hdr.se_type) {
255da6c28aaSamw 		case ACCESS_DENIED_ACE_TYPE:
25655bf511dSas 			ag = (ace_flags & INHERITED_ACE) ?
25755bf511dSas 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
258da6c28aaSamw 			break;
259da6c28aaSamw 
260da6c28aaSamw 		case ACCESS_ALLOWED_ACE_TYPE:
26155bf511dSas 			ag = (ace_flags & INHERITED_ACE) ?
26255bf511dSas 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
263da6c28aaSamw 			break;
264da6c28aaSamw 
265da6c28aaSamw 		default:
266da6c28aaSamw 			/*
267da6c28aaSamw 			 * This is the lowest priority group so we put
268da6c28aaSamw 			 * evertything unknown here.
269da6c28aaSamw 			 */
270da6c28aaSamw 			ag = SMB_AG_ALW_INHRT;
271da6c28aaSamw 			break;
272da6c28aaSamw 		}
273da6c28aaSamw 
27455bf511dSas 		/* Add the ACE to the selected group */
27555bf511dSas 		list_insert_tail(&ace_grps[ag], ace);
276da6c28aaSamw 	}
277da6c28aaSamw 
27855bf511dSas 	/*
27955bf511dSas 	 * start with highest priority ACE group and append
28055bf511dSas 	 * the ACEs to the ACL.
28155bf511dSas 	 */
28255bf511dSas 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
28355bf511dSas 		alist = &ace_grps[i];
28455bf511dSas 		while ((ace = list_head(alist)) != NULL) {
28555bf511dSas 			list_remove(alist, ace);
28655bf511dSas 			list_insert_tail(&acl->sl_sorted, ace);
28755bf511dSas 		}
288da6c28aaSamw 		list_destroy(alist);
289da6c28aaSamw 	}
290da6c28aaSamw }
291da6c28aaSamw 
292*f920d1d1SGordon Ross /*
293*f920d1d1SGordon Ross  * Error handling call-back for smb_idmap_batch_getmappings.
294*f920d1d1SGordon Ross  * Would be nice if this could report the path, but that's not
295*f920d1d1SGordon Ross  * passed down here.  For now, use a dtrace fbt probe here.
296*f920d1d1SGordon Ross  */
297*f920d1d1SGordon Ross static void
smb_acl_bgm_error(smb_idmap_batch_t * sib,smb_idmap_t * sim)298*f920d1d1SGordon Ross smb_acl_bgm_error(smb_idmap_batch_t *sib, smb_idmap_t *sim)
299*f920d1d1SGordon Ross {
300*f920d1d1SGordon Ross 
301*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) != 0)
302*f920d1d1SGordon Ross 		return;
303*f920d1d1SGordon Ross 
304*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
305*f920d1d1SGordon Ross 		/*
306*f920d1d1SGordon Ross 		 * Note: The ID and type we asked idmap to map
307*f920d1d1SGordon Ross 		 * were saved in *sim_id and sim_idtype.
308*f920d1d1SGordon Ross 		 */
309*f920d1d1SGordon Ross 		int id = (sim->sim_id == NULL) ? -1 : (int)*sim->sim_id;
310*f920d1d1SGordon Ross 		cmn_err(CE_WARN, "!smb_acl: Can't get SID for "
311*f920d1d1SGordon Ross 		    "ID=%d type=%d, status=%d",
312*f920d1d1SGordon Ross 		    id, sim->sim_idtype, sim->sim_stat);
313*f920d1d1SGordon Ross 	}
314*f920d1d1SGordon Ross 
315*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
316*f920d1d1SGordon Ross 		cmn_err(CE_WARN, "!smb_acl: Can't get ID for "
317*f920d1d1SGordon Ross 		    "SID %s-%u, status=%d",
318*f920d1d1SGordon Ross 		    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
319*f920d1d1SGordon Ross 	}
320*f920d1d1SGordon Ross }
321*f920d1d1SGordon Ross 
32255bf511dSas /*
32355bf511dSas  * smb_acl_from_zfs
32455bf511dSas  *
32555bf511dSas  * Converts given ZFS ACL to a Windows ACL.
32655bf511dSas  *
32755bf511dSas  * A pointer to allocated memory for the Win ACL will be
32855bf511dSas  * returned upon successful conversion.
32955bf511dSas  */
33055bf511dSas smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)331f96bd5c8SAlan Wright smb_acl_from_zfs(acl_t *zacl)
332da6c28aaSamw {
33355bf511dSas 	ace_t *zace;
33455bf511dSas 	int numaces;
33555bf511dSas 	smb_acl_t *acl;
336da6c28aaSamw 	smb_ace_t *ace;
33755bf511dSas 	smb_idmap_batch_t sib;
33855bf511dSas 	smb_idmap_t *sim;
33955bf511dSas 	idmap_stat idm_stat;
340da6c28aaSamw 
34155bf511dSas 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
34255bf511dSas 	    SMB_IDMAP_ID2SID);
34355bf511dSas 	if (idm_stat != IDMAP_SUCCESS)
34455bf511dSas 		return (NULL);
345da6c28aaSamw 
346*f920d1d1SGordon Ross 	/*
347*f920d1d1SGordon Ross 	 * Note that smb_fsacl_getsids sets up references in
348*f920d1d1SGordon Ross 	 * sib.sib_maps to the zace->a_who fields that live
349*f920d1d1SGordon Ross 	 * until smb_idmap_batch_destroy is called.
350*f920d1d1SGordon Ross 	 */
351f96bd5c8SAlan Wright 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
35255bf511dSas 		smb_idmap_batch_destroy(&sib);
353da6c28aaSamw 		return (NULL);
35455bf511dSas 	}
355da6c28aaSamw 
35655bf511dSas 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
357da6c28aaSamw 
35855bf511dSas 	sim = sib.sib_maps;
35955bf511dSas 	for (numaces = 0, zace = zacl->acl_aclp;
36055bf511dSas 	    numaces < zacl->acl_cnt;
36155bf511dSas 	    zace++, numaces++, sim++) {
36255bf511dSas 		ASSERT(sim->sim_sid);
36355bf511dSas 		if (sim->sim_sid == NULL) {
36455bf511dSas 			smb_acl_free(acl);
36555bf511dSas 			acl = NULL;
36655bf511dSas 			break;
367da6c28aaSamw 		}
368da6c28aaSamw 
36955bf511dSas 		ace = &acl->sl_aces[numaces];
37055bf511dSas 		ace->se_hdr.se_type = zace->a_type;
37155bf511dSas 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
37255bf511dSas 		ace->se_mask = zace->a_access_mask;
3736537f381Sas 		ace->se_sid = smb_sid_dup(sim->sim_sid);
37455bf511dSas 		ace->se_hdr.se_bsize = smb_ace_len(ace);
37555bf511dSas 
37655bf511dSas 		acl->sl_bsize += ace->se_hdr.se_bsize;
377da6c28aaSamw 	}
378da6c28aaSamw 
37955bf511dSas 	smb_idmap_batch_destroy(&sib);
38055bf511dSas 	return (acl);
381da6c28aaSamw }
382da6c28aaSamw 
383da6c28aaSamw /*
38455bf511dSas  * smb_acl_to_zfs
385da6c28aaSamw  *
38655bf511dSas  * Converts given Windows ACL to a ZFS ACL.
387da6c28aaSamw  *
38855bf511dSas  * fs_acl will contain a pointer to the created ZFS ACL.
38955bf511dSas  * The allocated memory should be freed by calling
39055bf511dSas  * smb_fsacl_free().
391da6c28aaSamw  *
39255bf511dSas  * Since the output parameter, fs_acl, is allocated in this
39355bf511dSas  * function, the caller has to make sure *fs_acl is NULL which
39455bf511dSas  * means it's not pointing to any memory.
395da6c28aaSamw  */
396da6c28aaSamw uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)39755bf511dSas smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
398da6c28aaSamw {
39955bf511dSas 	smb_ace_t *ace;
40055bf511dSas 	acl_t *zacl;
40155bf511dSas 	ace_t *zace;
40255bf511dSas 	smb_idmap_batch_t sib;
40355bf511dSas 	smb_idmap_t *sim;
40455bf511dSas 	idmap_stat idm_stat;
405f96bd5c8SAlan Wright 	char *sidstr;
406c8ec8eeaSjose borrego 	int i;
407da6c28aaSamw 
40855bf511dSas 	ASSERT(fs_acl);
40955bf511dSas 	ASSERT(*fs_acl == NULL);
41055bf511dSas 
41155bf511dSas 	if (acl && !smb_acl_isvalid(acl, which_acl))
41255bf511dSas 		return (NT_STATUS_INVALID_ACL);
41355bf511dSas 
41455bf511dSas 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
41555bf511dSas 		if (which_acl == SMB_DACL_SECINFO) {
416c8ec8eeaSjose borrego 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
41755bf511dSas 		}
41855bf511dSas 
41955bf511dSas 		return (NT_STATUS_SUCCESS);
420da6c28aaSamw 	}
421da6c28aaSamw 
42255bf511dSas 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
42355bf511dSas 	    SMB_IDMAP_SID2ID);
42455bf511dSas 	if (idm_stat != IDMAP_SUCCESS)
42555bf511dSas 		return (NT_STATUS_INTERNAL_ERROR);
42655bf511dSas 
427f96bd5c8SAlan Wright 	sidstr = kmem_alloc(SMB_SID_STRSZ, KM_SLEEP);
42855bf511dSas 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
42955bf511dSas 
43055bf511dSas 	zace = zacl->acl_aclp;
43155bf511dSas 	ace = acl->sl_aces;
43255bf511dSas 	sim = sib.sib_maps;
43355bf511dSas 
43455bf511dSas 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
43555bf511dSas 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
43655bf511dSas 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
437c8ec8eeaSjose borrego 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
438f96bd5c8SAlan Wright 		zace->a_who = (uid_t)-1;
43955bf511dSas 
440f96bd5c8SAlan Wright 		smb_sid_tostr(ace->se_sid, sidstr);
441f96bd5c8SAlan Wright 
442f96bd5c8SAlan Wright 		if (!smb_ace_wellknown_update(sidstr, zace)) {
44355bf511dSas 			sim->sim_id = &zace->a_who;
44455bf511dSas 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
445f96bd5c8SAlan Wright 			    ace->se_sid, SMB_IDMAP_UNKNOWN);
44655bf511dSas 
44755bf511dSas 			if (idm_stat != IDMAP_SUCCESS) {
448f96bd5c8SAlan Wright 				kmem_free(sidstr, SMB_SID_STRSZ);
44955bf511dSas 				smb_fsacl_free(zacl);
45055bf511dSas 				smb_idmap_batch_destroy(&sib);
45155bf511dSas 				return (NT_STATUS_INTERNAL_ERROR);
45255bf511dSas 			}
45355bf511dSas 		}
454da6c28aaSamw 	}
455da6c28aaSamw 
456f96bd5c8SAlan Wright 	kmem_free(sidstr, SMB_SID_STRSZ);
457f96bd5c8SAlan Wright 
458*f920d1d1SGordon Ross 	idm_stat = smb_idmap_batch_getmappings(&sib, smb_acl_bgm_error);
45955bf511dSas 	if (idm_stat != IDMAP_SUCCESS) {
46055bf511dSas 		smb_fsacl_free(zacl);
46155bf511dSas 		smb_idmap_batch_destroy(&sib);
46255bf511dSas 		return (NT_STATUS_NONE_MAPPED);
463da6c28aaSamw 	}
464da6c28aaSamw 
46555bf511dSas 	/*
46655bf511dSas 	 * Set the ACEs group flag based on the type of ID returned.
46755bf511dSas 	 */
46855bf511dSas 	zace = zacl->acl_aclp;
46955bf511dSas 	ace = acl->sl_aces;
47055bf511dSas 	sim = sib.sib_maps;
47155bf511dSas 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
472f96bd5c8SAlan Wright 		if (zace->a_who == (uid_t)-1)
47355bf511dSas 			continue;
47455bf511dSas 
47555bf511dSas 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
47655bf511dSas 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
477da6c28aaSamw 	}
478da6c28aaSamw 
47955bf511dSas 	smb_idmap_batch_destroy(&sib);
48055bf511dSas 
48155bf511dSas 	*fs_acl = zacl;
48255bf511dSas 	return (NT_STATUS_SUCCESS);
483da6c28aaSamw }
484da6c28aaSamw 
485f96bd5c8SAlan Wright static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)486f96bd5c8SAlan Wright smb_ace_wellknown_update(const char *sid, ace_t *zace)
487f96bd5c8SAlan Wright {
488f96bd5c8SAlan Wright 	struct {
489f96bd5c8SAlan Wright 		char		*sid;
490f96bd5c8SAlan Wright 		uint16_t	flags;
491f96bd5c8SAlan Wright 	} map[] = {
492f96bd5c8SAlan Wright 		{ NT_WORLD_SIDSTR,			ACE_EVERYONE },
493f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_OWNER_SIDSTR,	ACE_OWNER },
494f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_GROUP_SIDSTR,
495f96bd5c8SAlan Wright 			(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
496f96bd5c8SAlan Wright 	};
497f96bd5c8SAlan Wright 
498f96bd5c8SAlan Wright 	int	i;
499f96bd5c8SAlan Wright 
500f96bd5c8SAlan Wright 	for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
501f96bd5c8SAlan Wright 		if (strcmp(sid, map[i].sid) == 0) {
502f96bd5c8SAlan Wright 			zace->a_flags |= map[i].flags;
503f96bd5c8SAlan Wright 			return (B_TRUE);
504f96bd5c8SAlan Wright 		}
505f96bd5c8SAlan Wright 	}
506f96bd5c8SAlan Wright 
507f96bd5c8SAlan Wright 	return (B_FALSE);
508f96bd5c8SAlan Wright }
509f96bd5c8SAlan Wright 
510da6c28aaSamw /*
511c8ec8eeaSjose borrego  * smb_fsacl_getsids
512da6c28aaSamw  *
513da6c28aaSamw  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
514*f920d1d1SGordon Ross  * Note: sib is type SMB_IDMAP_ID2SID, zacl->acl_cnt entries.
515da6c28aaSamw  */
516da6c28aaSamw static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)517f96bd5c8SAlan Wright smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
518da6c28aaSamw {
519da6c28aaSamw 	ace_t *zace;
520da6c28aaSamw 	idmap_stat idm_stat;
521da6c28aaSamw 	smb_idmap_t *sim;
522*f920d1d1SGordon Ross 	uid_t id;
523da6c28aaSamw 	int i, idtype;
524da6c28aaSamw 
525da6c28aaSamw 	sim = sib->sib_maps;
526da6c28aaSamw 
527da6c28aaSamw 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
528da6c28aaSamw 	    zace++, i++, sim++) {
529*f920d1d1SGordon Ross 		id = (uid_t)-1;	/* some types do not need id */
530da6c28aaSamw 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
531da6c28aaSamw 		case ACE_OWNER:
532f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_OWNERAT;
533da6c28aaSamw 			break;
534da6c28aaSamw 
535da6c28aaSamw 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
536da6c28aaSamw 			/* owning group */
537f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_GROUPAT;
538da6c28aaSamw 			break;
539da6c28aaSamw 
540da6c28aaSamw 		case ACE_IDENTIFIER_GROUP:
541da6c28aaSamw 			/* regular group */
542da6c28aaSamw 			idtype = SMB_IDMAP_GROUP;
543*f920d1d1SGordon Ross 			id = zace->a_who;
544*f920d1d1SGordon Ross 			/* for smb_acl_bgm_error() ID2SID */
545*f920d1d1SGordon Ross 			sim->sim_id = &zace->a_who;
546da6c28aaSamw 			break;
547da6c28aaSamw 
548da6c28aaSamw 		case ACE_EVERYONE:
549da6c28aaSamw 			idtype = SMB_IDMAP_EVERYONE;
550da6c28aaSamw 			break;
551da6c28aaSamw 
552da6c28aaSamw 		default:
553da6c28aaSamw 			/* user entry */
554da6c28aaSamw 			idtype = SMB_IDMAP_USER;
555*f920d1d1SGordon Ross 			id = zace->a_who;
556*f920d1d1SGordon Ross 			/* for smb_acl_bgm_error() ID2SID */
557*f920d1d1SGordon Ross 			sim->sim_id = &zace->a_who;
558da6c28aaSamw 		}
559da6c28aaSamw 
560da6c28aaSamw 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
561da6c28aaSamw 		    id, idtype);
562da6c28aaSamw 
563da6c28aaSamw 		if (idm_stat != IDMAP_SUCCESS) {
564da6c28aaSamw 			return (idm_stat);
565da6c28aaSamw 		}
566da6c28aaSamw 	}
567da6c28aaSamw 
568*f920d1d1SGordon Ross 	idm_stat = smb_idmap_batch_getmappings(sib, smb_acl_bgm_error);
569da6c28aaSamw 	return (idm_stat);
570da6c28aaSamw }
571da6c28aaSamw 
572da6c28aaSamw /*
573c8ec8eeaSjose borrego  * smb_fsacl_null_empty
57455bf511dSas  *
57555bf511dSas  * NULL DACL means everyone full-access
57655bf511dSas  * Empty DACL means everyone full-deny
577da6c28aaSamw  *
57855bf511dSas  * ZFS ACL must have at least one entry so smb server has
57955bf511dSas  * to simulate the aforementioned expected behavior by adding
58055bf511dSas  * an entry in case the requested DACL is null or empty. Adding
58155bf511dSas  * a everyone full-deny entry has proved to be problematic in
58255bf511dSas  * tests since a deny entry takes precedence over allow entries.
58355bf511dSas  * So, instead of adding a everyone full-deny, an owner ACE with
58455bf511dSas  * owner implicit permissions will be set.
585da6c28aaSamw  */
58655bf511dSas static acl_t *
smb_fsacl_null_empty(boolean_t null)587c8ec8eeaSjose borrego smb_fsacl_null_empty(boolean_t null)
588da6c28aaSamw {
58955bf511dSas 	acl_t *zacl;
59055bf511dSas 	ace_t *zace;
591da6c28aaSamw 
59255bf511dSas 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
59355bf511dSas 	zace = zacl->acl_aclp;
594da6c28aaSamw 
59555bf511dSas 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
59655bf511dSas 	if (null) {
59755bf511dSas 		zace->a_access_mask = ACE_ALL_PERMS;
59855bf511dSas 		zace->a_flags = ACE_EVERYONE;
59955bf511dSas 	} else {
60055bf511dSas 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
60155bf511dSas 		    ACE_READ_ATTRIBUTES;
60255bf511dSas 		zace->a_flags = ACE_OWNER;
60355bf511dSas 	}
604da6c28aaSamw 
60555bf511dSas 	return (zacl);
606da6c28aaSamw }
607da6c28aaSamw 
608da6c28aaSamw /*
60955bf511dSas  * FS ACL (acl_t) Functions
61055bf511dSas  */
61155bf511dSas acl_t *
smb_fsacl_alloc(int acenum,int flags)61255bf511dSas smb_fsacl_alloc(int acenum, int flags)
61355bf511dSas {
61455bf511dSas 	acl_t *acl;
61555bf511dSas 
61655bf511dSas 	acl = acl_alloc(ACE_T);
61755bf511dSas 	acl->acl_cnt = acenum;
61855bf511dSas 	acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
61955bf511dSas 	acl->acl_flags = flags;
62055bf511dSas 	return (acl);
62155bf511dSas }
62255bf511dSas 
62355bf511dSas void
smb_fsacl_free(acl_t * acl)62455bf511dSas smb_fsacl_free(acl_t *acl)
62555bf511dSas {
62655bf511dSas 	if (acl)
62755bf511dSas 		acl_free(acl);
62855bf511dSas }
62955bf511dSas 
63055bf511dSas /*
63155bf511dSas  * smb_fsop_aclmerge
632da6c28aaSamw  *
63355bf511dSas  * smb_fsop_aclread/write routines which interact with filesystem
63455bf511dSas  * work with single ACL. This routine merges given DACL and SACL
63555bf511dSas  * which might have been created during CIFS to FS conversion into
63655bf511dSas  * one single ACL.
63755bf511dSas  */
63855bf511dSas acl_t *
smb_fsacl_merge(acl_t * dacl,acl_t * sacl)63955bf511dSas smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
64055bf511dSas {
64155bf511dSas 	acl_t *acl;
64255bf511dSas 	int dacl_size;
64355bf511dSas 
64455bf511dSas 	ASSERT(dacl);
64555bf511dSas 	ASSERT(sacl);
64655bf511dSas 
64755bf511dSas 	acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
64855bf511dSas 	dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
64955bf511dSas 	bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
65055bf511dSas 	bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
65155bf511dSas 	    sacl->acl_cnt * sacl->acl_entry_size);
65255bf511dSas 
65355bf511dSas 	return (acl);
65455bf511dSas }
65555bf511dSas 
65655bf511dSas /*
65755bf511dSas  * smb_fsacl_split
658da6c28aaSamw  *
65955bf511dSas  * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
66055bf511dSas  * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
66155bf511dSas  * NULL even if they're specified in 'which_acl', which means the target
66255bf511dSas  * doesn't have any access and/or audit ACEs.
663da6c28aaSamw  */
66455bf511dSas void
smb_fsacl_split(acl_t * zacl,acl_t ** dacl,acl_t ** sacl,int which_acl)66555bf511dSas smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
666da6c28aaSamw {
667da6c28aaSamw 	ace_t *zace;
668b819cea2SGordon Ross 	ace_t *access_ace = NULL;
669b819cea2SGordon Ross 	ace_t *audit_ace = NULL;
67055bf511dSas 	int naccess, naudit;
67155bf511dSas 	int get_dacl, get_sacl;
67255bf511dSas 	int i;
67355bf511dSas 
67455bf511dSas 	*dacl = *sacl = NULL;
67555bf511dSas 	naccess = naudit = 0;
67655bf511dSas 	get_dacl = (which_acl & SMB_DACL_SECINFO);
67755bf511dSas 	get_sacl = (which_acl & SMB_SACL_SECINFO);
67855bf511dSas 
67955bf511dSas 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
68055bf511dSas 		if (get_dacl && smb_ace_is_access(zace->a_type))
68155bf511dSas 			naccess++;
68255bf511dSas 		else if (get_sacl && smb_ace_is_audit(zace->a_type))
68355bf511dSas 			naudit++;
68455bf511dSas 	}
68555bf511dSas 
68655bf511dSas 	if (naccess) {
68755bf511dSas 		*dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
68855bf511dSas 		access_ace = (*dacl)->acl_aclp;
68955bf511dSas 	}
69055bf511dSas 
69155bf511dSas 	if (naudit) {
69255bf511dSas 		*sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
69355bf511dSas 		audit_ace = (*sacl)->acl_aclp;
69455bf511dSas 	}
69555bf511dSas 
69655bf511dSas 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
69755bf511dSas 		if (get_dacl && smb_ace_is_access(zace->a_type)) {
69855bf511dSas 			*access_ace = *zace;
69955bf511dSas 			access_ace++;
70055bf511dSas 		} else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
70155bf511dSas 			*audit_ace = *zace;
70255bf511dSas 			audit_ace++;
70355bf511dSas 		}
70455bf511dSas 	}
70555bf511dSas }
70655bf511dSas 
70755bf511dSas /*
70855bf511dSas  * ACE Inheritance Rules
70955bf511dSas  *
71055bf511dSas  * The system propagates inheritable ACEs to child objects according to a
71155bf511dSas  * set of inheritance rules. The system places inherited ACEs in the child's
71255bf511dSas  * DACL according to the preferred order of ACEs in a DACL. For Windows
71355bf511dSas  * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
71455bf511dSas  *
71555bf511dSas  * The following table shows the ACEs inherited by container and noncontainer
71655bf511dSas  * child objects for different combinations of inheritance flags. These
71755bf511dSas  * inheritance rules work the same for both DACLs and SACLs.
71855bf511dSas  *
719*f920d1d1SGordon Ross  * Parent ACE type			Effect on Child ACL
72055bf511dSas  * -----------------------		-------------------
721*f920d1d1SGordon Ross  * OBJECT_INHERIT_ACE only		Noncontainer child objects:
72255bf511dSas  *					Inherited as an effective ACE.
72355bf511dSas  *					Container child objects:
72455bf511dSas  *					Containers inherit an inherit-only ACE
72555bf511dSas  *					unless the NO_PROPAGATE_INHERIT_ACE bit
72655bf511dSas  *					flag is also set.
72755bf511dSas  *
728*f920d1d1SGordon Ross  * CONTAINER_INHERIT_ACE only		Noncontainer child objects:
72955bf511dSas  *					No effect on the child object.
73055bf511dSas  *					Container child objects:
73155bf511dSas  *				The child object inherits an effective ACE.
73255bf511dSas  *				The inherited ACE is inheritable unless the
73355bf511dSas  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set.
73455bf511dSas  *
73555bf511dSas  * CONTAINER_INHERIT_ACE and
736*f920d1d1SGordon Ross  * OBJECT_INHERIT_ACE			Noncontainer child objects:
73755bf511dSas  *					Inherited as an effective ACE.
73855bf511dSas  *					Container child objects:
73955bf511dSas  *				The child object inherits an effective ACE.
74055bf511dSas  *				The inherited ACE is inheritable unless the
74155bf511dSas  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set
74255bf511dSas  *
743*f920d1d1SGordon Ross  * No inheritance flags set	No effect on child container or noncontainer
74455bf511dSas  *				objects.
74555bf511dSas  *
74655bf511dSas  * If an inherited ACE is an effective ACE for the child object, the system
74755bf511dSas  * maps any generic rights to the specific rights for the child object.
74855bf511dSas  * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
74955bf511dSas  * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
75055bf511dSas  * rights or generic SIDs are left unchanged so that they can be mapped
75155bf511dSas  * appropriately when the ACE is inherited by the next generation of child
75255bf511dSas  * objects.
75355bf511dSas  *
75455bf511dSas  * For a case in which a container object inherits an ACE that is both
75555bf511dSas  * effective on the container and inheritable by its descendants, the
75655bf511dSas  * container may inherit two ACEs. This occurs if the inheritable ACE
75755bf511dSas  * contains generic information. The container inherits an inherit-only
75855bf511dSas  * ACE containing the generic information and an effective-only ACE in
75955bf511dSas  * which the generic information has been mapped.
76055bf511dSas  */
76155bf511dSas 
762b819cea2SGordon Ross #ifdef	_KERNEL
76355bf511dSas /*
76455bf511dSas  * smb_fsacl_inherit
76555bf511dSas  *
76655bf511dSas  * Manufacture the inherited ACL from the given ACL considering
76755bf511dSas  * the new object type (file/dir) specified by 'is_dir'. The
76855bf511dSas  * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
76955bf511dSas  * This function implements Windows inheritance rules explained above.
77055bf511dSas  *
77155bf511dSas  * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
77255bf511dSas  */
77355bf511dSas acl_t *
smb_fsacl_inherit(acl_t * dir_zacl,int is_dir,int which_acl,cred_t * cr)7749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, cred_t *cr)
77555bf511dSas {
77655bf511dSas 	boolean_t use_default = B_FALSE;
77755bf511dSas 	int num_inheritable = 0;
778da6c28aaSamw 	int numaces;
77955bf511dSas 	ace_t *dir_zace;
78055bf511dSas 	acl_t *new_zacl;
78155bf511dSas 	ace_t *new_zace;
7829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ksid_t *owner_sid;
7839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ksid_t *group_sid;
7849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uid_t uid;
7859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	gid_t gid;
7869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	owner_sid = crgetsid(cr, KSID_OWNER);
7889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	group_sid = crgetsid(cr, KSID_GROUP);
7899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(owner_sid);
7909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(group_sid);
7919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uid = owner_sid->ks_id;
7929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	gid = group_sid->ks_id;
793da6c28aaSamw 
79455bf511dSas 	num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
795da6c28aaSamw 
79655bf511dSas 	if (num_inheritable == 0) {
79755bf511dSas 		if (which_acl == SMB_DACL_SECINFO) {
79855bf511dSas 			/* No inheritable access ACEs -> default DACL */
79955bf511dSas 			num_inheritable = DEFAULT_DACL_ACENUM;
80055bf511dSas 			use_default = B_TRUE;
80155bf511dSas 		} else {
80255bf511dSas 			return (NULL);
80355bf511dSas 		}
804da6c28aaSamw 	}
805da6c28aaSamw 
80655bf511dSas 	new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
80755bf511dSas 	new_zace = new_zacl->acl_aclp;
808da6c28aaSamw 
80955bf511dSas 	if (use_default) {
81055bf511dSas 		bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
8119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		new_zace->a_who = uid;
81255bf511dSas 		return (new_zacl);
81355bf511dSas 	}
814da6c28aaSamw 
81555bf511dSas 	for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
81655bf511dSas 	    numaces < dir_zacl->acl_cnt;
81755bf511dSas 	    dir_zace++, numaces++) {
81855bf511dSas 		switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
81955bf511dSas 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
82055bf511dSas 			/*
82155bf511dSas 			 * Files inherit an effective ACE.
82255bf511dSas 			 *
82355bf511dSas 			 * Dirs inherit an effective ACE.
82455bf511dSas 			 * The inherited ACE is inheritable unless the
82555bf511dSas 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
82655bf511dSas 			 */
8279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
82855bf511dSas 			new_zace++;
82955bf511dSas 
83055bf511dSas 			if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
83155bf511dSas 			    (ZACE_IS_PROPAGATE(dir_zace))) {
83255bf511dSas 				*new_zace = *dir_zace;
83355bf511dSas 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
83455bf511dSas 				    ACE_INHERITED_ACE);
83555bf511dSas 				new_zace++;
83655bf511dSas 			}
837da6c28aaSamw 			break;
838da6c28aaSamw 
83955bf511dSas 		case ACE_FILE_INHERIT_ACE:
84055bf511dSas 			/*
84155bf511dSas 			 * Files inherit as an effective ACE.
84255bf511dSas 			 *
84355bf511dSas 			 * Dirs inherit an inherit-only ACE
84455bf511dSas 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
84555bf511dSas 			 * flag is also set.
84655bf511dSas 			 */
84755bf511dSas 			if (is_dir == 0) {
8489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				smb_ace_inherit(dir_zace, new_zace, is_dir,
8499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 				    uid, gid);
85055bf511dSas 				new_zace++;
85155bf511dSas 			} else if (ZACE_IS_PROPAGATE(dir_zace)) {
85255bf511dSas 				*new_zace = *dir_zace;
85355bf511dSas 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
85455bf511dSas 				    ACE_INHERITED_ACE);
85555bf511dSas 				new_zace++;
85655bf511dSas 			}
85755bf511dSas 			break;
858da6c28aaSamw 
85955bf511dSas 		case ACE_DIRECTORY_INHERIT_ACE:
86055bf511dSas 			/*
86155bf511dSas 			 * No effect on files
86255bf511dSas 			 *
86355bf511dSas 			 * Dirs inherit an effective ACE.
86455bf511dSas 			 * The inherited ACE is inheritable unless the
86555bf511dSas 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
86655bf511dSas 			 */
86755bf511dSas 			if (is_dir == 0)
86855bf511dSas 				break;
86955bf511dSas 
8709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			smb_ace_inherit(dir_zace, new_zace, is_dir, uid, gid);
87155bf511dSas 			new_zace++;
87255bf511dSas 
87355bf511dSas 			if (ZACE_IS_CREATOR(dir_zace) &&
87455bf511dSas 			    (ZACE_IS_PROPAGATE(dir_zace))) {
87555bf511dSas 				*new_zace = *dir_zace;
87655bf511dSas 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
87755bf511dSas 				    ACE_INHERITED_ACE);
87855bf511dSas 				new_zace++;
87955bf511dSas 			}
880da6c28aaSamw 
88155bf511dSas 			break;
88255bf511dSas 
88355bf511dSas 		default:
884da6c28aaSamw 			break;
885da6c28aaSamw 		}
886da6c28aaSamw 	}
887da6c28aaSamw 
88855bf511dSas 	return (new_zacl);
889da6c28aaSamw }
890b819cea2SGordon Ross #endif	/* _KERNEL */
891da6c28aaSamw 
892da6c28aaSamw /*
89355bf511dSas  * smb_fsacl_from_vsa
894da6c28aaSamw  *
89555bf511dSas  * Converts given vsecattr_t structure to a acl_t structure.
896da6c28aaSamw  *
89755bf511dSas  * The allocated memory for retuned acl_t should be freed by
89855bf511dSas  * calling acl_free().
899da6c28aaSamw  */
900da6c28aaSamw acl_t *
smb_fsacl_from_vsa(vsecattr_t * vsecattr,acl_type_t acl_type)90155bf511dSas smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
902da6c28aaSamw {
90355bf511dSas 	int		aclbsize = 0;	/* size of acl list in bytes */
90455bf511dSas 	int		dfaclbsize = 0;	/* size of default acl list in bytes */
90555bf511dSas 	int		numacls;
90655bf511dSas 	acl_t		*acl_info;
907da6c28aaSamw 
90855bf511dSas 	ASSERT(vsecattr);
909da6c28aaSamw 
91055bf511dSas 	acl_info = acl_alloc(acl_type);
91155bf511dSas 	if (acl_info == NULL)
91255bf511dSas 		return (NULL);
91355bf511dSas 
91455bf511dSas 	acl_info->acl_flags = 0;
91555bf511dSas 
91655bf511dSas 	switch (acl_type) {
91755bf511dSas 
91855bf511dSas 	case ACLENT_T:
91955bf511dSas 		numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
92055bf511dSas 		aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
92155bf511dSas 		dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
92255bf511dSas 
92355bf511dSas 		acl_info->acl_cnt = numacls;
92455bf511dSas 		acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
92555bf511dSas 		    KM_SLEEP);
92655bf511dSas 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
92755bf511dSas 		    aclbsize);
92855bf511dSas 		(void) memcpy((char *)acl_info->acl_aclp + aclbsize,
92955bf511dSas 		    vsecattr->vsa_dfaclentp, dfaclbsize);
93055bf511dSas 
93155bf511dSas 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
93255bf511dSas 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
93355bf511dSas 
93455bf511dSas 		break;
93555bf511dSas 
93655bf511dSas 	case ACE_T:
93755bf511dSas 		aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
93855bf511dSas 		acl_info->acl_cnt = vsecattr->vsa_aclcnt;
93955bf511dSas 		acl_info->acl_flags = vsecattr->vsa_aclflags;
94055bf511dSas 		acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
94155bf511dSas 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
94255bf511dSas 		    aclbsize);
94355bf511dSas 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
94455bf511dSas 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
94555bf511dSas 
94655bf511dSas 		break;
94755bf511dSas 
94855bf511dSas 	default:
94955bf511dSas 		acl_free(acl_info);
95055bf511dSas 		return (NULL);
951da6c28aaSamw 	}
952da6c28aaSamw 
95355bf511dSas 	if (aclbsize && vsecattr->vsa_aclentp)
95455bf511dSas 		kmem_free(vsecattr->vsa_aclentp, aclbsize);
95555bf511dSas 	if (dfaclbsize && vsecattr->vsa_dfaclentp)
95655bf511dSas 		kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
95755bf511dSas 
95855bf511dSas 	return (acl_info);
959da6c28aaSamw }
960da6c28aaSamw 
961da6c28aaSamw /*
96255bf511dSas  * smb_fsacl_to_vsa
963da6c28aaSamw  *
96455bf511dSas  * Converts given acl_t structure to a vsecattr_t structure.
965da6c28aaSamw  *
96655bf511dSas  * IMPORTANT:
96755bf511dSas  * Upon successful return the memory allocated for vsa_aclentp
96855bf511dSas  * should be freed by calling kmem_free(). The size is returned
96955bf511dSas  * in aclbsize.
970da6c28aaSamw  */
97155bf511dSas int
smb_fsacl_to_vsa(acl_t * acl_info,vsecattr_t * vsecattr,int * aclbsize)97255bf511dSas smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
973da6c28aaSamw {
97455bf511dSas 	int		error = 0;
97555bf511dSas 	int		numacls;
97655bf511dSas 	aclent_t	*aclp;
977da6c28aaSamw 
97855bf511dSas 	ASSERT(acl_info);
97955bf511dSas 	ASSERT(vsecattr);
98055bf511dSas 	ASSERT(aclbsize);
981da6c28aaSamw 
98255bf511dSas 	bzero(vsecattr, sizeof (vsecattr_t));
98355bf511dSas 	*aclbsize = 0;
984da6c28aaSamw 
98555bf511dSas 	switch (acl_info->acl_type) {
98655bf511dSas 	case ACLENT_T:
98755bf511dSas 		numacls = acl_info->acl_cnt;
98855bf511dSas 		/*
98955bf511dSas 		 * Minimum ACL size is three entries so might as well
99055bf511dSas 		 * bail out here.  Also limit request size to prevent user
99155bf511dSas 		 * from allocating too much kernel memory.  Maximum size
99255bf511dSas 		 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
99355bf511dSas 		 * for the default ACL part.
99455bf511dSas 		 */
99555bf511dSas 		if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
99655bf511dSas 			error = EINVAL;
99755bf511dSas 			break;
998da6c28aaSamw 		}
999da6c28aaSamw 
100055bf511dSas 		vsecattr->vsa_mask = VSA_ACL;
1001da6c28aaSamw 
100255bf511dSas 		vsecattr->vsa_aclcnt = numacls;
100355bf511dSas 		*aclbsize = numacls * sizeof (aclent_t);
100455bf511dSas 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
100555bf511dSas 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
100655bf511dSas 		    *aclbsize);
1007da6c28aaSamw 
100855bf511dSas 		/* Sort the acl list */
100955bf511dSas 		ksort((caddr_t)vsecattr->vsa_aclentp,
101055bf511dSas 		    vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
1011da6c28aaSamw 
101255bf511dSas 		/* Break into acl and default acl lists */
101355bf511dSas 		for (numacls = 0, aclp = vsecattr->vsa_aclentp;
101455bf511dSas 		    numacls < vsecattr->vsa_aclcnt;
101555bf511dSas 		    aclp++, numacls++) {
101655bf511dSas 			if (aclp->a_type & ACL_DEFAULT)
101755bf511dSas 				break;
101855bf511dSas 		}
1019da6c28aaSamw 
102055bf511dSas 		/* Find where defaults start (if any) */
102155bf511dSas 		if (numacls < vsecattr->vsa_aclcnt) {
102255bf511dSas 			vsecattr->vsa_mask |= VSA_DFACL;
102355bf511dSas 			vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
102455bf511dSas 			vsecattr->vsa_dfaclentp = aclp;
102555bf511dSas 			vsecattr->vsa_aclcnt = numacls;
102655bf511dSas 		}
1027da6c28aaSamw 
102855bf511dSas 		/* Adjust if they're all defaults */
102955bf511dSas 		if (vsecattr->vsa_aclcnt == 0) {
103055bf511dSas 			vsecattr->vsa_mask &= ~VSA_ACL;
103155bf511dSas 			vsecattr->vsa_aclentp = NULL;
103255bf511dSas 		}
1033da6c28aaSamw 
103455bf511dSas 		/* Only directories can have defaults */
103555bf511dSas 		if (vsecattr->vsa_dfaclcnt &&
103655bf511dSas 		    (acl_info->acl_flags & ACL_IS_DIR)) {
103755bf511dSas 			error = ENOTDIR;
103855bf511dSas 		}
1039da6c28aaSamw 
104055bf511dSas 		break;
104155bf511dSas 
104255bf511dSas 	case ACE_T:
104355bf511dSas 		if (acl_info->acl_cnt < 1 ||
104455bf511dSas 		    acl_info->acl_cnt > MAX_ACL_ENTRIES) {
104555bf511dSas 			error = EINVAL;
104655bf511dSas 			break;
1047da6c28aaSamw 		}
1048da6c28aaSamw 
104955bf511dSas 		vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
105055bf511dSas 		vsecattr->vsa_aclcnt = acl_info->acl_cnt;
105155bf511dSas 		vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
105255bf511dSas 		*aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
105355bf511dSas 		vsecattr->vsa_aclentsz = *aclbsize;
105455bf511dSas 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
105555bf511dSas 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
105655bf511dSas 		    *aclbsize);
1057da6c28aaSamw 
105855bf511dSas 		break;
1059da6c28aaSamw 
106055bf511dSas 	default:
106155bf511dSas 		error = EINVAL;
1062da6c28aaSamw 	}
1063da6c28aaSamw 
106455bf511dSas 	return (error);
1065da6c28aaSamw }
1066da6c28aaSamw 
1067b819cea2SGordon Ross #ifdef	_KERNEL
1068da6c28aaSamw /*
106955bf511dSas  * smb_fsacl_inheritable
1070da6c28aaSamw  *
1071da6c28aaSamw  * Checks to see if there are any inheritable ACEs in the
1072da6c28aaSamw  * given ZFS ACL. Returns the number of inheritable ACEs.
1073da6c28aaSamw  *
1074da6c28aaSamw  * The inherited ACL could be different based on the type of
1075da6c28aaSamw  * new object (file/dir) specified by 'is_dir'.
1076da6c28aaSamw  *
1077da6c28aaSamw  * Note that the input ACL is a ZFS ACL not Windows ACL.
1078da6c28aaSamw  */
1079da6c28aaSamw static int
smb_fsacl_inheritable(acl_t * zacl,int is_dir)108055bf511dSas smb_fsacl_inheritable(acl_t *zacl, int is_dir)
1081da6c28aaSamw {
1082da6c28aaSamw 	int numaces;
1083da6c28aaSamw 	int num_inheritable = 0;
1084da6c28aaSamw 	ace_t *zace;
1085da6c28aaSamw 
1086da6c28aaSamw 	if (zacl == NULL)
1087da6c28aaSamw 		return (0);
1088da6c28aaSamw 
1089da6c28aaSamw 	for (numaces = 0, zace = zacl->acl_aclp;
1090da6c28aaSamw 	    numaces < zacl->acl_cnt;
1091da6c28aaSamw 	    zace++, numaces++) {
1092da6c28aaSamw 		switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
1093da6c28aaSamw 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
1094da6c28aaSamw 			/*
1095da6c28aaSamw 			 * Files inherit an effective ACE.
1096da6c28aaSamw 			 *
1097da6c28aaSamw 			 * Dirs inherit an effective ACE.
1098da6c28aaSamw 			 * The inherited ACE is inheritable unless the
1099da6c28aaSamw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
1100da6c28aaSamw 			 */
1101da6c28aaSamw 			num_inheritable++;
1102da6c28aaSamw 
1103da6c28aaSamw 			if (is_dir && ZACE_IS_CREATOR(zace) &&
1104da6c28aaSamw 			    (ZACE_IS_PROPAGATE(zace))) {
1105da6c28aaSamw 				num_inheritable++;
1106da6c28aaSamw 			}
1107da6c28aaSamw 			break;
1108da6c28aaSamw 
1109da6c28aaSamw 		case ACE_FILE_INHERIT_ACE:
1110da6c28aaSamw 			/*
1111da6c28aaSamw 			 * Files inherit as an effective ACE.
1112da6c28aaSamw 			 *
1113da6c28aaSamw 			 * Dirs inherit an inherit-only ACE
1114da6c28aaSamw 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
1115da6c28aaSamw 			 * flag is also set.
1116da6c28aaSamw 			 */
1117da6c28aaSamw 			if (is_dir == 0)
1118da6c28aaSamw 				num_inheritable++;
1119da6c28aaSamw 			else if (ZACE_IS_PROPAGATE(zace))
1120da6c28aaSamw 				num_inheritable++;
1121da6c28aaSamw 			break;
1122da6c28aaSamw 
1123da6c28aaSamw 		case ACE_DIRECTORY_INHERIT_ACE:
1124da6c28aaSamw 			/*
1125da6c28aaSamw 			 * No effect on files
1126da6c28aaSamw 			 *
1127da6c28aaSamw 			 * Dirs inherit an effective ACE.
1128da6c28aaSamw 			 * The inherited ACE is inheritable unless the
1129da6c28aaSamw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
1130da6c28aaSamw 			 */
1131da6c28aaSamw 			if (is_dir == 0)
1132da6c28aaSamw 				break;
1133da6c28aaSamw 
1134da6c28aaSamw 			num_inheritable++;
1135da6c28aaSamw 
1136da6c28aaSamw 			if (ZACE_IS_CREATOR(zace) &&
1137da6c28aaSamw 			    (ZACE_IS_PROPAGATE(zace)))
1138da6c28aaSamw 				num_inheritable++;
1139da6c28aaSamw 			break;
1140da6c28aaSamw 
1141da6c28aaSamw 		default:
1142da6c28aaSamw 			break;
1143da6c28aaSamw 		}
1144da6c28aaSamw 	}
1145da6c28aaSamw 
1146da6c28aaSamw 	return (num_inheritable);
1147da6c28aaSamw }
1148b819cea2SGordon Ross #endif	/* _KERNEL */
1149da6c28aaSamw 
115055bf511dSas 
1151da6c28aaSamw /*
115255bf511dSas  * ACE Functions
1153da6c28aaSamw  */
1154da6c28aaSamw 
1155da6c28aaSamw /*
115655bf511dSas  * This is generic (ACL version 2) vs. object-specific
115755bf511dSas  * (ACL version 4) ACE types.
1158da6c28aaSamw  */
115955bf511dSas boolean_t
smb_ace_is_generic(int type)116055bf511dSas smb_ace_is_generic(int type)
1161da6c28aaSamw {
116255bf511dSas 	switch (type) {
116355bf511dSas 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
116455bf511dSas 	case ACE_ACCESS_DENIED_ACE_TYPE:
116555bf511dSas 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
116655bf511dSas 	case ACE_SYSTEM_ALARM_ACE_TYPE:
116755bf511dSas 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
116855bf511dSas 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
116955bf511dSas 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
117055bf511dSas 	case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
117155bf511dSas 		return (B_TRUE);
1172da6c28aaSamw 
117355bf511dSas 	default:
117455bf511dSas 		break;
1175da6c28aaSamw 	}
1176da6c28aaSamw 
117755bf511dSas 	return (B_FALSE);
117855bf511dSas }
1179da6c28aaSamw 
118055bf511dSas boolean_t
smb_ace_is_access(int type)118155bf511dSas smb_ace_is_access(int type)
118255bf511dSas {
118355bf511dSas 	switch (type) {
118455bf511dSas 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
118555bf511dSas 	case ACE_ACCESS_DENIED_ACE_TYPE:
118655bf511dSas 	case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
118755bf511dSas 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
118855bf511dSas 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
118955bf511dSas 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
119055bf511dSas 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
119155bf511dSas 	case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
119255bf511dSas 	case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
119355bf511dSas 		return (B_TRUE);
1194da6c28aaSamw 
119555bf511dSas 	default:
119655bf511dSas 		break;
119755bf511dSas 	}
1198da6c28aaSamw 
119955bf511dSas 	return (B_FALSE);
120055bf511dSas }
1201da6c28aaSamw 
120255bf511dSas boolean_t
smb_ace_is_audit(int type)120355bf511dSas smb_ace_is_audit(int type)
120455bf511dSas {
120555bf511dSas 	switch (type) {
120655bf511dSas 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
120755bf511dSas 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
120855bf511dSas 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
120955bf511dSas 	case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
121055bf511dSas 		return (B_TRUE);
1211da6c28aaSamw 
121255bf511dSas 	default:
121355bf511dSas 		break;
121455bf511dSas 	}
1215da6c28aaSamw 
121655bf511dSas 	return (B_FALSE);
121755bf511dSas }
1218da6c28aaSamw 
121955bf511dSas /*
122055bf511dSas  * smb_ace_len
122155bf511dSas  *
122255bf511dSas  * Returns the length of the given ACE as it appears in an
122355bf511dSas  * ACL on the wire (i.e. a flat buffer which contains the SID)
122455bf511dSas  */
122555bf511dSas static uint16_t
smb_ace_len(smb_ace_t * ace)122655bf511dSas smb_ace_len(smb_ace_t *ace)
122755bf511dSas {
122855bf511dSas 	ASSERT(ace);
122955bf511dSas 	ASSERT(ace->se_sid);
1230da6c28aaSamw 
123155bf511dSas 	if (ace == NULL)
123255bf511dSas 		return (0);
1233da6c28aaSamw 
123455bf511dSas 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
12356537f381Sas 	    smb_sid_len(ace->se_sid));
1236da6c28aaSamw }
1237da6c28aaSamw 
1238b819cea2SGordon Ross #ifdef	_KERNEL
1239da6c28aaSamw static void
smb_ace_inherit(ace_t * dir_zace,ace_t * zace,int is_dir,uid_t uid,gid_t gid)12409fb67ea3Safshin 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)
1241da6c28aaSamw {
1242da6c28aaSamw 	*zace = *dir_zace;
1243c8ec8eeaSjose borrego 
1244c8ec8eeaSjose borrego 	/* This is an effective ACE so remove the inherit_only flag */
1245c8ec8eeaSjose borrego 	zace->a_flags &= ~ACE_INHERIT_ONLY_ACE;
1246c8ec8eeaSjose borrego 	/* Mark this ACE as inherited */
1247c8ec8eeaSjose borrego 	zace->a_flags |= ACE_INHERITED_ACE;
1248c8ec8eeaSjose borrego 
1249c8ec8eeaSjose borrego 	/*
1250c8ec8eeaSjose borrego 	 * If this is a file or NO_PROPAGATE is set then this inherited
1251c8ec8eeaSjose borrego 	 * ACE is not inheritable so clear the inheritance flags
1252c8ec8eeaSjose borrego 	 */
1253da6c28aaSamw 	if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
1254da6c28aaSamw 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1255da6c28aaSamw 
1256da6c28aaSamw 	/*
1257c8ec8eeaSjose borrego 	 * Replace creator owner/group ACEs with actual owner/group ACEs.
12589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * This is a non-inheritable effective ACE.
1259da6c28aaSamw 	 */
1260da6c28aaSamw 	if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
12619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_who = uid;
1262c8ec8eeaSjose borrego 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1263da6c28aaSamw 	} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
12649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_who = gid;
12659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		zace->a_flags |= ACE_IDENTIFIER_GROUP;
1266c8ec8eeaSjose borrego 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
1267da6c28aaSamw 	}
1268da6c28aaSamw }
1269b819cea2SGordon Ross #endif	/* _KERNEL */
1270da6c28aaSamw 
127155bf511dSas /*
127255bf511dSas  * smb_ace_mask_g2s
127355bf511dSas  *
127455bf511dSas  * Converts generic access bits in the given mask (if any)
127555bf511dSas  * to file specific bits. Generic access masks shouldn't be
127655bf511dSas  * stored in filesystem ACEs.
127755bf511dSas  */
127855bf511dSas static uint32_t
smb_ace_mask_g2s(uint32_t mask)127955bf511dSas smb_ace_mask_g2s(uint32_t mask)
128055bf511dSas {
128155bf511dSas 	if (mask & GENERIC_ALL) {
128255bf511dSas 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
128355bf511dSas 		    | GENERIC_EXECUTE);
128455bf511dSas 
128555bf511dSas 		mask |= FILE_ALL_ACCESS;
128655bf511dSas 		return (mask);
128755bf511dSas 	}
128855bf511dSas 
128955bf511dSas 	if (mask & GENERIC_READ) {
129055bf511dSas 		mask &= ~GENERIC_READ;
129155bf511dSas 		mask |= FILE_GENERIC_READ;
129255bf511dSas 	}
129355bf511dSas 
129455bf511dSas 	if (mask & GENERIC_WRITE) {
129555bf511dSas 		mask &= ~GENERIC_WRITE;
129655bf511dSas 		mask |= FILE_GENERIC_WRITE;
129755bf511dSas 	}
129855bf511dSas 
129955bf511dSas 	if (mask & GENERIC_EXECUTE) {
130055bf511dSas 		mask &= ~GENERIC_EXECUTE;
130155bf511dSas 		mask |= FILE_GENERIC_EXECUTE;
130255bf511dSas 	}
130355bf511dSas 
130455bf511dSas 	return (mask);
130555bf511dSas }
130655bf511dSas 
1307c8ec8eeaSjose borrego /*
1308c8ec8eeaSjose borrego  * smb_ace_flags_tozfs
1309c8ec8eeaSjose borrego  *
1310c8ec8eeaSjose borrego  * This function maps the flags which have different values
1311c8ec8eeaSjose borrego  * in Windows and Solaris. The ones with the same value are
1312c8ec8eeaSjose borrego  * transferred untouched.
1313c8ec8eeaSjose borrego  */
1314da6c28aaSamw static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)1315c8ec8eeaSjose borrego smb_ace_flags_tozfs(uint8_t c_flags)
1316da6c28aaSamw {
1317da6c28aaSamw 	uint16_t z_flags = 0;
1318da6c28aaSamw 
1319da6c28aaSamw 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
1320da6c28aaSamw 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
1321da6c28aaSamw 
1322da6c28aaSamw 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
1323da6c28aaSamw 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
1324da6c28aaSamw 
1325da6c28aaSamw 	if (c_flags & INHERITED_ACE)
1326da6c28aaSamw 		z_flags |= ACE_INHERITED_ACE;
1327da6c28aaSamw 
1328c8ec8eeaSjose borrego 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
1329da6c28aaSamw 
1330da6c28aaSamw 	return (z_flags);
1331da6c28aaSamw }
1332da6c28aaSamw 
1333da6c28aaSamw static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)1334da6c28aaSamw smb_ace_flags_fromzfs(uint16_t z_flags)
1335da6c28aaSamw {
1336da6c28aaSamw 	uint8_t c_flags;
1337da6c28aaSamw 
1338da6c28aaSamw 	c_flags = z_flags & ACE_INHERIT_FLAGS;
1339da6c28aaSamw 
1340da6c28aaSamw 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
1341da6c28aaSamw 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
1342da6c28aaSamw 
1343da6c28aaSamw 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
1344da6c28aaSamw 		c_flags |= FAILED_ACCESS_ACE_FLAG;
1345da6c28aaSamw 
1346da6c28aaSamw 	if (z_flags & ACE_INHERITED_ACE)
1347da6c28aaSamw 		c_flags |= INHERITED_ACE;
1348da6c28aaSamw 
1349da6c28aaSamw 	return (c_flags);
1350da6c28aaSamw }
1351da6c28aaSamw 
135255bf511dSas static boolean_t
smb_ace_isvalid(smb_ace_t * ace,int which_acl)135355bf511dSas smb_ace_isvalid(smb_ace_t *ace, int which_acl)
1354da6c28aaSamw {
135555bf511dSas 	uint16_t min_len;
1356da6c28aaSamw 
135755bf511dSas 	min_len = sizeof (smb_acehdr_t);
1358da6c28aaSamw 
135955bf511dSas 	if (ace->se_hdr.se_bsize < min_len)
136055bf511dSas 		return (B_FALSE);
1361da6c28aaSamw 
136255bf511dSas 	if (smb_ace_is_access(ace->se_hdr.se_type) &&
136355bf511dSas 	    (which_acl != SMB_DACL_SECINFO))
136455bf511dSas 		return (B_FALSE);
1365da6c28aaSamw 
136655bf511dSas 	if (smb_ace_is_audit(ace->se_hdr.se_type) &&
136755bf511dSas 	    (which_acl != SMB_SACL_SECINFO))
136855bf511dSas 		return (B_FALSE);
1369da6c28aaSamw 
137055bf511dSas 	if (smb_ace_is_generic(ace->se_hdr.se_type)) {
13716537f381Sas 		if (!smb_sid_isvalid(ace->se_sid))
137255bf511dSas 			return (B_FALSE);
1373da6c28aaSamw 
137455bf511dSas 		min_len += sizeof (ace->se_mask);
13756537f381Sas 		min_len += smb_sid_len(ace->se_sid);
1376da6c28aaSamw 
137755bf511dSas 		if (ace->se_hdr.se_bsize < min_len)
137855bf511dSas 			return (B_FALSE);
1379da6c28aaSamw 	}
1380da6c28aaSamw 
138155bf511dSas 	/*
138255bf511dSas 	 * object-specific ACE validation will be added later.
138355bf511dSas 	 */
138455bf511dSas 	return (B_TRUE);
1385da6c28aaSamw }
1386