xref: /titanic_51/usr/src/lib/smbsrv/libsmb/common/smb_acl.c (revision f96bd5c800e73e351b0b6e4bd7f00b578dad29bb)
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 /*
22*f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2329bd2886SAlan Wright  * Use is subject to license terms.
2429bd2886SAlan Wright  */
2529bd2886SAlan Wright 
2629bd2886SAlan Wright #include <stddef.h>
2729bd2886SAlan Wright #include <strings.h>
2829bd2886SAlan Wright #include <assert.h>
2929bd2886SAlan Wright 
30bbf6f00cSJordan Brown #include <smbsrv/smb.h>
3129bd2886SAlan Wright #include <smbsrv/smb_sid.h>
3229bd2886SAlan Wright #include <smbsrv/smb_idmap.h>
3329bd2886SAlan Wright 
3429bd2886SAlan Wright #define	ACE_ALL_TYPES	0x001F
3529bd2886SAlan Wright 
3629bd2886SAlan Wright /*
3729bd2886SAlan Wright  * ACE groups within a DACL
3829bd2886SAlan Wright  *
3929bd2886SAlan Wright  * This is from lower to higher ACE order priority
4029bd2886SAlan Wright  */
4129bd2886SAlan Wright #define	SMB_AG_START		0
4229bd2886SAlan Wright #define	SMB_AG_ALW_INHRT	0
4329bd2886SAlan Wright #define	SMB_AG_DNY_INHRT	1
4429bd2886SAlan Wright #define	SMB_AG_ALW_DRCT		2
4529bd2886SAlan Wright #define	SMB_AG_DNY_DRCT		3
4629bd2886SAlan Wright #define	SMB_AG_NUM		4
4729bd2886SAlan Wright 
4829bd2886SAlan Wright #define	DEFAULT_DACL_ACENUM	2
4929bd2886SAlan Wright acl_t *acl_alloc(enum acl_type);
5029bd2886SAlan Wright 
51*f96bd5c8SAlan Wright static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *);
5229bd2886SAlan Wright static acl_t *smb_fsacl_null_empty(boolean_t);
5329bd2886SAlan Wright static uint16_t smb_ace_len(smb_ace_t *);
5429bd2886SAlan Wright static uint32_t smb_ace_mask_g2s(uint32_t);
5529bd2886SAlan Wright static uint16_t smb_ace_flags_tozfs(uint8_t);
5629bd2886SAlan Wright static uint8_t smb_ace_flags_fromzfs(uint16_t);
57*f96bd5c8SAlan Wright static boolean_t smb_ace_wellknown_update(const char *, ace_t *);
5829bd2886SAlan Wright 
5929bd2886SAlan Wright smb_acl_t *
6029bd2886SAlan Wright smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
6129bd2886SAlan Wright {
6229bd2886SAlan Wright 	smb_acl_t *acl;
6329bd2886SAlan Wright 	int size;
6429bd2886SAlan Wright 
6529bd2886SAlan Wright 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
6629bd2886SAlan Wright 	if ((acl = malloc(size)) == NULL)
6729bd2886SAlan Wright 		return (NULL);
6829bd2886SAlan Wright 
6929bd2886SAlan Wright 	acl->sl_revision = revision;
7029bd2886SAlan Wright 	acl->sl_bsize = bsize;
7129bd2886SAlan Wright 	acl->sl_acecnt = acecnt;
7229bd2886SAlan Wright 	acl->sl_aces = (smb_ace_t *)(acl + 1);
7329bd2886SAlan Wright 
7429bd2886SAlan Wright 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
7529bd2886SAlan Wright 	    offsetof(smb_ace_t, se_sln));
7629bd2886SAlan Wright 	return (acl);
7729bd2886SAlan Wright }
7829bd2886SAlan Wright 
7929bd2886SAlan Wright void
8029bd2886SAlan Wright smb_acl_free(smb_acl_t *acl)
8129bd2886SAlan Wright {
8229bd2886SAlan Wright 	int i;
8329bd2886SAlan Wright 	void *ace;
8429bd2886SAlan Wright 
8529bd2886SAlan Wright 	if (acl == NULL)
8629bd2886SAlan Wright 		return;
8729bd2886SAlan Wright 
8829bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++)
8929bd2886SAlan Wright 		smb_sid_free(acl->sl_aces[i].se_sid);
9029bd2886SAlan Wright 
9129bd2886SAlan Wright 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
9229bd2886SAlan Wright 		list_remove(&acl->sl_sorted, ace);
9329bd2886SAlan Wright 	list_destroy(&acl->sl_sorted);
9429bd2886SAlan Wright 	free(acl);
9529bd2886SAlan Wright 
9629bd2886SAlan Wright }
9729bd2886SAlan Wright 
9829bd2886SAlan Wright /*
9929bd2886SAlan Wright  * smb_acl_len
10029bd2886SAlan Wright  *
10129bd2886SAlan Wright  * Returns the size of given ACL in bytes. Note that this
10229bd2886SAlan Wright  * is not an in-memory size, it's the ACL's size as it would
10329bd2886SAlan Wright  * appear on the wire
10429bd2886SAlan Wright  */
10529bd2886SAlan Wright uint16_t
10629bd2886SAlan Wright smb_acl_len(smb_acl_t *acl)
10729bd2886SAlan Wright {
10829bd2886SAlan Wright 	return ((acl) ? acl->sl_bsize : 0);
10929bd2886SAlan Wright }
11029bd2886SAlan Wright 
11129bd2886SAlan Wright /*ARGSUSED*/
11229bd2886SAlan Wright boolean_t
11329bd2886SAlan Wright smb_acl_isvalid(smb_acl_t *acl, int which_acl)
11429bd2886SAlan Wright {
11529bd2886SAlan Wright 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
11629bd2886SAlan Wright 		return (B_FALSE);
11729bd2886SAlan Wright 
11829bd2886SAlan Wright 	if (acl->sl_revision != ACL_REVISION) {
11929bd2886SAlan Wright 		/*
12029bd2886SAlan Wright 		 * we are rejecting ACLs with object-specific ACEs for now
12129bd2886SAlan Wright 		 */
12229bd2886SAlan Wright 		return (B_FALSE);
12329bd2886SAlan Wright 	}
12429bd2886SAlan Wright 
12529bd2886SAlan Wright 	return (B_TRUE);
12629bd2886SAlan Wright }
12729bd2886SAlan Wright 
12829bd2886SAlan Wright /*
12929bd2886SAlan Wright  * smb_acl_sort
13029bd2886SAlan Wright  *
13129bd2886SAlan Wright  * Sorts the given ACL in place if it needs to be sorted.
13229bd2886SAlan Wright  *
13329bd2886SAlan Wright  * The following is an excerpt from MSDN website.
13429bd2886SAlan Wright  *
13529bd2886SAlan Wright  * Order of ACEs in a DACL
13629bd2886SAlan Wright  *
13729bd2886SAlan Wright  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
13829bd2886SAlan Wright  * is simple: In a DACL, all access-denied ACEs should precede any
13929bd2886SAlan Wright  * access-allowed ACEs.
14029bd2886SAlan Wright  *
14129bd2886SAlan Wright  * For Windows 2000 or later, the proper order of ACEs is more complicated
14229bd2886SAlan Wright  * because of the introduction of object-specific ACEs and automatic
14329bd2886SAlan Wright  * inheritance.
14429bd2886SAlan Wright  *
14529bd2886SAlan Wright  * The following describes the preferred order:
14629bd2886SAlan Wright  *
14729bd2886SAlan Wright  * To ensure that noninherited ACEs have precedence over inherited ACEs,
14829bd2886SAlan Wright  * place all noninherited ACEs in a group before any inherited ACEs. This
14929bd2886SAlan Wright  * ordering ensures, for example, that a noninherited access-denied ACE
15029bd2886SAlan Wright  * is enforced regardless of any inherited ACE that allows access.
15129bd2886SAlan Wright  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
15229bd2886SAlan Wright  * according to ACE type, as the following shows:
15329bd2886SAlan Wright  * 	. Access-denied ACEs that apply to the object itself
15429bd2886SAlan Wright  * 	. Access-denied ACEs that apply to a subobject of the
15529bd2886SAlan Wright  *	  object, such as a property set or property
15629bd2886SAlan Wright  * 	. Access-allowed ACEs that apply to the object itself
15729bd2886SAlan Wright  * 	. Access-allowed ACEs that apply to a subobject of the object
15829bd2886SAlan Wright  *
15929bd2886SAlan Wright  * So, here is the desired ACE order
16029bd2886SAlan Wright  *
16129bd2886SAlan Wright  * deny-direct, allow-direct, deny-inherited, allow-inherited
16229bd2886SAlan Wright  *
16329bd2886SAlan Wright  * Of course, not all ACE types are required in an ACL.
16429bd2886SAlan Wright  */
16529bd2886SAlan Wright void
16629bd2886SAlan Wright smb_acl_sort(smb_acl_t *acl)
16729bd2886SAlan Wright {
16829bd2886SAlan Wright 	list_t ace_grps[SMB_AG_NUM];
16929bd2886SAlan Wright 	list_t *alist;
17029bd2886SAlan Wright 	smb_ace_t *ace;
17129bd2886SAlan Wright 	uint8_t ace_flags;
17229bd2886SAlan Wright 	int ag, i;
17329bd2886SAlan Wright 
17429bd2886SAlan Wright 	assert(acl);
17529bd2886SAlan Wright 
17629bd2886SAlan Wright 	if (acl->sl_acecnt == 0) {
17729bd2886SAlan Wright 		/*
17829bd2886SAlan Wright 		 * ACL with no entry is a valid ACL and it means
17929bd2886SAlan Wright 		 * no access for anybody.
18029bd2886SAlan Wright 		 */
18129bd2886SAlan Wright 		return;
18229bd2886SAlan Wright 	}
18329bd2886SAlan Wright 
18429bd2886SAlan Wright 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
18529bd2886SAlan Wright 		list_create(&ace_grps[i], sizeof (smb_ace_t),
18629bd2886SAlan Wright 		    offsetof(smb_ace_t, se_sln));
18729bd2886SAlan Wright 	}
18829bd2886SAlan Wright 
18929bd2886SAlan Wright 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
19029bd2886SAlan Wright 		ace_flags = ace->se_hdr.se_flags;
19129bd2886SAlan Wright 
19229bd2886SAlan Wright 		switch (ace->se_hdr.se_type) {
19329bd2886SAlan Wright 		case ACCESS_DENIED_ACE_TYPE:
19429bd2886SAlan Wright 			ag = (ace_flags & INHERITED_ACE) ?
19529bd2886SAlan Wright 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
19629bd2886SAlan Wright 			break;
19729bd2886SAlan Wright 
19829bd2886SAlan Wright 		case ACCESS_ALLOWED_ACE_TYPE:
19929bd2886SAlan Wright 			ag = (ace_flags & INHERITED_ACE) ?
20029bd2886SAlan Wright 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
20129bd2886SAlan Wright 			break;
20229bd2886SAlan Wright 
20329bd2886SAlan Wright 		default:
20429bd2886SAlan Wright 			/*
20529bd2886SAlan Wright 			 * This is the lowest priority group so we put
20629bd2886SAlan Wright 			 * evertything unknown here.
20729bd2886SAlan Wright 			 */
20829bd2886SAlan Wright 			ag = SMB_AG_ALW_INHRT;
20929bd2886SAlan Wright 			break;
21029bd2886SAlan Wright 		}
21129bd2886SAlan Wright 
21229bd2886SAlan Wright 		/* Add the ACE to the selected group */
21329bd2886SAlan Wright 		list_insert_tail(&ace_grps[ag], ace);
21429bd2886SAlan Wright 	}
21529bd2886SAlan Wright 
21629bd2886SAlan Wright 	/*
21729bd2886SAlan Wright 	 * start with highest priority ACE group and append
21829bd2886SAlan Wright 	 * the ACEs to the ACL.
21929bd2886SAlan Wright 	 */
22029bd2886SAlan Wright 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
22129bd2886SAlan Wright 		alist = &ace_grps[i];
22229bd2886SAlan Wright 		while ((ace = list_head(alist)) != NULL) {
22329bd2886SAlan Wright 			list_remove(alist, ace);
22429bd2886SAlan Wright 			list_insert_tail(&acl->sl_sorted, ace);
22529bd2886SAlan Wright 		}
22629bd2886SAlan Wright 		list_destroy(alist);
22729bd2886SAlan Wright 	}
22829bd2886SAlan Wright }
22929bd2886SAlan Wright 
23029bd2886SAlan Wright /*
23129bd2886SAlan Wright  * smb_acl_from_zfs
23229bd2886SAlan Wright  *
23329bd2886SAlan Wright  * Converts given ZFS ACL to a Windows ACL.
23429bd2886SAlan Wright  *
23529bd2886SAlan Wright  * A pointer to allocated memory for the Windows ACL will be
23629bd2886SAlan Wright  * returned upon successful conversion.
23729bd2886SAlan Wright  */
23829bd2886SAlan Wright smb_acl_t *
239*f96bd5c8SAlan Wright smb_acl_from_zfs(acl_t *zacl)
24029bd2886SAlan Wright {
24129bd2886SAlan Wright 	ace_t *zace;
24229bd2886SAlan Wright 	int numaces;
24329bd2886SAlan Wright 	smb_acl_t *acl;
24429bd2886SAlan Wright 	smb_ace_t *ace;
24529bd2886SAlan Wright 	smb_idmap_batch_t sib;
24629bd2886SAlan Wright 	smb_idmap_t *sim;
24729bd2886SAlan Wright 	idmap_stat idm_stat;
24829bd2886SAlan Wright 
24929bd2886SAlan Wright 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
25029bd2886SAlan Wright 	    SMB_IDMAP_ID2SID);
25129bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS)
25229bd2886SAlan Wright 		return (NULL);
25329bd2886SAlan Wright 
254*f96bd5c8SAlan Wright 	if (smb_fsacl_getsids(&sib, zacl) != IDMAP_SUCCESS) {
25529bd2886SAlan Wright 		smb_idmap_batch_destroy(&sib);
25629bd2886SAlan Wright 		return (NULL);
25729bd2886SAlan Wright 	}
25829bd2886SAlan Wright 
25929bd2886SAlan Wright 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
26029bd2886SAlan Wright 
26129bd2886SAlan Wright 	sim = sib.sib_maps;
26229bd2886SAlan Wright 	for (numaces = 0, zace = zacl->acl_aclp;
26329bd2886SAlan Wright 	    numaces < zacl->acl_cnt;
26429bd2886SAlan Wright 	    zace++, numaces++, sim++) {
26529bd2886SAlan Wright 		assert(sim->sim_sid);
26629bd2886SAlan Wright 		if (sim->sim_sid == NULL) {
26729bd2886SAlan Wright 			smb_acl_free(acl);
26829bd2886SAlan Wright 			acl = NULL;
26929bd2886SAlan Wright 			break;
27029bd2886SAlan Wright 		}
27129bd2886SAlan Wright 
27229bd2886SAlan Wright 		ace = &acl->sl_aces[numaces];
27329bd2886SAlan Wright 		ace->se_hdr.se_type = zace->a_type;
27429bd2886SAlan Wright 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
27529bd2886SAlan Wright 		ace->se_mask = zace->a_access_mask;
27629bd2886SAlan Wright 		ace->se_sid = smb_sid_dup(sim->sim_sid);
27729bd2886SAlan Wright 		ace->se_hdr.se_bsize = smb_ace_len(ace);
27829bd2886SAlan Wright 
27929bd2886SAlan Wright 		acl->sl_bsize += ace->se_hdr.se_bsize;
28029bd2886SAlan Wright 	}
28129bd2886SAlan Wright 
28229bd2886SAlan Wright 	smb_idmap_batch_destroy(&sib);
28329bd2886SAlan Wright 	return (acl);
28429bd2886SAlan Wright }
28529bd2886SAlan Wright 
28629bd2886SAlan Wright /*
28729bd2886SAlan Wright  * smb_acl_to_zfs
28829bd2886SAlan Wright  *
28929bd2886SAlan Wright  * Converts given Windows ACL to a ZFS ACL.
29029bd2886SAlan Wright  *
29129bd2886SAlan Wright  * fs_acl will contain a pointer to the created ZFS ACL.
29229bd2886SAlan Wright  * The allocated memory should be freed by calling
29329bd2886SAlan Wright  * smb_fsacl_free().
29429bd2886SAlan Wright  *
29529bd2886SAlan Wright  * Since the output parameter, fs_acl, is allocated in this
29629bd2886SAlan Wright  * function, the caller has to make sure *fs_acl is NULL which
29729bd2886SAlan Wright  * means it's not pointing to any memory.
29829bd2886SAlan Wright  */
29929bd2886SAlan Wright uint32_t
30029bd2886SAlan Wright smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
30129bd2886SAlan Wright {
302*f96bd5c8SAlan Wright 	char sidstr[SMB_SID_STRSZ];
30329bd2886SAlan Wright 	smb_ace_t *ace;
30429bd2886SAlan Wright 	acl_t *zacl;
30529bd2886SAlan Wright 	ace_t *zace;
30629bd2886SAlan Wright 	smb_idmap_batch_t sib;
30729bd2886SAlan Wright 	smb_idmap_t *sim;
30829bd2886SAlan Wright 	idmap_stat idm_stat;
30929bd2886SAlan Wright 	int i;
31029bd2886SAlan Wright 
31129bd2886SAlan Wright 	assert(fs_acl);
31229bd2886SAlan Wright 	assert(*fs_acl == NULL);
31329bd2886SAlan Wright 
31429bd2886SAlan Wright 	if (acl && !smb_acl_isvalid(acl, which_acl))
31529bd2886SAlan Wright 		return (NT_STATUS_INVALID_ACL);
31629bd2886SAlan Wright 
31729bd2886SAlan Wright 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
31829bd2886SAlan Wright 		if (which_acl == SMB_DACL_SECINFO) {
31929bd2886SAlan Wright 			*fs_acl = smb_fsacl_null_empty(acl == NULL);
32029bd2886SAlan Wright 		}
32129bd2886SAlan Wright 
32229bd2886SAlan Wright 		return (NT_STATUS_SUCCESS);
32329bd2886SAlan Wright 	}
32429bd2886SAlan Wright 
32529bd2886SAlan Wright 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
32629bd2886SAlan Wright 	    SMB_IDMAP_SID2ID);
32729bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS)
32829bd2886SAlan Wright 		return (NT_STATUS_INTERNAL_ERROR);
32929bd2886SAlan Wright 
33029bd2886SAlan Wright 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
33129bd2886SAlan Wright 
33229bd2886SAlan Wright 	zace = zacl->acl_aclp;
33329bd2886SAlan Wright 	ace = acl->sl_aces;
33429bd2886SAlan Wright 	sim = sib.sib_maps;
33529bd2886SAlan Wright 
33629bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
33729bd2886SAlan Wright 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
33829bd2886SAlan Wright 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
33929bd2886SAlan Wright 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
340*f96bd5c8SAlan Wright 		zace->a_who = (uid_t)-1;
34129bd2886SAlan Wright 
342*f96bd5c8SAlan Wright 		smb_sid_tostr(ace->se_sid, sidstr);
343*f96bd5c8SAlan Wright 
344*f96bd5c8SAlan Wright 		if (!smb_ace_wellknown_update(sidstr, zace)) {
34529bd2886SAlan Wright 			sim->sim_id = &zace->a_who;
34629bd2886SAlan Wright 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
347*f96bd5c8SAlan Wright 			    ace->se_sid, SMB_IDMAP_UNKNOWN);
34829bd2886SAlan Wright 
34929bd2886SAlan Wright 			if (idm_stat != IDMAP_SUCCESS) {
35029bd2886SAlan Wright 				smb_fsacl_free(zacl);
35129bd2886SAlan Wright 				smb_idmap_batch_destroy(&sib);
35229bd2886SAlan Wright 				return (NT_STATUS_INTERNAL_ERROR);
35329bd2886SAlan Wright 			}
35429bd2886SAlan Wright 		}
35529bd2886SAlan Wright 	}
35629bd2886SAlan Wright 
35729bd2886SAlan Wright 	idm_stat = smb_idmap_batch_getmappings(&sib);
35829bd2886SAlan Wright 	if (idm_stat != IDMAP_SUCCESS) {
35929bd2886SAlan Wright 		smb_fsacl_free(zacl);
36029bd2886SAlan Wright 		smb_idmap_batch_destroy(&sib);
36129bd2886SAlan Wright 		return (NT_STATUS_NONE_MAPPED);
36229bd2886SAlan Wright 	}
36329bd2886SAlan Wright 
36429bd2886SAlan Wright 	/*
36529bd2886SAlan Wright 	 * Set the ACEs group flag based on the type of ID returned.
36629bd2886SAlan Wright 	 */
36729bd2886SAlan Wright 	zace = zacl->acl_aclp;
36829bd2886SAlan Wright 	ace = acl->sl_aces;
36929bd2886SAlan Wright 	sim = sib.sib_maps;
37029bd2886SAlan Wright 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
371*f96bd5c8SAlan Wright 		if (zace->a_who == (uid_t)-1)
37229bd2886SAlan Wright 			continue;
37329bd2886SAlan Wright 
37429bd2886SAlan Wright 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
37529bd2886SAlan Wright 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
37629bd2886SAlan Wright 	}
37729bd2886SAlan Wright 
37829bd2886SAlan Wright 	smb_idmap_batch_destroy(&sib);
37929bd2886SAlan Wright 
38029bd2886SAlan Wright 	*fs_acl = zacl;
38129bd2886SAlan Wright 	return (NT_STATUS_SUCCESS);
38229bd2886SAlan Wright }
38329bd2886SAlan Wright 
384*f96bd5c8SAlan Wright static boolean_t
385*f96bd5c8SAlan Wright smb_ace_wellknown_update(const char *sid, ace_t *zace)
386*f96bd5c8SAlan Wright {
387*f96bd5c8SAlan Wright 	struct {
388*f96bd5c8SAlan Wright 		char		*sid;
389*f96bd5c8SAlan Wright 		uint16_t	flags;
390*f96bd5c8SAlan Wright 	} map[] = {
391*f96bd5c8SAlan Wright 		{ NT_WORLD_SIDSTR,			ACE_EVERYONE },
392*f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_OWNER_SIDSTR,	ACE_OWNER },
393*f96bd5c8SAlan Wright 		{ NT_BUILTIN_CURRENT_GROUP_SIDSTR,
394*f96bd5c8SAlan Wright 			(ACE_GROUP | ACE_IDENTIFIER_GROUP) },
395*f96bd5c8SAlan Wright 	};
396*f96bd5c8SAlan Wright 
397*f96bd5c8SAlan Wright 	int	i;
398*f96bd5c8SAlan Wright 
399*f96bd5c8SAlan Wright 	for (i = 0; i < (sizeof (map) / sizeof (map[0])); ++i) {
400*f96bd5c8SAlan Wright 		if (strcmp(sid, map[i].sid) == 0) {
401*f96bd5c8SAlan Wright 			zace->a_flags |= map[i].flags;
402*f96bd5c8SAlan Wright 			return (B_TRUE);
403*f96bd5c8SAlan Wright 		}
404*f96bd5c8SAlan Wright 	}
405*f96bd5c8SAlan Wright 
406*f96bd5c8SAlan Wright 	return (B_FALSE);
407*f96bd5c8SAlan Wright }
408*f96bd5c8SAlan Wright 
40929bd2886SAlan Wright /*
41029bd2886SAlan Wright  * smb_fsacl_getsids
41129bd2886SAlan Wright  *
41229bd2886SAlan Wright  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
41329bd2886SAlan Wright  */
41429bd2886SAlan Wright static idmap_stat
415*f96bd5c8SAlan Wright smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl)
41629bd2886SAlan Wright {
41729bd2886SAlan Wright 	ace_t *zace;
41829bd2886SAlan Wright 	idmap_stat idm_stat;
41929bd2886SAlan Wright 	smb_idmap_t *sim;
42029bd2886SAlan Wright 	uid_t id;
42129bd2886SAlan Wright 	int i, idtype;
42229bd2886SAlan Wright 
42329bd2886SAlan Wright 	sim = sib->sib_maps;
42429bd2886SAlan Wright 
42529bd2886SAlan Wright 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
42629bd2886SAlan Wright 	    zace++, i++, sim++) {
42729bd2886SAlan Wright 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
42829bd2886SAlan Wright 		case ACE_OWNER:
429*f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_OWNERAT;
43029bd2886SAlan Wright 			break;
43129bd2886SAlan Wright 
43229bd2886SAlan Wright 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
43329bd2886SAlan Wright 			/* owning group */
434*f96bd5c8SAlan Wright 			idtype = SMB_IDMAP_GROUPAT;
43529bd2886SAlan Wright 			break;
43629bd2886SAlan Wright 
43729bd2886SAlan Wright 		case ACE_IDENTIFIER_GROUP:
43829bd2886SAlan Wright 			/* regular group */
43929bd2886SAlan Wright 			id = zace->a_who;
44029bd2886SAlan Wright 			idtype = SMB_IDMAP_GROUP;
44129bd2886SAlan Wright 			break;
44229bd2886SAlan Wright 
44329bd2886SAlan Wright 		case ACE_EVERYONE:
44429bd2886SAlan Wright 			idtype = SMB_IDMAP_EVERYONE;
44529bd2886SAlan Wright 			break;
44629bd2886SAlan Wright 
44729bd2886SAlan Wright 		default:
44829bd2886SAlan Wright 			/* user entry */
44929bd2886SAlan Wright 			id = zace->a_who;
45029bd2886SAlan Wright 			idtype = SMB_IDMAP_USER;
45129bd2886SAlan Wright 		}
45229bd2886SAlan Wright 
45329bd2886SAlan Wright 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
45429bd2886SAlan Wright 		    id, idtype);
45529bd2886SAlan Wright 
45629bd2886SAlan Wright 		if (idm_stat != IDMAP_SUCCESS) {
45729bd2886SAlan Wright 			return (idm_stat);
45829bd2886SAlan Wright 		}
45929bd2886SAlan Wright 	}
46029bd2886SAlan Wright 
46129bd2886SAlan Wright 	idm_stat = smb_idmap_batch_getmappings(sib);
46229bd2886SAlan Wright 	return (idm_stat);
46329bd2886SAlan Wright }
46429bd2886SAlan Wright 
46529bd2886SAlan Wright /*
46629bd2886SAlan Wright  * smb_fsacl_null_empty
46729bd2886SAlan Wright  *
46829bd2886SAlan Wright  * NULL DACL means everyone full-access
46929bd2886SAlan Wright  * Empty DACL means everyone full-deny
47029bd2886SAlan Wright  *
47129bd2886SAlan Wright  * ZFS ACL must have at least one entry so smb server has
47229bd2886SAlan Wright  * to simulate the aforementioned expected behavior by adding
47329bd2886SAlan Wright  * an entry in case the requested DACL is null or empty. Adding
47429bd2886SAlan Wright  * a everyone full-deny entry has proved to be problematic in
47529bd2886SAlan Wright  * tests since a deny entry takes precedence over allow entries.
47629bd2886SAlan Wright  * So, instead of adding a everyone full-deny, an owner ACE with
47729bd2886SAlan Wright  * owner implicit permissions will be set.
47829bd2886SAlan Wright  */
47929bd2886SAlan Wright static acl_t *
48029bd2886SAlan Wright smb_fsacl_null_empty(boolean_t null)
48129bd2886SAlan Wright {
48229bd2886SAlan Wright 	acl_t *zacl;
48329bd2886SAlan Wright 	ace_t *zace;
48429bd2886SAlan Wright 
48529bd2886SAlan Wright 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
48629bd2886SAlan Wright 	zace = zacl->acl_aclp;
48729bd2886SAlan Wright 
48829bd2886SAlan Wright 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
48929bd2886SAlan Wright 	if (null) {
49029bd2886SAlan Wright 		zace->a_access_mask = ACE_ALL_PERMS;
49129bd2886SAlan Wright 		zace->a_flags = ACE_EVERYONE;
49229bd2886SAlan Wright 	} else {
49329bd2886SAlan Wright 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
49429bd2886SAlan Wright 		    ACE_READ_ATTRIBUTES;
49529bd2886SAlan Wright 		zace->a_flags = ACE_OWNER;
49629bd2886SAlan Wright 	}
49729bd2886SAlan Wright 
49829bd2886SAlan Wright 	return (zacl);
49929bd2886SAlan Wright }
50029bd2886SAlan Wright 
50129bd2886SAlan Wright /*
50229bd2886SAlan Wright  * FS ACL (acl_t) Functions
50329bd2886SAlan Wright  */
50429bd2886SAlan Wright acl_t *
50529bd2886SAlan Wright smb_fsacl_alloc(int acenum, int flags)
50629bd2886SAlan Wright {
50729bd2886SAlan Wright 	acl_t *acl;
50829bd2886SAlan Wright 
50929bd2886SAlan Wright 	acl = acl_alloc(ACE_T);
51029bd2886SAlan Wright 	acl->acl_cnt = acenum;
51129bd2886SAlan Wright 	if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
51229bd2886SAlan Wright 		return (NULL);
51329bd2886SAlan Wright 
51429bd2886SAlan Wright 	acl->acl_flags = flags;
51529bd2886SAlan Wright 	return (acl);
51629bd2886SAlan Wright }
51729bd2886SAlan Wright 
51829bd2886SAlan Wright void
51929bd2886SAlan Wright smb_fsacl_free(acl_t *acl)
52029bd2886SAlan Wright {
52129bd2886SAlan Wright 	if (acl)
52229bd2886SAlan Wright 		acl_free(acl);
52329bd2886SAlan Wright }
52429bd2886SAlan Wright 
52529bd2886SAlan Wright /*
52629bd2886SAlan Wright  * ACE Functions
52729bd2886SAlan Wright  */
52829bd2886SAlan Wright 
52929bd2886SAlan Wright /*
53029bd2886SAlan Wright  * smb_ace_len
53129bd2886SAlan Wright  *
53229bd2886SAlan Wright  * Returns the length of the given ACE as it appears in an
53329bd2886SAlan Wright  * ACL on the wire (i.e. a flat buffer which contains the SID)
53429bd2886SAlan Wright  */
53529bd2886SAlan Wright static uint16_t
53629bd2886SAlan Wright smb_ace_len(smb_ace_t *ace)
53729bd2886SAlan Wright {
53829bd2886SAlan Wright 	assert(ace);
53929bd2886SAlan Wright 	assert(ace->se_sid);
54029bd2886SAlan Wright 
54129bd2886SAlan Wright 	if (ace == NULL)
54229bd2886SAlan Wright 		return (0);
54329bd2886SAlan Wright 
54429bd2886SAlan Wright 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
54529bd2886SAlan Wright 	    smb_sid_len(ace->se_sid));
54629bd2886SAlan Wright }
54729bd2886SAlan Wright 
54829bd2886SAlan Wright /*
54929bd2886SAlan Wright  * smb_ace_mask_g2s
55029bd2886SAlan Wright  *
55129bd2886SAlan Wright  * Converts generic access bits in the given mask (if any)
55229bd2886SAlan Wright  * to file specific bits. Generic access masks shouldn't be
55329bd2886SAlan Wright  * stored in filesystem ACEs.
55429bd2886SAlan Wright  */
55529bd2886SAlan Wright static uint32_t
55629bd2886SAlan Wright smb_ace_mask_g2s(uint32_t mask)
55729bd2886SAlan Wright {
55829bd2886SAlan Wright 	if (mask & GENERIC_ALL) {
55929bd2886SAlan Wright 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
56029bd2886SAlan Wright 		    | GENERIC_EXECUTE);
56129bd2886SAlan Wright 
56229bd2886SAlan Wright 		mask |= FILE_ALL_ACCESS;
56329bd2886SAlan Wright 		return (mask);
56429bd2886SAlan Wright 	}
56529bd2886SAlan Wright 
56629bd2886SAlan Wright 	if (mask & GENERIC_READ) {
56729bd2886SAlan Wright 		mask &= ~GENERIC_READ;
56829bd2886SAlan Wright 		mask |= FILE_GENERIC_READ;
56929bd2886SAlan Wright 	}
57029bd2886SAlan Wright 
57129bd2886SAlan Wright 	if (mask & GENERIC_WRITE) {
57229bd2886SAlan Wright 		mask &= ~GENERIC_WRITE;
57329bd2886SAlan Wright 		mask |= FILE_GENERIC_WRITE;
57429bd2886SAlan Wright 	}
57529bd2886SAlan Wright 
57629bd2886SAlan Wright 	if (mask & GENERIC_EXECUTE) {
57729bd2886SAlan Wright 		mask &= ~GENERIC_EXECUTE;
57829bd2886SAlan Wright 		mask |= FILE_GENERIC_EXECUTE;
57929bd2886SAlan Wright 	}
58029bd2886SAlan Wright 
58129bd2886SAlan Wright 	return (mask);
58229bd2886SAlan Wright }
58329bd2886SAlan Wright 
58429bd2886SAlan Wright /*
58529bd2886SAlan Wright  * smb_ace_flags_tozfs
58629bd2886SAlan Wright  *
58729bd2886SAlan Wright  * This function maps the flags which have different values
58829bd2886SAlan Wright  * in Windows and Solaris. The ones with the same value are
58929bd2886SAlan Wright  * transferred untouched.
59029bd2886SAlan Wright  */
59129bd2886SAlan Wright static uint16_t
59229bd2886SAlan Wright smb_ace_flags_tozfs(uint8_t c_flags)
59329bd2886SAlan Wright {
59429bd2886SAlan Wright 	uint16_t z_flags = 0;
59529bd2886SAlan Wright 
59629bd2886SAlan Wright 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
59729bd2886SAlan Wright 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
59829bd2886SAlan Wright 
59929bd2886SAlan Wright 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
60029bd2886SAlan Wright 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
60129bd2886SAlan Wright 
60229bd2886SAlan Wright 	if (c_flags & INHERITED_ACE)
60329bd2886SAlan Wright 		z_flags |= ACE_INHERITED_ACE;
60429bd2886SAlan Wright 
60529bd2886SAlan Wright 	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
60629bd2886SAlan Wright 
60729bd2886SAlan Wright 	return (z_flags);
60829bd2886SAlan Wright }
60929bd2886SAlan Wright 
61029bd2886SAlan Wright static uint8_t
61129bd2886SAlan Wright smb_ace_flags_fromzfs(uint16_t z_flags)
61229bd2886SAlan Wright {
61329bd2886SAlan Wright 	uint8_t c_flags;
61429bd2886SAlan Wright 
61529bd2886SAlan Wright 	c_flags = z_flags & ACE_INHERIT_FLAGS;
61629bd2886SAlan Wright 
61729bd2886SAlan Wright 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
61829bd2886SAlan Wright 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
61929bd2886SAlan Wright 
62029bd2886SAlan Wright 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
62129bd2886SAlan Wright 		c_flags |= FAILED_ACCESS_ACE_FLAG;
62229bd2886SAlan Wright 
62329bd2886SAlan Wright 	if (z_flags & ACE_INHERITED_ACE)
62429bd2886SAlan Wright 		c_flags |= INHERITED_ACE;
62529bd2886SAlan Wright 
62629bd2886SAlan Wright 	return (c_flags);
62729bd2886SAlan Wright }
628