129bd2886SAlan Wright /*
229bd2886SAlan Wright  * CDDL HEADER START
329bd2886SAlan Wright  *
429bd2886SAlan Wright  * The contents of this file are subject to the terms of the
529bd2886SAlan Wright  * Common Development and Distribution License (the "License").
629bd2886SAlan Wright  * You may not use this file except in compliance with the License.
729bd2886SAlan Wright  *
829bd2886SAlan Wright  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
929bd2886SAlan Wright  * or http://www.opensolaris.org/os/licensing.
1029bd2886SAlan Wright  * See the License for the specific language governing permissions
1129bd2886SAlan Wright  * and limitations under the License.
1229bd2886SAlan Wright  *
1329bd2886SAlan Wright  * When distributing Covered Code, include this CDDL HEADER in each
1429bd2886SAlan Wright  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1529bd2886SAlan Wright  * If applicable, add the following below this CDDL HEADER, with the
1629bd2886SAlan Wright  * fields enclosed by brackets "[]" replaced with your own identifying
1729bd2886SAlan Wright  * information: Portions Copyright [yyyy] [name of copyright owner]
1829bd2886SAlan Wright  *
1929bd2886SAlan Wright  * CDDL HEADER END
2029bd2886SAlan Wright  */
2129bd2886SAlan Wright /*
22f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2329bd2886SAlan Wright  * Use is subject to license terms.
24*f920d1d1SGordon Ross  *
25*f920d1d1SGordon Ross  * Copyright 2023 RackTop Systems, Inc.
26*f920d1d1SGordon Ross  */
27*f920d1d1SGordon Ross 
28*f920d1d1SGordon Ross /*
29*f920d1d1SGordon Ross  * SMB server interfaces for ACL conversion (smb_acl_...)
30*f920d1d1SGordon Ross  *
31*f920d1d1SGordon Ross  * There are two variants of this interface:
32*f920d1d1SGordon Ross  * This is the library version.  See also:
33*f920d1d1SGordon Ross  * $SRC/uts/common/fs/smbsrv/smb_acl.c
3429bd2886SAlan Wright  */
3529bd2886SAlan Wright 
3629bd2886SAlan Wright #include <stddef.h>
3729bd2886SAlan Wright #include <strings.h>
38*f920d1d1SGordon Ross #include <syslog.h>
3929bd2886SAlan Wright #include <assert.h>
4029bd2886SAlan Wright 
41bbf6f00cSJordan Brown #include <smbsrv/smb.h>
4229bd2886SAlan Wright #include <smbsrv/smb_sid.h>
4329bd2886SAlan Wright #include <smbsrv/smb_idmap.h>
4429bd2886SAlan Wright 
4529bd2886SAlan Wright #define	ACE_ALL_TYPES	0x001F
4629bd2886SAlan Wright 
4729bd2886SAlan Wright /*
4829bd2886SAlan Wright  * ACE groups within a DACL
4929bd2886SAlan Wright  *
5029bd2886SAlan Wright  * This is from lower to higher ACE order priority
5129bd2886SAlan Wright  */
5229bd2886SAlan Wright #define	SMB_AG_START		0
5329bd2886SAlan Wright #define	SMB_AG_ALW_INHRT	0
5429bd2886SAlan Wright #define	SMB_AG_DNY_INHRT	1
5529bd2886SAlan Wright #define	SMB_AG_ALW_DRCT		2
5629bd2886SAlan Wright #define	SMB_AG_DNY_DRCT		3
5729bd2886SAlan Wright #define	SMB_AG_NUM		4
5829bd2886SAlan Wright 
5929bd2886SAlan Wright #define	DEFAULT_DACL_ACENUM	2
6029bd2886SAlan Wright acl_t *acl_alloc(enum acl_type);
6129bd2886SAlan Wright 
62f96bd5c8SAlan Wright static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
6329bd2886SAlan Wright static acl_t *smb_fsacl_null_empty(boolean_t);
64*f920d1d1SGordon Ross static boolean_t smb_ace_isvalid(smb_ace_t *, int);
6529bd2886SAlan Wright static uint16_t smb_ace_len(smb_ace_t *);
6629bd2886SAlan Wright static uint32_t smb_ace_mask_g2s(uint32_t);
6729bd2886SAlan Wright static uint16_t smb_ace_flags_tozfs(uint8_t);
6829bd2886SAlan Wright static uint8_t smb_ace_flags_fromzfs(uint16_t);
69f96bd5c8SAlan Wright static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
7029bd2886SAlan Wright 
7129bd2886SAlan Wright smb_acl_t *
smb_acl_alloc(uint8_t revision,uint16_t bsize,uint16_t acecnt)7229bd2886SAlan Wright smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
7329bd2886SAlan Wright {
7429bd2886SAlan Wright 	smb_acl_t *acl;
7529bd2886SAlan Wright 	int size;
7629bd2886SAlan Wright 
7729bd2886SAlan Wright 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
7829bd2886SAlan Wright 	if ((acl = malloc(size)) == NULL)
7929bd2886SAlan Wright 		return (NULL);
8029bd2886SAlan Wright 
8129bd2886SAlan Wright 	acl->sl_revision = revision;
8229bd2886SAlan Wright 	acl->sl_bsize = bsize;
8329bd2886SAlan Wright 	acl->sl_acecnt = acecnt;
8429bd2886SAlan Wright 	acl->sl_aces = (smb_ace_t *)(acl + 1);
8529bd2886SAlan Wright 
8629bd2886SAlan Wright 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
8729bd2886SAlan Wright 	    offsetof(smb_ace_t, se_sln));
8829bd2886SAlan Wright 	return (acl);
8929bd2886SAlan Wright }
9029bd2886SAlan Wright 
9129bd2886SAlan Wright void
smb_acl_free(smb_acl_t * acl)9229bd2886SAlan Wright smb_acl_free(smb_acl_t *acl)
9329bd2886SAlan Wright {
9429bd2886SAlan Wright 	int i;
9529bd2886SAlan Wright 	void *ace;
9629bd2886SAlan Wright 
9729bd2886SAlan Wright 	if (acl == NULL)
9829bd2886SAlan Wright 		return;
9929bd2886SAlan Wright 
10029bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++)
10129bd2886SAlan Wright 		smb_sid_free(acl->sl_aces[i].se_sid);
10229bd2886SAlan Wright 
10329bd2886SAlan Wright 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
10429bd2886SAlan Wright 		list_remove(&acl->sl_sorted, ace);
10529bd2886SAlan Wright 	list_destroy(&acl->sl_sorted);
10629bd2886SAlan Wright 	free(acl);
10729bd2886SAlan Wright }
10829bd2886SAlan Wright 
10929bd2886SAlan Wright /*
11029bd2886SAlan Wright  * smb_acl_len
11129bd2886SAlan Wright  *
11229bd2886SAlan Wright  * Returns the size of given ACL in bytes. Note that this
11329bd2886SAlan Wright  * is not an in-memory size, it's the ACL's size as it would
11429bd2886SAlan Wright  * appear on the wire
11529bd2886SAlan Wright  */
11629bd2886SAlan Wright uint16_t
smb_acl_len(smb_acl_t * acl)11729bd2886SAlan Wright smb_acl_len(smb_acl_t *acl)
11829bd2886SAlan Wright {
11929bd2886SAlan Wright 	return ((acl) ? acl->sl_bsize : 0);
12029bd2886SAlan Wright }
12129bd2886SAlan Wright 
12229bd2886SAlan Wright boolean_t
smb_acl_isvalid(smb_acl_t * acl,int which_acl)123*f920d1d1SGordon Ross smb_acl_isvalid(smb_acl_t *acl, int which_acl)
12429bd2886SAlan Wright {
125*f920d1d1SGordon Ross 	int i;
126*f920d1d1SGordon Ross 
12729bd2886SAlan Wright 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
12829bd2886SAlan Wright 		return (B_FALSE);
12929bd2886SAlan Wright 
13029bd2886SAlan Wright 	if (acl->sl_revision != ACL_REVISION) {
13129bd2886SAlan Wright 		/*
13229bd2886SAlan Wright 		 * we are rejecting ACLs with object-specific ACEs for now
13329bd2886SAlan Wright 		 */
13429bd2886SAlan Wright 		return (B_FALSE);
13529bd2886SAlan Wright 	}
13629bd2886SAlan Wright 
137*f920d1d1SGordon Ross 	for (i = 0; i < acl->sl_acecnt; i++) {
138*f920d1d1SGordon Ross 		if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
139*f920d1d1SGordon Ross 			return (B_FALSE);
140*f920d1d1SGordon Ross 	}
141*f920d1d1SGordon Ross 
14229bd2886SAlan Wright 	return (B_TRUE);
14329bd2886SAlan Wright }
14429bd2886SAlan Wright 
14529bd2886SAlan Wright /*
14629bd2886SAlan Wright  * smb_acl_sort
14729bd2886SAlan Wright  *
14829bd2886SAlan Wright  * Sorts the given ACL in place if it needs to be sorted.
14929bd2886SAlan Wright  *
15029bd2886SAlan Wright  * The following is an excerpt from MSDN website.
15129bd2886SAlan Wright  *
15229bd2886SAlan Wright  * Order of ACEs in a DACL
15329bd2886SAlan Wright  *
15429bd2886SAlan Wright  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
15529bd2886SAlan Wright  * is simple: In a DACL, all access-denied ACEs should precede any
15629bd2886SAlan Wright  * access-allowed ACEs.
15729bd2886SAlan Wright  *
15829bd2886SAlan Wright  * For Windows 2000 or later, the proper order of ACEs is more complicated
15929bd2886SAlan Wright  * because of the introduction of object-specific ACEs and automatic
16029bd2886SAlan Wright  * inheritance.
16129bd2886SAlan Wright  *
16229bd2886SAlan Wright  * The following describes the preferred order:
16329bd2886SAlan Wright  *
16429bd2886SAlan Wright  * To ensure that noninherited ACEs have precedence over inherited ACEs,
16529bd2886SAlan Wright  * place all noninherited ACEs in a group before any inherited ACEs. This
16629bd2886SAlan Wright  * ordering ensures, for example, that a noninherited access-denied ACE
16729bd2886SAlan Wright  * is enforced regardless of any inherited ACE that allows access.
16829bd2886SAlan Wright  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
16929bd2886SAlan Wright  * according to ACE type, as the following shows:
17083163ba8SToomas Soome  *	. Access-denied ACEs that apply to the object itself
17183163ba8SToomas Soome  *	. Access-denied ACEs that apply to a subobject of the
17229bd2886SAlan Wright  *	  object, such as a property set or property
17383163ba8SToomas Soome  *	. Access-allowed ACEs that apply to the object itself
17483163ba8SToomas Soome  *	. Access-allowed ACEs that apply to a subobject of the object
17529bd2886SAlan Wright  *
17629bd2886SAlan Wright  * So, here is the desired ACE order
17729bd2886SAlan Wright  *
17829bd2886SAlan Wright  * deny-direct, allow-direct, deny-inherited, allow-inherited
17929bd2886SAlan Wright  *
18029bd2886SAlan Wright  * Of course, not all ACE types are required in an ACL.
18129bd2886SAlan Wright  */
18229bd2886SAlan Wright void
smb_acl_sort(smb_acl_t * acl)18329bd2886SAlan Wright smb_acl_sort(smb_acl_t *acl)
18429bd2886SAlan Wright {
18529bd2886SAlan Wright 	list_t ace_grps[SMB_AG_NUM];
18629bd2886SAlan Wright 	list_t *alist;
18729bd2886SAlan Wright 	smb_ace_t *ace;
18829bd2886SAlan Wright 	uint8_t ace_flags;
18929bd2886SAlan Wright 	int ag, i;
19029bd2886SAlan Wright 
19129bd2886SAlan Wright 	assert(acl);
19229bd2886SAlan Wright 
19329bd2886SAlan Wright 	if (acl->sl_acecnt == 0) {
19429bd2886SAlan Wright 		/*
19529bd2886SAlan Wright 		 * ACL with no entry is a valid ACL and it means
19629bd2886SAlan Wright 		 * no access for anybody.
19729bd2886SAlan Wright 		 */
19829bd2886SAlan Wright 		return;
19929bd2886SAlan Wright 	}
20029bd2886SAlan Wright 
20129bd2886SAlan Wright 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
20229bd2886SAlan Wright 		list_create(&ace_grps[i], sizeof (smb_ace_t),
20329bd2886SAlan Wright 		    offsetof(smb_ace_t, se_sln));
20429bd2886SAlan Wright 	}
20529bd2886SAlan Wright 
20629bd2886SAlan Wright 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
20729bd2886SAlan Wright 		ace_flags = ace->se_hdr.se_flags;
20829bd2886SAlan Wright 
20929bd2886SAlan Wright 		switch (ace->se_hdr.se_type) {
21029bd2886SAlan Wright 		case ACCESS_DENIED_ACE_TYPE:
21129bd2886SAlan Wright 			ag = (ace_flags & INHERITED_ACE) ?
21229bd2886SAlan Wright 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
21329bd2886SAlan Wright 			break;
21429bd2886SAlan Wright 
21529bd2886SAlan Wright 		case ACCESS_ALLOWED_ACE_TYPE:
21629bd2886SAlan Wright 			ag = (ace_flags & INHERITED_ACE) ?
21729bd2886SAlan Wright 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
21829bd2886SAlan Wright 			break;
21929bd2886SAlan Wright 
22029bd2886SAlan Wright 		default:
22129bd2886SAlan Wright 			/*
22229bd2886SAlan Wright 			 * This is the lowest priority group so we put
22329bd2886SAlan Wright 			 * evertything unknown here.
22429bd2886SAlan Wright 			 */
22529bd2886SAlan Wright 			ag = SMB_AG_ALW_INHRT;
22629bd2886SAlan Wright 			break;
22729bd2886SAlan Wright 		}
22829bd2886SAlan Wright 
22929bd2886SAlan Wright 		/* Add the ACE to the selected group */
23029bd2886SAlan Wright 		list_insert_tail(&ace_grps[ag], ace);
23129bd2886SAlan Wright 	}
23229bd2886SAlan Wright 
23329bd2886SAlan Wright 	/*
23429bd2886SAlan Wright 	 * start with highest priority ACE group and append
23529bd2886SAlan Wright 	 * the ACEs to the ACL.
23629bd2886SAlan Wright 	 */
23729bd2886SAlan Wright 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
23829bd2886SAlan Wright 		alist = &ace_grps[i];
23929bd2886SAlan Wright 		while ((ace = list_head(alist)) != NULL) {
24029bd2886SAlan Wright 			list_remove(alist, ace);
24129bd2886SAlan Wright 			list_insert_tail(&acl->sl_sorted, ace);
24229bd2886SAlan Wright 		}
24329bd2886SAlan Wright 		list_destroy(alist);
24429bd2886SAlan Wright 	}
24529bd2886SAlan Wright }
24629bd2886SAlan Wright 
247*f920d1d1SGordon Ross /*
248*f920d1d1SGordon Ross  * Error handling call-back for smb_idmap_batch_getmappings.
249*f920d1d1SGordon Ross  * Would be nice if this could report the path, but that's not
250*f920d1d1SGordon Ross  * passed down here.  For now, use a dtrace fbt probe here.
251*f920d1d1SGordon Ross  */
252*f920d1d1SGordon Ross static void
smb_acl_bgm_error(smb_idmap_batch_t * sib,smb_idmap_t * sim)253*f920d1d1SGordon Ross smb_acl_bgm_error(smb_idmap_batch_t *sib, smb_idmap_t *sim)
254*f920d1d1SGordon Ross {
255*f920d1d1SGordon Ross 
256*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) != 0)
257*f920d1d1SGordon Ross 		return;
258*f920d1d1SGordon Ross 
259*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
260*f920d1d1SGordon Ross 		/*
261*f920d1d1SGordon Ross 		 * Note: The ID and type we asked idmap to map
262*f920d1d1SGordon Ross 		 * were saved in *sim_id and sim_idtype.
263*f920d1d1SGordon Ross 		 */
264*f920d1d1SGordon Ross 		uid_t id = (sim->sim_id == NULL) ? (uid_t)-1 : *sim->sim_id;
265*f920d1d1SGordon Ross 		syslog(LOG_ERR, "!smb_acl: Can't get SID for "
266*f920d1d1SGordon Ross 		    "ID=%u type=%d, status=%d",
267*f920d1d1SGordon Ross 		    id, sim->sim_idtype, sim->sim_stat);
268*f920d1d1SGordon Ross 	}
269*f920d1d1SGordon Ross 
270*f920d1d1SGordon Ross 	if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
271*f920d1d1SGordon Ross 		syslog(LOG_ERR, "!smb_acl: Can't get ID for "
272*f920d1d1SGordon Ross 		    "SID %s-%u, status=%d",
273*f920d1d1SGordon Ross 		    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
274*f920d1d1SGordon Ross 	}
275*f920d1d1SGordon Ross }
276*f920d1d1SGordon Ross 
27729bd2886SAlan Wright /*
27829bd2886SAlan Wright  * smb_acl_from_zfs
27929bd2886SAlan Wright  *
28029bd2886SAlan Wright  * Converts given ZFS ACL to a Windows ACL.
28129bd2886SAlan Wright  *
28229bd2886SAlan Wright  * A pointer to allocated memory for the Windows ACL will be
28329bd2886SAlan Wright  * returned upon successful conversion.
28429bd2886SAlan Wright  */
28529bd2886SAlan Wright smb_acl_t *
smb_acl_from_zfs(acl_t * zacl)286f96bd5c8SAlan Wright smb_acl_from_zfs(acl_t *zacl)
28729bd2886SAlan Wright {
28829bd2886SAlan Wright 	ace_t *zace;
28929bd2886SAlan Wright 	int numaces;
29029bd2886SAlan Wright 	smb_acl_t *acl;
29129bd2886SAlan Wright 	smb_ace_t *ace;
29229bd2886SAlan Wright 	smb_idmap_batch_t sib;
29329bd2886SAlan Wright 	smb_idmap_t *sim;
29429bd2886SAlan Wright 	idmap_stat idm_stat;
29529bd2886SAlan Wright 
29629bd2886SAlan Wright 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
29729bd2886SAlan Wright 	    SMB_IDMAP_ID2SID);
29829bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS)
29929bd2886SAlan Wright 		return (NULL);
30029bd2886SAlan Wright 
301*f920d1d1SGordon Ross 	/*
302*f920d1d1SGordon Ross 	 * Note that smb_fsacl_getsids sets up references in
303*f920d1d1SGordon Ross 	 * sib.sib_maps to the zace->a_who fields that live
304*f920d1d1SGordon Ross 	 * until smb_idmap_batch_destroy is called.
305*f920d1d1SGordon Ross 	 */
306f96bd5c8SAlan Wright 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
30729bd2886SAlan Wright 		smb_idmap_batch_destroy(&sib);
30829bd2886SAlan Wright 		return (NULL);
30929bd2886SAlan Wright 	}
31029bd2886SAlan Wright 
31129bd2886SAlan Wright 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
31229bd2886SAlan Wright 
31329bd2886SAlan Wright 	sim = sib.sib_maps;
31429bd2886SAlan Wright 	for (numaces = 0, zace = zacl->acl_aclp;
31529bd2886SAlan Wright 	    numaces < zacl->acl_cnt;
31629bd2886SAlan Wright 	    zace++, numaces++, sim++) {
31729bd2886SAlan Wright 		assert(sim->sim_sid);
31829bd2886SAlan Wright 		if (sim->sim_sid == NULL) {
31929bd2886SAlan Wright 			smb_acl_free(acl);
32029bd2886SAlan Wright 			acl = NULL;
32129bd2886SAlan Wright 			break;
32229bd2886SAlan Wright 		}
32329bd2886SAlan Wright 
32429bd2886SAlan Wright 		ace = &acl->sl_aces[numaces];
32529bd2886SAlan Wright 		ace->se_hdr.se_type = zace->a_type;
32629bd2886SAlan Wright 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
32729bd2886SAlan Wright 		ace->se_mask = zace->a_access_mask;
32829bd2886SAlan Wright 		ace->se_sid = smb_sid_dup(sim->sim_sid);
32929bd2886SAlan Wright 		ace->se_hdr.se_bsize = smb_ace_len(ace);
33029bd2886SAlan Wright 
33129bd2886SAlan Wright 		acl->sl_bsize += ace->se_hdr.se_bsize;
33229bd2886SAlan Wright 	}
33329bd2886SAlan Wright 
33429bd2886SAlan Wright 	smb_idmap_batch_destroy(&sib);
33529bd2886SAlan Wright 	return (acl);
33629bd2886SAlan Wright }
33729bd2886SAlan Wright 
33829bd2886SAlan Wright /*
33929bd2886SAlan Wright  * smb_acl_to_zfs
34029bd2886SAlan Wright  *
34129bd2886SAlan Wright  * Converts given Windows ACL to a ZFS ACL.
34229bd2886SAlan Wright  *
34329bd2886SAlan Wright  * fs_acl will contain a pointer to the created ZFS ACL.
34429bd2886SAlan Wright  * The allocated memory should be freed by calling
34529bd2886SAlan Wright  * smb_fsacl_free().
34629bd2886SAlan Wright  *
34729bd2886SAlan Wright  * Since the output parameter, fs_acl, is allocated in this
34829bd2886SAlan Wright  * function, the caller has to make sure *fs_acl is NULL which
34929bd2886SAlan Wright  * means it's not pointing to any memory.
35029bd2886SAlan Wright  */
35129bd2886SAlan Wright uint32_t
smb_acl_to_zfs(smb_acl_t * acl,uint32_t flags,int which_acl,acl_t ** fs_acl)35229bd2886SAlan Wright smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
35329bd2886SAlan Wright {
354f96bd5c8SAlan Wright 	char sidstr[SMB_SID_STRSZ];
35529bd2886SAlan Wright 	smb_ace_t *ace;
35629bd2886SAlan Wright 	acl_t *zacl;
35729bd2886SAlan Wright 	ace_t *zace;
35829bd2886SAlan Wright 	smb_idmap_batch_t sib;
35929bd2886SAlan Wright 	smb_idmap_t *sim;
36029bd2886SAlan Wright 	idmap_stat idm_stat;
36129bd2886SAlan Wright 	int i;
36229bd2886SAlan Wright 
36329bd2886SAlan Wright 	assert(fs_acl);
36429bd2886SAlan Wright 	assert(*fs_acl == NULL);
36529bd2886SAlan Wright 
36629bd2886SAlan Wright 	if (acl && !smb_acl_isvalid(acl, which_acl))
36729bd2886SAlan Wright 		return (NT_STATUS_INVALID_ACL);
36829bd2886SAlan Wright 
36929bd2886SAlan Wright 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
37029bd2886SAlan Wright 		if (which_acl == SMB_DACL_SECINFO) {
37129bd2886SAlan Wright 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
37229bd2886SAlan Wright 		}
37329bd2886SAlan Wright 
37429bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
37529bd2886SAlan Wright 	}
37629bd2886SAlan Wright 
37729bd2886SAlan Wright 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
37829bd2886SAlan Wright 	    SMB_IDMAP_SID2ID);
37929bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS)
38029bd2886SAlan Wright 		return (NT_STATUS_INTERNAL_ERROR);
38129bd2886SAlan Wright 
38229bd2886SAlan Wright 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
38329bd2886SAlan Wright 
38429bd2886SAlan Wright 	zace = zacl->acl_aclp;
38529bd2886SAlan Wright 	ace = acl->sl_aces;
38629bd2886SAlan Wright 	sim = sib.sib_maps;
38729bd2886SAlan Wright 
38829bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
38929bd2886SAlan Wright 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
39029bd2886SAlan Wright 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
39129bd2886SAlan Wright 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
392f96bd5c8SAlan Wright 		zace->a_who = (uid_t)-1;
39329bd2886SAlan Wright 
394f96bd5c8SAlan Wright 		smb_sid_tostr(ace->se_sid, sidstr);
395f96bd5c8SAlan Wright 
396f96bd5c8SAlan Wright 		if (!smb_ace_wellknown_update(sidstr, zace)) {
39729bd2886SAlan Wright 			sim->sim_id = &zace->a_who;
39829bd2886SAlan Wright 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
399f96bd5c8SAlan Wright 			    ace->se_sid, SMB_IDMAP_UNKNOWN);
40029bd2886SAlan Wright 
40129bd2886SAlan Wright 			if (idm_stat != IDMAP_SUCCESS) {
40229bd2886SAlan Wright 				smb_fsacl_free(zacl);
40329bd2886SAlan Wright 				smb_idmap_batch_destroy(&sib);
40429bd2886SAlan Wright 				return (NT_STATUS_INTERNAL_ERROR);
40529bd2886SAlan Wright 			}
40629bd2886SAlan Wright 		}
40729bd2886SAlan Wright 	}
40829bd2886SAlan Wright 
409*f920d1d1SGordon Ross 	idm_stat = smb_idmap_batch_getmappings(&sib, smb_acl_bgm_error);
41029bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS) {
41129bd2886SAlan Wright 		smb_fsacl_free(zacl);
41229bd2886SAlan Wright 		smb_idmap_batch_destroy(&sib);
41329bd2886SAlan Wright 		return (NT_STATUS_NONE_MAPPED);
41429bd2886SAlan Wright 	}
41529bd2886SAlan Wright 
41629bd2886SAlan Wright 	/*
41729bd2886SAlan Wright 	 * Set the ACEs group flag based on the type of ID returned.
41829bd2886SAlan Wright 	 */
41929bd2886SAlan Wright 	zace = zacl->acl_aclp;
42029bd2886SAlan Wright 	ace = acl->sl_aces;
42129bd2886SAlan Wright 	sim = sib.sib_maps;
42229bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
423f96bd5c8SAlan Wright 		if (zace->a_who == (uid_t)-1)
42429bd2886SAlan Wright 			continue;
42529bd2886SAlan Wright 
42629bd2886SAlan Wright 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
42729bd2886SAlan Wright 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
42829bd2886SAlan Wright 	}
42929bd2886SAlan Wright 
43029bd2886SAlan Wright 	smb_idmap_batch_destroy(&sib);
43129bd2886SAlan Wright 
43229bd2886SAlan Wright 	*fs_acl = zacl;
43329bd2886SAlan Wright 	return (NT_STATUS_SUCCESS);
43429bd2886SAlan Wright }
43529bd2886SAlan Wright 
436f96bd5c8SAlan Wright static boolean_t
smb_ace_wellknown_update(const char * sid,ace_t * zace)437f96bd5c8SAlan Wright smb_ace_wellknown_update(const char *sid, ace_t *zace)
438f96bd5c8SAlan Wright {
439f96bd5c8SAlan Wright 	struct {
440f96bd5c8SAlan Wright 		char		*sid;
441f96bd5c8SAlan Wright 		uint16_t	flags;
442f96bd5c8SAlan Wright 	} map[] = {
443f96bd5c8SAlan Wright 		{ NT_WORLD_SIDSTR,			ACE_EVERYONE },
444f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_OWNER_SIDSTR,	ACE_OWNER },
445f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_GROUP_SIDSTR,
446f96bd5c8SAlan Wright 			(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
447f96bd5c8SAlan Wright 	};
448f96bd5c8SAlan Wright 
449f96bd5c8SAlan Wright 	int	i;
450f96bd5c8SAlan Wright 
451f96bd5c8SAlan Wright 	for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
452f96bd5c8SAlan Wright 		if (strcmp(sid, map[i].sid) == 0) {
453f96bd5c8SAlan Wright 			zace->a_flags |= map[i].flags;
454f96bd5c8SAlan Wright 			return (B_TRUE);
455f96bd5c8SAlan Wright 		}
456f96bd5c8SAlan Wright 	}
457f96bd5c8SAlan Wright 
458f96bd5c8SAlan Wright 	return (B_FALSE);
459f96bd5c8SAlan Wright }
460f96bd5c8SAlan Wright 
46129bd2886SAlan Wright /*
46229bd2886SAlan Wright  * smb_fsacl_getsids
46329bd2886SAlan Wright  *
46429bd2886SAlan Wright  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
465*f920d1d1SGordon Ross  * Note: sib is type SMB_IDMAP_ID2SID, zacl->acl_cnt entries.
46629bd2886SAlan Wright  */
46729bd2886SAlan Wright static idmap_stat
smb_fsacl_getsids(smb_idmap_batch_t * sib,acl_t * zacl)468f96bd5c8SAlan Wright smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
46929bd2886SAlan Wright {
47029bd2886SAlan Wright 	ace_t *zace;
47129bd2886SAlan Wright 	idmap_stat idm_stat;
47229bd2886SAlan Wright 	smb_idmap_t *sim;
47329bd2886SAlan Wright 	uid_t id;
47429bd2886SAlan Wright 	int i, idtype;
47529bd2886SAlan Wright 
47629bd2886SAlan Wright 	sim = sib->sib_maps;
47729bd2886SAlan Wright 
47829bd2886SAlan Wright 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
47929bd2886SAlan Wright 	    zace++, i++, sim++) {
48083163ba8SToomas Soome 		id = (uid_t)-1;	/* some types do not need id */
48129bd2886SAlan Wright 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
48229bd2886SAlan Wright 		case ACE_OWNER:
483f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_OWNERAT;
48429bd2886SAlan Wright 			break;
48529bd2886SAlan Wright 
48629bd2886SAlan Wright 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
48729bd2886SAlan Wright 			/* owning group */
488f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_GROUPAT;
48929bd2886SAlan Wright 			break;
49029bd2886SAlan Wright 
49129bd2886SAlan Wright 		case ACE_IDENTIFIER_GROUP:
49229bd2886SAlan Wright 			/* regular group */
49329bd2886SAlan Wright 			idtype = SMB_IDMAP_GROUP;
494*f920d1d1SGordon Ross 			id = zace->a_who;
495*f920d1d1SGordon Ross 			/* for smb_acl_bgm_error ID2SID */
496*f920d1d1SGordon Ross 			sim->sim_id = &zace->a_who;
49729bd2886SAlan Wright 			break;
49829bd2886SAlan Wright 
49929bd2886SAlan Wright 		case ACE_EVERYONE:
50029bd2886SAlan Wright 			idtype = SMB_IDMAP_EVERYONE;
50129bd2886SAlan Wright 			break;
50229bd2886SAlan Wright 
50329bd2886SAlan Wright 		default:
50429bd2886SAlan Wright 			/* user entry */
50529bd2886SAlan Wright 			idtype = SMB_IDMAP_USER;
506*f920d1d1SGordon Ross 			id = zace->a_who;
507*f920d1d1SGordon Ross 			/* for smb_acl_bgm_error ID2SID */
508*f920d1d1SGordon Ross 			sim->sim_id = &zace->a_who;
509*f920d1d1SGordon Ross 			break;
51029bd2886SAlan Wright 		}
51129bd2886SAlan Wright 
51229bd2886SAlan Wright 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
51329bd2886SAlan Wright 		    id, idtype);
51429bd2886SAlan Wright 
51529bd2886SAlan Wright 		if (idm_stat != IDMAP_SUCCESS) {
51629bd2886SAlan Wright 			return (idm_stat);
51729bd2886SAlan Wright 		}
51829bd2886SAlan Wright 	}
51929bd2886SAlan Wright 
520*f920d1d1SGordon Ross 	idm_stat = smb_idmap_batch_getmappings(sib, smb_acl_bgm_error);
52129bd2886SAlan Wright 	return (idm_stat);
52229bd2886SAlan Wright }
52329bd2886SAlan Wright 
52429bd2886SAlan Wright /*
52529bd2886SAlan Wright  * smb_fsacl_null_empty
52629bd2886SAlan Wright  *
52729bd2886SAlan Wright  * NULL DACL means everyone full-access
52829bd2886SAlan Wright  * Empty DACL means everyone full-deny
52929bd2886SAlan Wright  *
53029bd2886SAlan Wright  * ZFS ACL must have at least one entry so smb server has
53129bd2886SAlan Wright  * to simulate the aforementioned expected behavior by adding
53229bd2886SAlan Wright  * an entry in case the requested DACL is null or empty. Adding
53329bd2886SAlan Wright  * a everyone full-deny entry has proved to be problematic in
53429bd2886SAlan Wright  * tests since a deny entry takes precedence over allow entries.
53529bd2886SAlan Wright  * So, instead of adding a everyone full-deny, an owner ACE with
53629bd2886SAlan Wright  * owner implicit permissions will be set.
53729bd2886SAlan Wright  */
53829bd2886SAlan Wright static acl_t *
smb_fsacl_null_empty(boolean_t null)53929bd2886SAlan Wright smb_fsacl_null_empty(boolean_t null)
54029bd2886SAlan Wright {
54129bd2886SAlan Wright 	acl_t *zacl;
54229bd2886SAlan Wright 	ace_t *zace;
54329bd2886SAlan Wright 
54429bd2886SAlan Wright 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
54529bd2886SAlan Wright 	zace = zacl->acl_aclp;
54629bd2886SAlan Wright 
54729bd2886SAlan Wright 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
54829bd2886SAlan Wright 	if (null) {
54929bd2886SAlan Wright 		zace->a_access_mask = ACE_ALL_PERMS;
55029bd2886SAlan Wright 		zace->a_flags = ACE_EVERYONE;
55129bd2886SAlan Wright 	} else {
55229bd2886SAlan Wright 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
55329bd2886SAlan Wright 		    ACE_READ_ATTRIBUTES;
55429bd2886SAlan Wright 		zace->a_flags = ACE_OWNER;
55529bd2886SAlan Wright 	}
55629bd2886SAlan Wright 
55729bd2886SAlan Wright 	return (zacl);
55829bd2886SAlan Wright }
55929bd2886SAlan Wright 
56029bd2886SAlan Wright /*
56129bd2886SAlan Wright  * FS ACL (acl_t) Functions
56229bd2886SAlan Wright  */
56329bd2886SAlan Wright acl_t *
smb_fsacl_alloc(int acenum,int flags)56429bd2886SAlan Wright smb_fsacl_alloc(int acenum, int flags)
56529bd2886SAlan Wright {
56629bd2886SAlan Wright 	acl_t *acl;
56729bd2886SAlan Wright 
56829bd2886SAlan Wright 	acl = acl_alloc(ACE_T);
56929bd2886SAlan Wright 	acl->acl_cnt = acenum;
57029bd2886SAlan Wright 	if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
57129bd2886SAlan Wright 		return (NULL);
57229bd2886SAlan Wright 
57329bd2886SAlan Wright 	acl->acl_flags = flags;
57429bd2886SAlan Wright 	return (acl);
57529bd2886SAlan Wright }
57629bd2886SAlan Wright 
57729bd2886SAlan Wright void
smb_fsacl_free(acl_t * acl)57829bd2886SAlan Wright smb_fsacl_free(acl_t *acl)
57929bd2886SAlan Wright {
58029bd2886SAlan Wright 	if (acl)
58129bd2886SAlan Wright 		acl_free(acl);
58229bd2886SAlan Wright }
58329bd2886SAlan Wright 
58429bd2886SAlan Wright /*
58529bd2886SAlan Wright  * ACE Functions
58629bd2886SAlan Wright  */
58729bd2886SAlan Wright 
588*f920d1d1SGordon Ross /*
589*f920d1d1SGordon Ross  * This is generic (ACL version 2) vs. object-specific
590*f920d1d1SGordon Ross  * (ACL version 4) ACE types.
591*f920d1d1SGordon Ross  */
592*f920d1d1SGordon Ross boolean_t
smb_ace_is_generic(int type)593*f920d1d1SGordon Ross smb_ace_is_generic(int type)
594*f920d1d1SGordon Ross {
595*f920d1d1SGordon Ross 	switch (type) {
596*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
597*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_ACE_TYPE:
598*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
599*f920d1d1SGordon Ross 	case ACE_SYSTEM_ALARM_ACE_TYPE:
600*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
601*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
602*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
603*f920d1d1SGordon Ross 	case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
604*f920d1d1SGordon Ross 		return (B_TRUE);
605*f920d1d1SGordon Ross 
606*f920d1d1SGordon Ross 	default:
607*f920d1d1SGordon Ross 		break;
608*f920d1d1SGordon Ross 	}
609*f920d1d1SGordon Ross 
610*f920d1d1SGordon Ross 	return (B_FALSE);
611*f920d1d1SGordon Ross }
612*f920d1d1SGordon Ross 
613*f920d1d1SGordon Ross boolean_t
smb_ace_is_access(int type)614*f920d1d1SGordon Ross smb_ace_is_access(int type)
615*f920d1d1SGordon Ross {
616*f920d1d1SGordon Ross 	switch (type) {
617*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
618*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_ACE_TYPE:
619*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
620*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
621*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
622*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
623*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
624*f920d1d1SGordon Ross 	case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
625*f920d1d1SGordon Ross 	case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
626*f920d1d1SGordon Ross 		return (B_TRUE);
627*f920d1d1SGordon Ross 
628*f920d1d1SGordon Ross 	default:
629*f920d1d1SGordon Ross 		break;
630*f920d1d1SGordon Ross 	}
631*f920d1d1SGordon Ross 
632*f920d1d1SGordon Ross 	return (B_FALSE);
633*f920d1d1SGordon Ross }
634*f920d1d1SGordon Ross 
635*f920d1d1SGordon Ross boolean_t
smb_ace_is_audit(int type)636*f920d1d1SGordon Ross smb_ace_is_audit(int type)
637*f920d1d1SGordon Ross {
638*f920d1d1SGordon Ross 	switch (type) {
639*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
640*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
641*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
642*f920d1d1SGordon Ross 	case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
643*f920d1d1SGordon Ross 		return (B_TRUE);
644*f920d1d1SGordon Ross 
645*f920d1d1SGordon Ross 	default:
646*f920d1d1SGordon Ross 		break;
647*f920d1d1SGordon Ross 	}
648*f920d1d1SGordon Ross 
649*f920d1d1SGordon Ross 	return (B_FALSE);
650*f920d1d1SGordon Ross }
651*f920d1d1SGordon Ross 
65229bd2886SAlan Wright /*
65329bd2886SAlan Wright  * smb_ace_len
65429bd2886SAlan Wright  *
65529bd2886SAlan Wright  * Returns the length of the given ACE as it appears in an
65629bd2886SAlan Wright  * ACL on the wire (i.e. a flat buffer which contains the SID)
65729bd2886SAlan Wright  */
65829bd2886SAlan Wright static uint16_t
smb_ace_len(smb_ace_t * ace)65929bd2886SAlan Wright smb_ace_len(smb_ace_t *ace)
66029bd2886SAlan Wright {
66129bd2886SAlan Wright 	assert(ace);
66229bd2886SAlan Wright 	assert(ace->se_sid);
66329bd2886SAlan Wright 
66429bd2886SAlan Wright 	if (ace == NULL)
66529bd2886SAlan Wright 		return (0);
66629bd2886SAlan Wright 
66729bd2886SAlan Wright 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
66829bd2886SAlan Wright 	    smb_sid_len(ace->se_sid));
66929bd2886SAlan Wright }
67029bd2886SAlan Wright 
67129bd2886SAlan Wright /*
67229bd2886SAlan Wright  * smb_ace_mask_g2s
67329bd2886SAlan Wright  *
67429bd2886SAlan Wright  * Converts generic access bits in the given mask (if any)
67529bd2886SAlan Wright  * to file specific bits. Generic access masks shouldn't be
67629bd2886SAlan Wright  * stored in filesystem ACEs.
67729bd2886SAlan Wright  */
67829bd2886SAlan Wright static uint32_t
smb_ace_mask_g2s(uint32_t mask)67929bd2886SAlan Wright smb_ace_mask_g2s(uint32_t mask)
68029bd2886SAlan Wright {
68129bd2886SAlan Wright 	if (mask & GENERIC_ALL) {
68229bd2886SAlan Wright 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
68329bd2886SAlan Wright 		    | GENERIC_EXECUTE);
68429bd2886SAlan Wright 
68529bd2886SAlan Wright 		mask |= FILE_ALL_ACCESS;
68629bd2886SAlan Wright 		return (mask);
68729bd2886SAlan Wright 	}
68829bd2886SAlan Wright 
68929bd2886SAlan Wright 	if (mask & GENERIC_READ) {
69029bd2886SAlan Wright 		mask &= ~GENERIC_READ;
69129bd2886SAlan Wright 		mask |= FILE_GENERIC_READ;
69229bd2886SAlan Wright 	}
69329bd2886SAlan Wright 
69429bd2886SAlan Wright 	if (mask & GENERIC_WRITE) {
69529bd2886SAlan Wright 		mask &= ~GENERIC_WRITE;
69629bd2886SAlan Wright 		mask |= FILE_GENERIC_WRITE;
69729bd2886SAlan Wright 	}
69829bd2886SAlan Wright 
69929bd2886SAlan Wright 	if (mask & GENERIC_EXECUTE) {
70029bd2886SAlan Wright 		mask &= ~GENERIC_EXECUTE;
70129bd2886SAlan Wright 		mask |= FILE_GENERIC_EXECUTE;
70229bd2886SAlan Wright 	}
70329bd2886SAlan Wright 
70429bd2886SAlan Wright 	return (mask);
70529bd2886SAlan Wright }
70629bd2886SAlan Wright 
70729bd2886SAlan Wright /*
70829bd2886SAlan Wright  * smb_ace_flags_tozfs
70929bd2886SAlan Wright  *
71029bd2886SAlan Wright  * This function maps the flags which have different values
71129bd2886SAlan Wright  * in Windows and Solaris. The ones with the same value are
71229bd2886SAlan Wright  * transferred untouched.
71329bd2886SAlan Wright  */
71429bd2886SAlan Wright static uint16_t
smb_ace_flags_tozfs(uint8_t c_flags)71529bd2886SAlan Wright smb_ace_flags_tozfs(uint8_t c_flags)
71629bd2886SAlan Wright {
71729bd2886SAlan Wright 	uint16_t z_flags = 0;
71829bd2886SAlan Wright 
71929bd2886SAlan Wright 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
72029bd2886SAlan Wright 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
72129bd2886SAlan Wright 
72229bd2886SAlan Wright 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
72329bd2886SAlan Wright 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
72429bd2886SAlan Wright 
72529bd2886SAlan Wright 	if (c_flags & INHERITED_ACE)
72629bd2886SAlan Wright 		z_flags |= ACE_INHERITED_ACE;
72729bd2886SAlan Wright 
72829bd2886SAlan Wright 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
72929bd2886SAlan Wright 
73029bd2886SAlan Wright 	return (z_flags);
73129bd2886SAlan Wright }
73229bd2886SAlan Wright 
73329bd2886SAlan Wright static uint8_t
smb_ace_flags_fromzfs(uint16_t z_flags)73429bd2886SAlan Wright smb_ace_flags_fromzfs(uint16_t z_flags)
73529bd2886SAlan Wright {
73629bd2886SAlan Wright 	uint8_t c_flags;
73729bd2886SAlan Wright 
73829bd2886SAlan Wright 	c_flags = z_flags & ACE_INHERIT_FLAGS;
73929bd2886SAlan Wright 
74029bd2886SAlan Wright 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
74129bd2886SAlan Wright 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
74229bd2886SAlan Wright 
74329bd2886SAlan Wright 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
74429bd2886SAlan Wright 		c_flags |= FAILED_ACCESS_ACE_FLAG;
74529bd2886SAlan Wright 
74629bd2886SAlan Wright 	if (z_flags & ACE_INHERITED_ACE)
74729bd2886SAlan Wright 		c_flags |= INHERITED_ACE;
74829bd2886SAlan Wright 
74929bd2886SAlan Wright 	return (c_flags);
75029bd2886SAlan Wright }
751*f920d1d1SGordon Ross 
752*f920d1d1SGordon Ross static boolean_t
smb_ace_isvalid(smb_ace_t * ace,int which_acl)753*f920d1d1SGordon Ross smb_ace_isvalid(smb_ace_t *ace, int which_acl)
754*f920d1d1SGordon Ross {
755*f920d1d1SGordon Ross 	uint16_t min_len;
756*f920d1d1SGordon Ross 
757*f920d1d1SGordon Ross 	min_len = sizeof (smb_acehdr_t);
758*f920d1d1SGordon Ross 
759*f920d1d1SGordon Ross 	if (ace->se_hdr.se_bsize < min_len)
760*f920d1d1SGordon Ross 		return (B_FALSE);
761*f920d1d1SGordon Ross 
762*f920d1d1SGordon Ross 	if (smb_ace_is_access(ace->se_hdr.se_type) &&
763*f920d1d1SGordon Ross 	    (which_acl != SMB_DACL_SECINFO))
764*f920d1d1SGordon Ross 		return (B_FALSE);
765*f920d1d1SGordon Ross 
766*f920d1d1SGordon Ross 	if (smb_ace_is_audit(ace->se_hdr.se_type) &&
767*f920d1d1SGordon Ross 	    (which_acl != SMB_SACL_SECINFO))
768*f920d1d1SGordon Ross 		return (B_FALSE);
769*f920d1d1SGordon Ross 
770*f920d1d1SGordon Ross 	if (smb_ace_is_generic(ace->se_hdr.se_type)) {
771*f920d1d1SGordon Ross 		if (!smb_sid_isvalid(ace->se_sid))
772*f920d1d1SGordon Ross 			return (B_FALSE);
773*f920d1d1SGordon Ross 
774*f920d1d1SGordon Ross 		min_len += sizeof (ace->se_mask);
775*f920d1d1SGordon Ross 		min_len += smb_sid_len(ace->se_sid);
776*f920d1d1SGordon Ross 
777*f920d1d1SGordon Ross 		if (ace->se_hdr.se_bsize < min_len)
778*f920d1d1SGordon Ross 			return (B_FALSE);
779*f920d1d1SGordon Ross 	}
780*f920d1d1SGordon Ross 
781*f920d1d1SGordon Ross 	/*
782*f920d1d1SGordon Ross 	 * object-specific ACE validation will be added later.
783*f920d1d1SGordon Ross 	 */
784*f920d1d1SGordon Ross 	return (B_TRUE);
785*f920d1d1SGordon Ross }
786