xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_acl.c (revision 5521:cf62335046cd)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
225331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
275331Samw 
285331Samw #include <sys/acl.h>
29*5521Sas200622 #include <acl/acl_common.h>
305331Samw #include <smbsrv/ntsid.h>
315331Samw #include <smbsrv/smb_fsops.h>
325331Samw #include <smbsrv/smb_idmap.h>
33*5521Sas200622 #include <smbsrv/smb_kproto.h>
34*5521Sas200622 #include <smbsrv/smbvar.h>
35*5521Sas200622 #include <smbsrv/ntstatus.h>
36*5521Sas200622 #include <smbsrv/ntaccess.h>
375331Samw 
385331Samw #define	ACE_FD_INHERIT_ACE (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE)
395331Samw 
405331Samw #define	ZACE_IS_OWNER(zace) ((zace->a_flags & ACE_TYPE_FLAGS) == ACE_OWNER)
415331Samw #define	ZACE_IS_OWNGRP(zace) \
425331Samw 	((zace->a_flags & ACE_TYPE_FLAGS) == (ACE_IDENTIFIER_GROUP|ACE_GROUP))
435331Samw 
445331Samw #define	ZACE_IS_USER(zace) \
455331Samw 	(((zace->a_flags & ACE_TYPE_FLAGS) == 0) || (ZACE_IS_OWNER(zace)))
465331Samw #define	ZACE_IS_GROUP(zace) (zace->a_flags & ACE_IDENTIFIER_GROUP)
475331Samw #define	ZACE_IS_EVERYONE(zace) (zace->a_flags & ACE_EVERYONE)
485331Samw 
495331Samw #define	ZACE_IS_PROPAGATE(zace) \
505331Samw 	((zace->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) == 0)
515331Samw 
525331Samw #define	ZACE_IS_CREATOR_OWNER(zace) \
535331Samw 	(ZACE_IS_USER(zace) && (zace->a_who == IDMAP_WK_CREATOR_OWNER_UID))
545331Samw 
555331Samw #define	ZACE_IS_CREATOR_GROUP(zace) \
565331Samw 	(ZACE_IS_GROUP(zace) && (zace->a_who == IDMAP_WK_CREATOR_GROUP_GID))
575331Samw 
585331Samw #define	ZACE_IS_CREATOR(zace) \
595331Samw 	(ZACE_IS_CREATOR_OWNER(zace) || ZACE_IS_CREATOR_GROUP(zace))
605331Samw 
615331Samw /*
625331Samw  * ACE groups within a DACL
635331Samw  *
645331Samw  * This is from lower to higher ACE order priority
655331Samw  */
665331Samw #define	SMB_AG_START		0
675331Samw #define	SMB_AG_ALW_INHRT	0
685331Samw #define	SMB_AG_DNY_INHRT	1
695331Samw #define	SMB_AG_ALW_DRCT		2
705331Samw #define	SMB_AG_DNY_DRCT		3
715331Samw #define	SMB_AG_NUM		4
725331Samw 
735331Samw /*
74*5521Sas200622  * SID for Everyone group: S-1-1-0.
75*5521Sas200622  */
76*5521Sas200622 nt_sid_t everyone_sid = {
77*5521Sas200622 	NT_SID_REVISION,
78*5521Sas200622 	1,
79*5521Sas200622 	NT_SECURITY_WORLD_AUTH,
80*5521Sas200622 	{ 0 }
81*5521Sas200622 };
82*5521Sas200622 
83*5521Sas200622 #define	DEFAULT_DACL_ACENUM	2
84*5521Sas200622 /*
85*5521Sas200622  * Default ACL:
86*5521Sas200622  *    owner: full access
87*5521Sas200622  *    SYSTEM: full access
88*5521Sas200622  */
89*5521Sas200622 static ace_t default_dacl[DEFAULT_DACL_ACENUM] = {
90*5521Sas200622 	{ (uid_t)-1, ACE_ALL_PERMS, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
91*5521Sas200622 	{ IDMAP_WK_LOCAL_SYSTEM_GID, ACE_ALL_PERMS, ACE_IDENTIFIER_GROUP,
92*5521Sas200622 	    ACE_ACCESS_ALLOWED_ACE_TYPE }
93*5521Sas200622 };
94*5521Sas200622 
95*5521Sas200622 /*
96*5521Sas200622  * Note:
975331Samw  *
98*5521Sas200622  * smb_acl_xxx functions work with smb_acl_t which represents the CIFS format
99*5521Sas200622  * smb_fsacl_xxx functions work with acl_t which represents the Solaris native
100*5521Sas200622  * format
101*5521Sas200622  */
102*5521Sas200622 
103*5521Sas200622 static idmap_stat smb_acl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t);
104*5521Sas200622 static acl_t *smb_acl_null_empty(boolean_t null);
105*5521Sas200622 
106*5521Sas200622 static int smb_fsacl_inheritable(acl_t *, int);
107*5521Sas200622 
108*5521Sas200622 
109*5521Sas200622 static void smb_ace_inherit(ace_t *, ace_t *, int);
110*5521Sas200622 static boolean_t smb_ace_isvalid(smb_ace_t *, int);
111*5521Sas200622 static uint16_t smb_ace_len(smb_ace_t *);
112*5521Sas200622 static uint32_t smb_ace_mask_g2s(uint32_t);
113*5521Sas200622 static uint16_t smb_ace_flags_tozfs(uint8_t, int);
114*5521Sas200622 static uint8_t smb_ace_flags_fromzfs(uint16_t);
115*5521Sas200622 
116*5521Sas200622 smb_acl_t *
117*5521Sas200622 smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
118*5521Sas200622 {
119*5521Sas200622 	smb_acl_t *acl;
120*5521Sas200622 	int size;
121*5521Sas200622 
122*5521Sas200622 	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
123*5521Sas200622 	acl = kmem_zalloc(size, KM_SLEEP);
124*5521Sas200622 	acl->sl_revision = revision;
125*5521Sas200622 	acl->sl_bsize = bsize;
126*5521Sas200622 	acl->sl_acecnt = acecnt;
127*5521Sas200622 	acl->sl_aces = (smb_ace_t *)(acl + 1);
128*5521Sas200622 
129*5521Sas200622 	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
130*5521Sas200622 	    offsetof(smb_ace_t, se_sln));
131*5521Sas200622 	return (acl);
132*5521Sas200622 }
133*5521Sas200622 
134*5521Sas200622 void
135*5521Sas200622 smb_acl_free(smb_acl_t *acl)
136*5521Sas200622 {
137*5521Sas200622 	int i, size;
138*5521Sas200622 	void *ace;
139*5521Sas200622 
140*5521Sas200622 	if (acl == NULL)
141*5521Sas200622 		return;
142*5521Sas200622 
143*5521Sas200622 	for (i = 0; i < acl->sl_acecnt; i++) {
144*5521Sas200622 		MEM_FREE("smbsrv", acl->sl_aces[i].se_sid);
145*5521Sas200622 	}
146*5521Sas200622 
147*5521Sas200622 	while ((ace = list_head(&acl->sl_sorted)) != NULL)
148*5521Sas200622 		list_remove(&acl->sl_sorted, ace);
149*5521Sas200622 	list_destroy(&acl->sl_sorted);
150*5521Sas200622 
151*5521Sas200622 	size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t));
152*5521Sas200622 	kmem_free(acl, size);
153*5521Sas200622 }
154*5521Sas200622 
155*5521Sas200622 /*
156*5521Sas200622  * smb_acl_len
157*5521Sas200622  *
158*5521Sas200622  * Returns the size of given ACL in bytes. Note that this
159*5521Sas200622  * is not an in-memory size, it's the ACL's size as it would
160*5521Sas200622  * appear on the wire
161*5521Sas200622  */
162*5521Sas200622 uint16_t
163*5521Sas200622 smb_acl_len(smb_acl_t *acl)
164*5521Sas200622 {
165*5521Sas200622 	if (acl == NULL)
166*5521Sas200622 		return (0);
167*5521Sas200622 
168*5521Sas200622 	return (acl->sl_bsize);
169*5521Sas200622 }
170*5521Sas200622 
171*5521Sas200622 boolean_t
172*5521Sas200622 smb_acl_isvalid(smb_acl_t *acl, int which_acl)
173*5521Sas200622 {
174*5521Sas200622 	int i;
175*5521Sas200622 
176*5521Sas200622 	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
177*5521Sas200622 		return (B_FALSE);
178*5521Sas200622 
179*5521Sas200622 	if (acl->sl_revision != ACL_REVISION) {
180*5521Sas200622 		/*
181*5521Sas200622 		 * we are rejecting ACLs with object-specific ACEs for now
182*5521Sas200622 		 */
183*5521Sas200622 		return (B_FALSE);
184*5521Sas200622 	}
185*5521Sas200622 
186*5521Sas200622 	for (i = 0; i < acl->sl_acecnt; i++) {
187*5521Sas200622 		if (!smb_ace_isvalid(&acl->sl_aces[i], which_acl))
188*5521Sas200622 			return (B_FALSE);
189*5521Sas200622 	}
190*5521Sas200622 
191*5521Sas200622 	return (B_TRUE);
192*5521Sas200622 }
193*5521Sas200622 
194*5521Sas200622 /*
195*5521Sas200622  * smb_acl_sort
196*5521Sas200622  *
197*5521Sas200622  * Sorts the given ACL in place if it needs to be sorted.
1985331Samw  *
1995331Samw  * The following is an excerpt from MSDN website.
2005331Samw  *
2015331Samw  * Order of ACEs in a DACL
2025331Samw  *
2035331Samw  * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
2045331Samw  * is simple: In a DACL, all access-denied ACEs should precede any
2055331Samw  * access-allowed ACEs.
2065331Samw  *
2075331Samw  * For Windows 2000 or later, the proper order of ACEs is more complicated
2085331Samw  * because of the introduction of object-specific ACEs and automatic
2095331Samw  * inheritance.
2105331Samw  *
2115331Samw  * The following describes the preferred order:
2125331Samw  *
2135331Samw  * To ensure that noninherited ACEs have precedence over inherited ACEs,
2145331Samw  * place all noninherited ACEs in a group before any inherited ACEs. This
2155331Samw  * ordering ensures, for example, that a noninherited access-denied ACE
2165331Samw  * is enforced regardless of any inherited ACE that allows access.
2175331Samw  * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
2185331Samw  * according to ACE type, as the following shows:
2195331Samw  * 	. Access-denied ACEs that apply to the object itself
2205331Samw  * 	. Access-denied ACEs that apply to a subobject of the
2215331Samw  *	  object, such as a property set or property
2225331Samw  * 	. Access-allowed ACEs that apply to the object itself
2235331Samw  * 	. Access-allowed ACEs that apply to a subobject of the object
2245331Samw  *
225*5521Sas200622  * So, here is the desired ACE order
2265331Samw  *
2275331Samw  * deny-direct, allow-direct, deny-inherited, allow-inherited
2285331Samw  *
229*5521Sas200622  * Of course, not all ACE types are required in an ACL.
2305331Samw  */
231*5521Sas200622 void
2325331Samw smb_acl_sort(smb_acl_t *acl)
2335331Samw {
234*5521Sas200622 	list_t ace_grps[SMB_AG_NUM];
235*5521Sas200622 	list_t *alist;
2365331Samw 	smb_ace_t *ace;
2375331Samw 	uint8_t ace_flags;
238*5521Sas200622 	int ag, i;
2395331Samw 
2405331Samw 	ASSERT(acl);
2415331Samw 
2425331Samw 	if (acl->sl_acecnt == 0) {
2435331Samw 		/*
2445331Samw 		 * ACL with no entry is a valid ACL and it means
2455331Samw 		 * no access for anybody.
2465331Samw 		 */
247*5521Sas200622 		return;
2485331Samw 	}
2495331Samw 
2505331Samw 	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
251*5521Sas200622 		list_create(&ace_grps[i], sizeof (smb_ace_t),
252*5521Sas200622 		    offsetof(smb_ace_t, se_sln));
2535331Samw 	}
2545331Samw 
255*5521Sas200622 	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
256*5521Sas200622 		ace_flags = ace->se_hdr.se_flags;
2575331Samw 
258*5521Sas200622 		switch (ace->se_hdr.se_type) {
2595331Samw 		case ACCESS_DENIED_ACE_TYPE:
260*5521Sas200622 			ag = (ace_flags & INHERITED_ACE) ?
261*5521Sas200622 			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
2625331Samw 			break;
2635331Samw 
2645331Samw 		case ACCESS_ALLOWED_ACE_TYPE:
265*5521Sas200622 			ag = (ace_flags & INHERITED_ACE) ?
266*5521Sas200622 			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
2675331Samw 			break;
2685331Samw 
2695331Samw 		default:
2705331Samw 			/*
2715331Samw 			 * This is the lowest priority group so we put
2725331Samw 			 * evertything unknown here.
2735331Samw 			 */
2745331Samw 			ag = SMB_AG_ALW_INHRT;
2755331Samw 			break;
2765331Samw 		}
2775331Samw 
278*5521Sas200622 		/* Add the ACE to the selected group */
279*5521Sas200622 		list_insert_tail(&ace_grps[ag], ace);
2805331Samw 	}
2815331Samw 
282*5521Sas200622 	/*
283*5521Sas200622 	 * start with highest priority ACE group and append
284*5521Sas200622 	 * the ACEs to the ACL.
285*5521Sas200622 	 */
286*5521Sas200622 	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
287*5521Sas200622 		alist = &ace_grps[i];
288*5521Sas200622 		while ((ace = list_head(alist)) != NULL) {
289*5521Sas200622 			list_remove(alist, ace);
290*5521Sas200622 			list_insert_tail(&acl->sl_sorted, ace);
291*5521Sas200622 		}
292*5521Sas200622 		list_destroy(alist);
2935331Samw 	}
2945331Samw }
2955331Samw 
296*5521Sas200622 /*
297*5521Sas200622  * smb_acl_from_zfs
298*5521Sas200622  *
299*5521Sas200622  * Converts given ZFS ACL to a Windows ACL.
300*5521Sas200622  *
301*5521Sas200622  * A pointer to allocated memory for the Win ACL will be
302*5521Sas200622  * returned upon successful conversion.
303*5521Sas200622  */
304*5521Sas200622 smb_acl_t *
305*5521Sas200622 smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
3065331Samw {
307*5521Sas200622 	ace_t *zace;
308*5521Sas200622 	int numaces;
309*5521Sas200622 	smb_acl_t *acl;
3105331Samw 	smb_ace_t *ace;
311*5521Sas200622 	smb_idmap_batch_t sib;
312*5521Sas200622 	smb_idmap_t *sim;
313*5521Sas200622 	idmap_stat idm_stat;
3145331Samw 
315*5521Sas200622 	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
316*5521Sas200622 	    SMB_IDMAP_ID2SID);
317*5521Sas200622 	if (idm_stat != IDMAP_SUCCESS)
3185331Samw 		return (NULL);
3195331Samw 
320*5521Sas200622 	if (smb_acl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
321*5521Sas200622 		smb_idmap_batch_destroy(&sib);
322*5521Sas200622 		return (NULL);
3235331Samw 	}
3245331Samw 
325*5521Sas200622 	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
3265331Samw 
327*5521Sas200622 	sim = sib.sib_maps;
328*5521Sas200622 	for (numaces = 0, zace = zacl->acl_aclp;
329*5521Sas200622 	    numaces < zacl->acl_cnt;
330*5521Sas200622 	    zace++, numaces++, sim++) {
331*5521Sas200622 		ASSERT(sim->sim_sid);
332*5521Sas200622 		if (sim->sim_sid == NULL) {
333*5521Sas200622 			smb_acl_free(acl);
334*5521Sas200622 			acl = NULL;
335*5521Sas200622 			break;
336*5521Sas200622 		}
3375331Samw 
338*5521Sas200622 		ace = &acl->sl_aces[numaces];
339*5521Sas200622 		ace->se_hdr.se_type = zace->a_type;
340*5521Sas200622 		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
341*5521Sas200622 		ace->se_mask = zace->a_access_mask;
342*5521Sas200622 		ace->se_sid = nt_sid_dup(sim->sim_sid);
343*5521Sas200622 		ace->se_hdr.se_bsize = smb_ace_len(ace);
344*5521Sas200622 
345*5521Sas200622 		acl->sl_bsize += ace->se_hdr.se_bsize;
3465331Samw 	}
3475331Samw 
348*5521Sas200622 	smb_idmap_batch_destroy(&sib);
349*5521Sas200622 	return (acl);
3505331Samw }
3515331Samw 
3525331Samw /*
353*5521Sas200622  * smb_acl_to_zfs
3545331Samw  *
355*5521Sas200622  * Converts given Windows ACL to a ZFS ACL.
3565331Samw  *
357*5521Sas200622  * fs_acl will contain a pointer to the created ZFS ACL.
358*5521Sas200622  * The allocated memory should be freed by calling
359*5521Sas200622  * smb_fsacl_free().
3605331Samw  *
361*5521Sas200622  * Since the output parameter, fs_acl, is allocated in this
362*5521Sas200622  * function, the caller has to make sure *fs_acl is NULL which
363*5521Sas200622  * means it's not pointing to any memory.
3645331Samw  */
3655331Samw uint32_t
366*5521Sas200622 smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
3675331Samw {
368*5521Sas200622 	smb_ace_t *ace;
369*5521Sas200622 	acl_t *zacl;
370*5521Sas200622 	ace_t *zace;
371*5521Sas200622 	smb_idmap_batch_t sib;
372*5521Sas200622 	smb_idmap_t *sim;
373*5521Sas200622 	idmap_stat idm_stat;
374*5521Sas200622 	int i, isdir;
3755331Samw 
376*5521Sas200622 	ASSERT(fs_acl);
377*5521Sas200622 	ASSERT(*fs_acl == NULL);
378*5521Sas200622 
379*5521Sas200622 	if (acl && !smb_acl_isvalid(acl, which_acl))
380*5521Sas200622 		return (NT_STATUS_INVALID_ACL);
381*5521Sas200622 
382*5521Sas200622 	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
383*5521Sas200622 		if (which_acl == SMB_DACL_SECINFO) {
384*5521Sas200622 			*fs_acl = smb_acl_null_empty(acl == NULL);
385*5521Sas200622 		}
386*5521Sas200622 
387*5521Sas200622 		return (NT_STATUS_SUCCESS);
3885331Samw 	}
3895331Samw 
390*5521Sas200622 	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
391*5521Sas200622 	    SMB_IDMAP_SID2ID);
392*5521Sas200622 	if (idm_stat != IDMAP_SUCCESS)
393*5521Sas200622 		return (NT_STATUS_INTERNAL_ERROR);
394*5521Sas200622 
395*5521Sas200622 	isdir = ((flags & ACL_IS_DIR) == ACL_IS_DIR);
396*5521Sas200622 
397*5521Sas200622 	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
398*5521Sas200622 
399*5521Sas200622 	zace = zacl->acl_aclp;
400*5521Sas200622 	ace = acl->sl_aces;
401*5521Sas200622 	sim = sib.sib_maps;
402*5521Sas200622 
403*5521Sas200622 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
404*5521Sas200622 		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
405*5521Sas200622 		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
406*5521Sas200622 		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags,
407*5521Sas200622 		    isdir);
408*5521Sas200622 
409*5521Sas200622 		if (nt_sid_is_equal(ace->se_sid, &everyone_sid))
410*5521Sas200622 			zace->a_flags |= ACE_EVERYONE;
411*5521Sas200622 		else {
412*5521Sas200622 			sim->sim_id = &zace->a_who;
413*5521Sas200622 			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
414*5521Sas200622 			    ace->se_sid, -1);
415*5521Sas200622 
416*5521Sas200622 			if (idm_stat != IDMAP_SUCCESS) {
417*5521Sas200622 				smb_fsacl_free(zacl);
418*5521Sas200622 				smb_idmap_batch_destroy(&sib);
419*5521Sas200622 				return (NT_STATUS_INTERNAL_ERROR);
420*5521Sas200622 			}
421*5521Sas200622 		}
4225331Samw 	}
4235331Samw 
424*5521Sas200622 	idm_stat = smb_idmap_batch_getmappings(&sib);
425*5521Sas200622 	if (idm_stat != IDMAP_SUCCESS) {
426*5521Sas200622 		smb_fsacl_free(zacl);
427*5521Sas200622 		smb_idmap_batch_destroy(&sib);
428*5521Sas200622 		return (NT_STATUS_NONE_MAPPED);
4295331Samw 	}
4305331Samw 
431*5521Sas200622 	/*
432*5521Sas200622 	 * Set the ACEs group flag based on the type of ID returned.
433*5521Sas200622 	 */
434*5521Sas200622 	zace = zacl->acl_aclp;
435*5521Sas200622 	ace = acl->sl_aces;
436*5521Sas200622 	sim = sib.sib_maps;
437*5521Sas200622 	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
438*5521Sas200622 		if (zace->a_flags & ACE_EVERYONE)
439*5521Sas200622 			continue;
440*5521Sas200622 
441*5521Sas200622 		if (sim->sim_idtype == SMB_IDMAP_GROUP)
442*5521Sas200622 			zace->a_flags |= ACE_IDENTIFIER_GROUP;
4435331Samw 	}
4445331Samw 
445*5521Sas200622 	smb_idmap_batch_destroy(&sib);
446*5521Sas200622 
447*5521Sas200622 	*fs_acl = zacl;
448*5521Sas200622 	return (NT_STATUS_SUCCESS);
4495331Samw }
4505331Samw 
4515331Samw /*
4525331Samw  * smb_acl_getsids
4535331Samw  *
4545331Samw  * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
4555331Samw  */
4565331Samw static idmap_stat
4575331Samw smb_acl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
4585331Samw {
4595331Samw 	ace_t *zace;
4605331Samw 	idmap_stat idm_stat;
4615331Samw 	smb_idmap_t *sim;
4625331Samw 	uid_t id;
4635331Samw 	int i, idtype;
4645331Samw 
4655331Samw 	sim = sib->sib_maps;
4665331Samw 
4675331Samw 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
4685331Samw 	    zace++, i++, sim++) {
4695331Samw 		switch (zace->a_flags & ACE_TYPE_FLAGS) {
4705331Samw 		case ACE_OWNER:
4715331Samw 			id = uid;
4725331Samw 			idtype = SMB_IDMAP_USER;
4735331Samw 			break;
4745331Samw 
4755331Samw 		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
4765331Samw 			/* owning group */
4775331Samw 			id = gid;
4785331Samw 			idtype = SMB_IDMAP_GROUP;
4795331Samw 			break;
4805331Samw 
4815331Samw 		case ACE_IDENTIFIER_GROUP:
4825331Samw 			/* regular group */
4835331Samw 			id = zace->a_who;
4845331Samw 			idtype = SMB_IDMAP_GROUP;
4855331Samw 			break;
4865331Samw 
4875331Samw 		case ACE_EVERYONE:
4885331Samw 			idtype = SMB_IDMAP_EVERYONE;
4895331Samw 			break;
4905331Samw 
4915331Samw 		default:
4925331Samw 			/* user entry */
4935331Samw 			id = zace->a_who;
4945331Samw 			idtype = SMB_IDMAP_USER;
4955331Samw 		}
4965331Samw 
4975331Samw 		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
4985331Samw 		    id, idtype);
4995331Samw 
5005331Samw 		if (idm_stat != IDMAP_SUCCESS) {
5015331Samw 			return (idm_stat);
5025331Samw 		}
5035331Samw 	}
5045331Samw 
5055331Samw 	idm_stat = smb_idmap_batch_getmappings(sib);
5065331Samw 	return (idm_stat);
5075331Samw }
5085331Samw 
5095331Samw /*
5105331Samw  * smb_acl_null_empty
5115331Samw  *
5125331Samw  * NULL DACL means everyone full-access
5135331Samw  * Empty DACL means everyone full-deny
5145331Samw  *
5155331Samw  * ZFS ACL must have at least one entry so smb server has
5165331Samw  * to simulate the aforementioned expected behavior by adding
5175331Samw  * an entry in case the requested DACL is null or empty. Adding
5185331Samw  * a everyone full-deny entry has proved to be problematic in
5195331Samw  * tests since a deny entry takes precedence over allow entries.
5205331Samw  * So, instead of adding a everyone full-deny, an owner ACE with
5215331Samw  * owner implicit permissions will be set.
5225331Samw  */
523*5521Sas200622 static acl_t *
524*5521Sas200622 smb_acl_null_empty(boolean_t null)
5255331Samw {
5265331Samw 	acl_t *zacl;
5275331Samw 	ace_t *zace;
5285331Samw 
529*5521Sas200622 	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
5305331Samw 	zace = zacl->acl_aclp;
5315331Samw 
5325331Samw 	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
5335331Samw 	if (null) {
5345331Samw 		zace->a_access_mask = ACE_ALL_PERMS;
5355331Samw 		zace->a_flags = ACE_EVERYONE;
5365331Samw 	} else {
5375331Samw 		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
5385331Samw 		    ACE_READ_ATTRIBUTES;
5395331Samw 		zace->a_flags = ACE_OWNER;
5405331Samw 	}
5415331Samw 
5425331Samw 	return (zacl);
5435331Samw }
5445331Samw 
5455331Samw /*
546*5521Sas200622  * FS ACL (acl_t) Functions
5475331Samw  */
548*5521Sas200622 acl_t *
549*5521Sas200622 smb_fsacl_alloc(int acenum, int flags)
5505331Samw {
551*5521Sas200622 	acl_t *acl;
5525331Samw 
553*5521Sas200622 	acl = acl_alloc(ACE_T);
554*5521Sas200622 	acl->acl_cnt = acenum;
555*5521Sas200622 	acl->acl_aclp = kmem_zalloc(acl->acl_entry_size * acenum, KM_SLEEP);
556*5521Sas200622 	acl->acl_flags = flags;
557*5521Sas200622 	return (acl);
558*5521Sas200622 }
5595331Samw 
560*5521Sas200622 void
561*5521Sas200622 smb_fsacl_free(acl_t *acl)
562*5521Sas200622 {
563*5521Sas200622 	if (acl)
564*5521Sas200622 		acl_free(acl);
565*5521Sas200622 }
5665331Samw 
567*5521Sas200622 /*
568*5521Sas200622  * smb_fsop_aclmerge
569*5521Sas200622  *
570*5521Sas200622  * smb_fsop_aclread/write routines which interact with filesystem
571*5521Sas200622  * work with single ACL. This routine merges given DACL and SACL
572*5521Sas200622  * which might have been created during CIFS to FS conversion into
573*5521Sas200622  * one single ACL.
574*5521Sas200622  */
575*5521Sas200622 acl_t *
576*5521Sas200622 smb_fsacl_merge(acl_t *dacl, acl_t *sacl)
577*5521Sas200622 {
578*5521Sas200622 	acl_t *acl;
579*5521Sas200622 	int dacl_size;
5805331Samw 
581*5521Sas200622 	ASSERT(dacl);
582*5521Sas200622 	ASSERT(sacl);
5835331Samw 
584*5521Sas200622 	acl = smb_fsacl_alloc(dacl->acl_cnt + sacl->acl_cnt, dacl->acl_flags);
585*5521Sas200622 	dacl_size = dacl->acl_cnt * dacl->acl_entry_size;
586*5521Sas200622 	bcopy(dacl->acl_aclp, acl->acl_aclp, dacl_size);
587*5521Sas200622 	bcopy(sacl->acl_aclp, (char *)acl->acl_aclp + dacl_size,
588*5521Sas200622 	    sacl->acl_cnt * sacl->acl_entry_size);
5895331Samw 
590*5521Sas200622 	return (acl);
5915331Samw }
5925331Samw 
5935331Samw /*
594*5521Sas200622  * smb_fsacl_split
5955331Samw  *
596*5521Sas200622  * splits the given ACE_T ACL (zacl) to one or two ACLs (DACL/SACL) based on
597*5521Sas200622  * the 'which_acl' parameter. Note that output dacl/sacl parameters could be
598*5521Sas200622  * NULL even if they're specified in 'which_acl', which means the target
599*5521Sas200622  * doesn't have any access and/or audit ACEs.
6005331Samw  */
601*5521Sas200622 void
602*5521Sas200622 smb_fsacl_split(acl_t *zacl, acl_t **dacl, acl_t **sacl, int which_acl)
6035331Samw {
6045331Samw 	ace_t *zace;
605*5521Sas200622 	ace_t *access_ace;
606*5521Sas200622 	ace_t *audit_ace;
607*5521Sas200622 	int naccess, naudit;
608*5521Sas200622 	int get_dacl, get_sacl;
609*5521Sas200622 	int i;
610*5521Sas200622 
611*5521Sas200622 	*dacl = *sacl = NULL;
612*5521Sas200622 	naccess = naudit = 0;
613*5521Sas200622 	get_dacl = (which_acl & SMB_DACL_SECINFO);
614*5521Sas200622 	get_sacl = (which_acl & SMB_SACL_SECINFO);
6155331Samw 
616*5521Sas200622 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
617*5521Sas200622 		if (get_dacl && smb_ace_is_access(zace->a_type))
618*5521Sas200622 			naccess++;
619*5521Sas200622 		else if (get_sacl && smb_ace_is_audit(zace->a_type))
620*5521Sas200622 			naudit++;
621*5521Sas200622 	}
6225331Samw 
623*5521Sas200622 	if (naccess) {
624*5521Sas200622 		*dacl = smb_fsacl_alloc(naccess, zacl->acl_flags);
625*5521Sas200622 		access_ace = (*dacl)->acl_aclp;
626*5521Sas200622 	}
6275331Samw 
628*5521Sas200622 	if (naudit) {
629*5521Sas200622 		*sacl = smb_fsacl_alloc(naudit, zacl->acl_flags);
630*5521Sas200622 		audit_ace = (*sacl)->acl_aclp;
631*5521Sas200622 	}
6325331Samw 
633*5521Sas200622 	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt; zace++, i++) {
634*5521Sas200622 		if (get_dacl && smb_ace_is_access(zace->a_type)) {
635*5521Sas200622 			*access_ace = *zace;
636*5521Sas200622 			access_ace++;
637*5521Sas200622 		} else if (get_sacl && smb_ace_is_audit(zace->a_type)) {
638*5521Sas200622 			*audit_ace = *zace;
639*5521Sas200622 			audit_ace++;
6405331Samw 		}
6415331Samw 	}
6425331Samw }
6435331Samw 
6445331Samw /*
645*5521Sas200622  * ACE Inheritance Rules
646*5521Sas200622  *
647*5521Sas200622  * The system propagates inheritable ACEs to child objects according to a
648*5521Sas200622  * set of inheritance rules. The system places inherited ACEs in the child's
649*5521Sas200622  * DACL according to the preferred order of ACEs in a DACL. For Windows
650*5521Sas200622  * 2000 or later, the system sets the INHERITED_ACE flag in all inherited ACEs.
651*5521Sas200622  *
652*5521Sas200622  * The following table shows the ACEs inherited by container and noncontainer
653*5521Sas200622  * child objects for different combinations of inheritance flags. These
654*5521Sas200622  * inheritance rules work the same for both DACLs and SACLs.
655*5521Sas200622  *
656*5521Sas200622  * Parent ACE type 			Effect on Child ACL
657*5521Sas200622  * -----------------------		-------------------
658*5521Sas200622  * OBJECT_INHERIT_ACE only 		Noncontainer child objects:
659*5521Sas200622  *					Inherited as an effective ACE.
660*5521Sas200622  *					Container child objects:
661*5521Sas200622  *					Containers inherit an inherit-only ACE
662*5521Sas200622  *					unless the NO_PROPAGATE_INHERIT_ACE bit
663*5521Sas200622  *					flag is also set.
664*5521Sas200622  *
665*5521Sas200622  * CONTAINER_INHERIT_ACE only 		Noncontainer child objects:
666*5521Sas200622  *					No effect on the child object.
667*5521Sas200622  *					Container child objects:
668*5521Sas200622  *				The child object inherits an effective ACE.
669*5521Sas200622  *				The inherited ACE is inheritable unless the
670*5521Sas200622  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set.
671*5521Sas200622  *
672*5521Sas200622  * CONTAINER_INHERIT_ACE and
673*5521Sas200622  * OBJECT_INHERIT_ACE 			Noncontainer child objects:
674*5521Sas200622  *					Inherited as an effective ACE.
675*5521Sas200622  *					Container child objects:
676*5521Sas200622  *				The child object inherits an effective ACE.
677*5521Sas200622  *				The inherited ACE is inheritable unless the
678*5521Sas200622  *				NO_PROPAGATE_INHERIT_ACE bit flag is also set
679*5521Sas200622  *
680*5521Sas200622  * No inheritance flags set 	No effect on child container or noncontainer
681*5521Sas200622  *				objects.
682*5521Sas200622  *
683*5521Sas200622  * If an inherited ACE is an effective ACE for the child object, the system
684*5521Sas200622  * maps any generic rights to the specific rights for the child object.
685*5521Sas200622  * Similarly, the system maps generic SIDs, such as CREATOR_OWNER, to the
686*5521Sas200622  * appropriate SID. If an inherited ACE is an inherit-only ACE, any generic
687*5521Sas200622  * rights or generic SIDs are left unchanged so that they can be mapped
688*5521Sas200622  * appropriately when the ACE is inherited by the next generation of child
689*5521Sas200622  * objects.
690*5521Sas200622  *
691*5521Sas200622  * For a case in which a container object inherits an ACE that is both
692*5521Sas200622  * effective on the container and inheritable by its descendants, the
693*5521Sas200622  * container may inherit two ACEs. This occurs if the inheritable ACE
694*5521Sas200622  * contains generic information. The container inherits an inherit-only
695*5521Sas200622  * ACE containing the generic information and an effective-only ACE in
696*5521Sas200622  * which the generic information has been mapped.
6975331Samw  */
6985331Samw 
6995331Samw /*
700*5521Sas200622  * smb_fsacl_inherit
7015331Samw  *
7025331Samw  * Manufacture the inherited ACL from the given ACL considering
7035331Samw  * the new object type (file/dir) specified by 'is_dir'. The
7045331Samw  * returned ACL is used in smb_fsop_create/smb_fsop_mkdir functions.
705*5521Sas200622  * This function implements Windows inheritance rules explained above.
7065331Samw  *
707*5521Sas200622  * Note that the in/out ACLs are ZFS ACLs not Windows ACLs
7085331Samw  */
7095331Samw acl_t *
710*5521Sas200622 smb_fsacl_inherit(acl_t *dir_zacl, int is_dir, int which_acl, uid_t owner_uid)
7115331Samw {
7125331Samw 	boolean_t use_default = B_FALSE;
7135331Samw 	int num_inheritable = 0;
7145331Samw 	int numaces;
7155331Samw 	ace_t *dir_zace;
7165331Samw 	acl_t *new_zacl;
7175331Samw 	ace_t *new_zace;
7185331Samw 
719*5521Sas200622 	num_inheritable = smb_fsacl_inheritable(dir_zacl, is_dir);
7205331Samw 
7215331Samw 	if (num_inheritable == 0) {
7225331Samw 		if (which_acl == SMB_DACL_SECINFO) {
7235331Samw 			/* No inheritable access ACEs -> default DACL */
7245331Samw 			num_inheritable = DEFAULT_DACL_ACENUM;
7255331Samw 			use_default = B_TRUE;
7265331Samw 		} else {
7275331Samw 			return (NULL);
7285331Samw 		}
7295331Samw 	}
7305331Samw 
731*5521Sas200622 	new_zacl = smb_fsacl_alloc(num_inheritable, ACL_AUTO_INHERIT);
7325331Samw 	new_zace = new_zacl->acl_aclp;
7335331Samw 
7345331Samw 	if (use_default) {
7355331Samw 		bcopy(default_dacl, new_zacl->acl_aclp, sizeof (default_dacl));
7365331Samw 		new_zace->a_who = owner_uid;
7375331Samw 		return (new_zacl);
7385331Samw 	}
7395331Samw 
7405331Samw 	for (numaces = 0, dir_zace = dir_zacl->acl_aclp;
7415331Samw 	    numaces < dir_zacl->acl_cnt;
7425331Samw 	    dir_zace++, numaces++) {
7435331Samw 		switch (dir_zace->a_flags & ACE_FD_INHERIT_ACE) {
7445331Samw 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
7455331Samw 			/*
7465331Samw 			 * Files inherit an effective ACE.
7475331Samw 			 *
7485331Samw 			 * Dirs inherit an effective ACE.
7495331Samw 			 * The inherited ACE is inheritable unless the
7505331Samw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
7515331Samw 			 */
7525331Samw 			smb_ace_inherit(dir_zace, new_zace, is_dir);
7535331Samw 			new_zace++;
7545331Samw 
7555331Samw 			if (is_dir && ZACE_IS_CREATOR(dir_zace) &&
7565331Samw 			    (ZACE_IS_PROPAGATE(dir_zace))) {
7575331Samw 				*new_zace = *dir_zace;
7585331Samw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
7595331Samw 				    ACE_INHERITED_ACE);
7605331Samw 				new_zace++;
7615331Samw 			}
7625331Samw 			break;
7635331Samw 
7645331Samw 		case ACE_FILE_INHERIT_ACE:
7655331Samw 			/*
7665331Samw 			 * Files inherit as an effective ACE.
7675331Samw 			 *
7685331Samw 			 * Dirs inherit an inherit-only ACE
7695331Samw 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
7705331Samw 			 * flag is also set.
7715331Samw 			 */
7725331Samw 			if (is_dir == 0) {
7735331Samw 				smb_ace_inherit(dir_zace, new_zace, is_dir);
7745331Samw 				new_zace++;
7755331Samw 			} else if (ZACE_IS_PROPAGATE(dir_zace)) {
7765331Samw 				*new_zace = *dir_zace;
7775331Samw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
7785331Samw 				    ACE_INHERITED_ACE);
7795331Samw 				new_zace++;
7805331Samw 			}
7815331Samw 			break;
7825331Samw 
7835331Samw 		case ACE_DIRECTORY_INHERIT_ACE:
7845331Samw 			/*
7855331Samw 			 * No effect on files
7865331Samw 			 *
7875331Samw 			 * Dirs inherit an effective ACE.
7885331Samw 			 * The inherited ACE is inheritable unless the
7895331Samw 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
7905331Samw 			 */
7915331Samw 			if (is_dir == 0)
7925331Samw 				break;
7935331Samw 
7945331Samw 			smb_ace_inherit(dir_zace, new_zace, is_dir);
7955331Samw 			new_zace++;
7965331Samw 
7975331Samw 			if (ZACE_IS_CREATOR(dir_zace) &&
7985331Samw 			    (ZACE_IS_PROPAGATE(dir_zace))) {
7995331Samw 				*new_zace = *dir_zace;
8005331Samw 				new_zace->a_flags |= (ACE_INHERIT_ONLY_ACE |
8015331Samw 				    ACE_INHERITED_ACE);
8025331Samw 				new_zace++;
8035331Samw 			}
8045331Samw 
8055331Samw 			break;
8065331Samw 
8075331Samw 		default:
8085331Samw 			break;
8095331Samw 		}
8105331Samw 	}
8115331Samw 
8125331Samw 	return (new_zacl);
8135331Samw }
8145331Samw 
815*5521Sas200622 /*
816*5521Sas200622  * smb_fsacl_from_vsa
817*5521Sas200622  *
818*5521Sas200622  * Converts given vsecattr_t structure to a acl_t structure.
819*5521Sas200622  *
820*5521Sas200622  * The allocated memory for retuned acl_t should be freed by
821*5521Sas200622  * calling acl_free().
822*5521Sas200622  */
823*5521Sas200622 acl_t *
824*5521Sas200622 smb_fsacl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type)
825*5521Sas200622 {
826*5521Sas200622 	int		aclbsize = 0;	/* size of acl list in bytes */
827*5521Sas200622 	int		dfaclbsize = 0;	/* size of default acl list in bytes */
828*5521Sas200622 	int		numacls;
829*5521Sas200622 	acl_t		*acl_info;
830*5521Sas200622 
831*5521Sas200622 	ASSERT(vsecattr);
832*5521Sas200622 
833*5521Sas200622 	acl_info = acl_alloc(acl_type);
834*5521Sas200622 	if (acl_info == NULL)
835*5521Sas200622 		return (NULL);
836*5521Sas200622 
837*5521Sas200622 	acl_info->acl_flags = 0;
838*5521Sas200622 
839*5521Sas200622 	switch (acl_type) {
840*5521Sas200622 
841*5521Sas200622 	case ACLENT_T:
842*5521Sas200622 		numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt;
843*5521Sas200622 		aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t);
844*5521Sas200622 		dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t);
845*5521Sas200622 
846*5521Sas200622 		acl_info->acl_cnt = numacls;
847*5521Sas200622 		acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize,
848*5521Sas200622 		    KM_SLEEP);
849*5521Sas200622 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
850*5521Sas200622 		    aclbsize);
851*5521Sas200622 		(void) memcpy((char *)acl_info->acl_aclp + aclbsize,
852*5521Sas200622 		    vsecattr->vsa_dfaclentp, dfaclbsize);
853*5521Sas200622 
854*5521Sas200622 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
855*5521Sas200622 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
856*5521Sas200622 
857*5521Sas200622 		break;
858*5521Sas200622 
859*5521Sas200622 	case ACE_T:
860*5521Sas200622 		aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
861*5521Sas200622 		acl_info->acl_cnt = vsecattr->vsa_aclcnt;
862*5521Sas200622 		acl_info->acl_flags = vsecattr->vsa_aclflags;
863*5521Sas200622 		acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP);
864*5521Sas200622 		(void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp,
865*5521Sas200622 		    aclbsize);
866*5521Sas200622 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
867*5521Sas200622 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
868*5521Sas200622 
869*5521Sas200622 		break;
870*5521Sas200622 
871*5521Sas200622 	default:
872*5521Sas200622 		acl_free(acl_info);
873*5521Sas200622 		return (NULL);
874*5521Sas200622 	}
875*5521Sas200622 
876*5521Sas200622 	if (aclbsize && vsecattr->vsa_aclentp)
877*5521Sas200622 		kmem_free(vsecattr->vsa_aclentp, aclbsize);
878*5521Sas200622 	if (dfaclbsize && vsecattr->vsa_dfaclentp)
879*5521Sas200622 		kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize);
880*5521Sas200622 
881*5521Sas200622 	return (acl_info);
882*5521Sas200622 }
883*5521Sas200622 
884*5521Sas200622 /*
885*5521Sas200622  * smb_fsacl_to_vsa
886*5521Sas200622  *
887*5521Sas200622  * Converts given acl_t structure to a vsecattr_t structure.
888*5521Sas200622  *
889*5521Sas200622  * IMPORTANT:
890*5521Sas200622  * Upon successful return the memory allocated for vsa_aclentp
891*5521Sas200622  * should be freed by calling kmem_free(). The size is returned
892*5521Sas200622  * in aclbsize.
893*5521Sas200622  */
894*5521Sas200622 int
895*5521Sas200622 smb_fsacl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize)
896*5521Sas200622 {
897*5521Sas200622 	int		error = 0;
898*5521Sas200622 	int		numacls;
899*5521Sas200622 	aclent_t	*aclp;
900*5521Sas200622 
901*5521Sas200622 	ASSERT(acl_info);
902*5521Sas200622 	ASSERT(vsecattr);
903*5521Sas200622 	ASSERT(aclbsize);
904*5521Sas200622 
905*5521Sas200622 	bzero(vsecattr, sizeof (vsecattr_t));
906*5521Sas200622 	*aclbsize = 0;
907*5521Sas200622 
908*5521Sas200622 	switch (acl_info->acl_type) {
909*5521Sas200622 	case ACLENT_T:
910*5521Sas200622 		numacls = acl_info->acl_cnt;
911*5521Sas200622 		/*
912*5521Sas200622 		 * Minimum ACL size is three entries so might as well
913*5521Sas200622 		 * bail out here.  Also limit request size to prevent user
914*5521Sas200622 		 * from allocating too much kernel memory.  Maximum size
915*5521Sas200622 		 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES
916*5521Sas200622 		 * for the default ACL part.
917*5521Sas200622 		 */
918*5521Sas200622 		if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) {
919*5521Sas200622 			error = EINVAL;
920*5521Sas200622 			break;
921*5521Sas200622 		}
922*5521Sas200622 
923*5521Sas200622 		vsecattr->vsa_mask = VSA_ACL;
924*5521Sas200622 
925*5521Sas200622 		vsecattr->vsa_aclcnt = numacls;
926*5521Sas200622 		*aclbsize = numacls * sizeof (aclent_t);
927*5521Sas200622 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
928*5521Sas200622 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
929*5521Sas200622 		    *aclbsize);
930*5521Sas200622 
931*5521Sas200622 		/* Sort the acl list */
932*5521Sas200622 		ksort((caddr_t)vsecattr->vsa_aclentp,
933*5521Sas200622 		    vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls);
934*5521Sas200622 
935*5521Sas200622 		/* Break into acl and default acl lists */
936*5521Sas200622 		for (numacls = 0, aclp = vsecattr->vsa_aclentp;
937*5521Sas200622 		    numacls < vsecattr->vsa_aclcnt;
938*5521Sas200622 		    aclp++, numacls++) {
939*5521Sas200622 			if (aclp->a_type & ACL_DEFAULT)
940*5521Sas200622 				break;
941*5521Sas200622 		}
942*5521Sas200622 
943*5521Sas200622 		/* Find where defaults start (if any) */
944*5521Sas200622 		if (numacls < vsecattr->vsa_aclcnt) {
945*5521Sas200622 			vsecattr->vsa_mask |= VSA_DFACL;
946*5521Sas200622 			vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls;
947*5521Sas200622 			vsecattr->vsa_dfaclentp = aclp;
948*5521Sas200622 			vsecattr->vsa_aclcnt = numacls;
949*5521Sas200622 		}
950*5521Sas200622 
951*5521Sas200622 		/* Adjust if they're all defaults */
952*5521Sas200622 		if (vsecattr->vsa_aclcnt == 0) {
953*5521Sas200622 			vsecattr->vsa_mask &= ~VSA_ACL;
954*5521Sas200622 			vsecattr->vsa_aclentp = NULL;
955*5521Sas200622 		}
956*5521Sas200622 
957*5521Sas200622 		/* Only directories can have defaults */
958*5521Sas200622 		if (vsecattr->vsa_dfaclcnt &&
959*5521Sas200622 		    (acl_info->acl_flags & ACL_IS_DIR)) {
960*5521Sas200622 			error = ENOTDIR;
961*5521Sas200622 		}
962*5521Sas200622 
963*5521Sas200622 		break;
964*5521Sas200622 
965*5521Sas200622 	case ACE_T:
966*5521Sas200622 		if (acl_info->acl_cnt < 1 ||
967*5521Sas200622 		    acl_info->acl_cnt > MAX_ACL_ENTRIES) {
968*5521Sas200622 			error = EINVAL;
969*5521Sas200622 			break;
970*5521Sas200622 		}
971*5521Sas200622 
972*5521Sas200622 		vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS;
973*5521Sas200622 		vsecattr->vsa_aclcnt = acl_info->acl_cnt;
974*5521Sas200622 		vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL;
975*5521Sas200622 		*aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t);
976*5521Sas200622 		vsecattr->vsa_aclentsz = *aclbsize;
977*5521Sas200622 		vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP);
978*5521Sas200622 		(void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp,
979*5521Sas200622 		    *aclbsize);
980*5521Sas200622 
981*5521Sas200622 		break;
982*5521Sas200622 
983*5521Sas200622 	default:
984*5521Sas200622 		error = EINVAL;
985*5521Sas200622 	}
986*5521Sas200622 
987*5521Sas200622 	return (error);
988*5521Sas200622 }
989*5521Sas200622 
990*5521Sas200622 /*
991*5521Sas200622  * smb_fsacl_inheritable
992*5521Sas200622  *
993*5521Sas200622  * Checks to see if there are any inheritable ACEs in the
994*5521Sas200622  * given ZFS ACL. Returns the number of inheritable ACEs.
995*5521Sas200622  *
996*5521Sas200622  * The inherited ACL could be different based on the type of
997*5521Sas200622  * new object (file/dir) specified by 'is_dir'.
998*5521Sas200622  *
999*5521Sas200622  * Note that the input ACL is a ZFS ACL not Windows ACL.
1000*5521Sas200622  *
1001*5521Sas200622  * Any ACE except creator owner/group:
1002*5521Sas200622  *
1003*5521Sas200622  *  FI   DI   NP   #F  #D
1004*5521Sas200622  * ---- ---- ---- ---- ----
1005*5521Sas200622  *  -    -    ?    0    0
1006*5521Sas200622  *  X    -    -    1    1
1007*5521Sas200622  *  X    -    X    1    0
1008*5521Sas200622  *  -    X    -    0    1
1009*5521Sas200622  *  -    X    X    0    1
1010*5521Sas200622  *  X    X    -    1    1
1011*5521Sas200622  *  X    X    X    1    1
1012*5521Sas200622  *
1013*5521Sas200622  * Creator owner/group ACE:
1014*5521Sas200622  *
1015*5521Sas200622  *  FI   DI   NP   #F  #D
1016*5521Sas200622  * ---- ---- ---- ---- ----
1017*5521Sas200622  *  -    -    ?    0    0
1018*5521Sas200622  *  X    -    -    1r   1c
1019*5521Sas200622  *  X    -    X    1r   0
1020*5521Sas200622  *  -    X    -    0    2
1021*5521Sas200622  *  -    X    X    0    1r
1022*5521Sas200622  *  X    X    -    1r   2
1023*5521Sas200622  *  X    X    X    1r   1r
1024*5521Sas200622  *
1025*5521Sas200622  * Legend:
1026*5521Sas200622  *
1027*5521Sas200622  *  FI: File Inherit
1028*5521Sas200622  *  DI: Dir Inherit
1029*5521Sas200622  *  NP: No Propagate
1030*5521Sas200622  *  #F: #ACE for a new file
1031*5521Sas200622  *  #D: #ACE for a new dir
1032*5521Sas200622  *
1033*5521Sas200622  *   X: bit is set
1034*5521Sas200622  *   -: bit is not set
1035*5521Sas200622  *   ?: don't care
1036*5521Sas200622  *
1037*5521Sas200622  *  1r: one owner/group ACE
1038*5521Sas200622  *  1c: one creator owner/group ACE
1039*5521Sas200622  */
1040*5521Sas200622 static int
1041*5521Sas200622 smb_fsacl_inheritable(acl_t *zacl, int is_dir)
1042*5521Sas200622 {
1043*5521Sas200622 	int numaces;
1044*5521Sas200622 	int num_inheritable = 0;
1045*5521Sas200622 	ace_t *zace;
1046*5521Sas200622 
1047*5521Sas200622 	if (zacl == NULL)
1048*5521Sas200622 		return (0);
1049*5521Sas200622 
1050*5521Sas200622 	for (numaces = 0, zace = zacl->acl_aclp;
1051*5521Sas200622 	    numaces < zacl->acl_cnt;
1052*5521Sas200622 	    zace++, numaces++) {
1053*5521Sas200622 		switch (zace->a_flags & ACE_FD_INHERIT_ACE) {
1054*5521Sas200622 		case (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE):
1055*5521Sas200622 			/*
1056*5521Sas200622 			 * Files inherit an effective ACE.
1057*5521Sas200622 			 *
1058*5521Sas200622 			 * Dirs inherit an effective ACE.
1059*5521Sas200622 			 * The inherited ACE is inheritable unless the
1060*5521Sas200622 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set
1061*5521Sas200622 			 */
1062*5521Sas200622 			num_inheritable++;
1063*5521Sas200622 
1064*5521Sas200622 			if (is_dir && ZACE_IS_CREATOR(zace) &&
1065*5521Sas200622 			    (ZACE_IS_PROPAGATE(zace))) {
1066*5521Sas200622 				num_inheritable++;
1067*5521Sas200622 			}
1068*5521Sas200622 			break;
1069*5521Sas200622 
1070*5521Sas200622 		case ACE_FILE_INHERIT_ACE:
1071*5521Sas200622 			/*
1072*5521Sas200622 			 * Files inherit as an effective ACE.
1073*5521Sas200622 			 *
1074*5521Sas200622 			 * Dirs inherit an inherit-only ACE
1075*5521Sas200622 			 * unless the ACE_NO_PROPAGATE_INHERIT_ACE bit
1076*5521Sas200622 			 * flag is also set.
1077*5521Sas200622 			 */
1078*5521Sas200622 			if (is_dir == 0)
1079*5521Sas200622 				num_inheritable++;
1080*5521Sas200622 			else if (ZACE_IS_PROPAGATE(zace))
1081*5521Sas200622 				num_inheritable++;
1082*5521Sas200622 			break;
1083*5521Sas200622 
1084*5521Sas200622 		case ACE_DIRECTORY_INHERIT_ACE:
1085*5521Sas200622 			/*
1086*5521Sas200622 			 * No effect on files
1087*5521Sas200622 			 *
1088*5521Sas200622 			 * Dirs inherit an effective ACE.
1089*5521Sas200622 			 * The inherited ACE is inheritable unless the
1090*5521Sas200622 			 * ACE_NO_PROPAGATE_INHERIT_ACE bit flag is also set.
1091*5521Sas200622 			 */
1092*5521Sas200622 			if (is_dir == 0)
1093*5521Sas200622 				break;
1094*5521Sas200622 
1095*5521Sas200622 			num_inheritable++;
1096*5521Sas200622 
1097*5521Sas200622 			if (ZACE_IS_CREATOR(zace) &&
1098*5521Sas200622 			    (ZACE_IS_PROPAGATE(zace)))
1099*5521Sas200622 				num_inheritable++;
1100*5521Sas200622 			break;
1101*5521Sas200622 
1102*5521Sas200622 		default:
1103*5521Sas200622 			break;
1104*5521Sas200622 		}
1105*5521Sas200622 	}
1106*5521Sas200622 
1107*5521Sas200622 	return (num_inheritable);
1108*5521Sas200622 }
1109*5521Sas200622 
1110*5521Sas200622 
1111*5521Sas200622 /*
1112*5521Sas200622  * ACE Functions
1113*5521Sas200622  */
1114*5521Sas200622 
1115*5521Sas200622 /*
1116*5521Sas200622  * This is generic (ACL version 2) vs. object-specific
1117*5521Sas200622  * (ACL version 4) ACE types.
1118*5521Sas200622  */
1119*5521Sas200622 boolean_t
1120*5521Sas200622 smb_ace_is_generic(int type)
1121*5521Sas200622 {
1122*5521Sas200622 	switch (type) {
1123*5521Sas200622 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
1124*5521Sas200622 	case ACE_ACCESS_DENIED_ACE_TYPE:
1125*5521Sas200622 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
1126*5521Sas200622 	case ACE_SYSTEM_ALARM_ACE_TYPE:
1127*5521Sas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
1128*5521Sas200622 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
1129*5521Sas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
1130*5521Sas200622 	case ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE:
1131*5521Sas200622 		return (B_TRUE);
1132*5521Sas200622 
1133*5521Sas200622 	default:
1134*5521Sas200622 		break;
1135*5521Sas200622 	}
1136*5521Sas200622 
1137*5521Sas200622 	return (B_FALSE);
1138*5521Sas200622 }
1139*5521Sas200622 
1140*5521Sas200622 boolean_t
1141*5521Sas200622 smb_ace_is_access(int type)
1142*5521Sas200622 {
1143*5521Sas200622 	switch (type) {
1144*5521Sas200622 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
1145*5521Sas200622 	case ACE_ACCESS_DENIED_ACE_TYPE:
1146*5521Sas200622 	case ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
1147*5521Sas200622 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1148*5521Sas200622 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1149*5521Sas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
1150*5521Sas200622 	case ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE:
1151*5521Sas200622 	case ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE:
1152*5521Sas200622 	case ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE:
1153*5521Sas200622 		return (B_TRUE);
1154*5521Sas200622 
1155*5521Sas200622 	default:
1156*5521Sas200622 		break;
1157*5521Sas200622 	}
1158*5521Sas200622 
1159*5521Sas200622 	return (B_FALSE);
1160*5521Sas200622 }
1161*5521Sas200622 
1162*5521Sas200622 boolean_t
1163*5521Sas200622 smb_ace_is_audit(int type)
1164*5521Sas200622 {
1165*5521Sas200622 	switch (type) {
1166*5521Sas200622 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
1167*5521Sas200622 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1168*5521Sas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE:
1169*5521Sas200622 	case ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE:
1170*5521Sas200622 		return (B_TRUE);
1171*5521Sas200622 
1172*5521Sas200622 	default:
1173*5521Sas200622 		break;
1174*5521Sas200622 	}
1175*5521Sas200622 
1176*5521Sas200622 	return (B_FALSE);
1177*5521Sas200622 }
1178*5521Sas200622 
1179*5521Sas200622 /*
1180*5521Sas200622  * smb_ace_len
1181*5521Sas200622  *
1182*5521Sas200622  * Returns the length of the given ACE as it appears in an
1183*5521Sas200622  * ACL on the wire (i.e. a flat buffer which contains the SID)
1184*5521Sas200622  */
1185*5521Sas200622 static uint16_t
1186*5521Sas200622 smb_ace_len(smb_ace_t *ace)
1187*5521Sas200622 {
1188*5521Sas200622 	ASSERT(ace);
1189*5521Sas200622 	ASSERT(ace->se_sid);
1190*5521Sas200622 
1191*5521Sas200622 	if (ace == NULL)
1192*5521Sas200622 		return (0);
1193*5521Sas200622 
1194*5521Sas200622 	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
1195*5521Sas200622 	    nt_sid_length(ace->se_sid));
1196*5521Sas200622 }
1197*5521Sas200622 
11985331Samw static void
11995331Samw smb_ace_inherit(ace_t *dir_zace, ace_t *zace, int is_dir)
12005331Samw {
12015331Samw 	*zace = *dir_zace;
12025331Samw 	if (!(is_dir && ZACE_IS_PROPAGATE(dir_zace)))
12035331Samw 		zace->a_flags &= ~ACE_INHERIT_FLAGS;
12045331Samw 	zace->a_flags |= ACE_INHERITED_ACE;
12055331Samw 
12065331Samw 	/*
12075331Samw 	 * Replace creator owner/group ACEs with
12085331Samw 	 * actual owner/group ACEs.
12095331Samw 	 */
12105331Samw 	if (ZACE_IS_CREATOR_OWNER(dir_zace)) {
12115331Samw 		zace->a_who = (uid_t)-1;
12125331Samw 		zace->a_flags |= ACE_OWNER;
12135331Samw 	} else if (ZACE_IS_CREATOR_GROUP(dir_zace)) {
12145331Samw 		zace->a_who = (uid_t)-1;
12155331Samw 		zace->a_flags |= ACE_GROUP;
12165331Samw 	}
12175331Samw }
12185331Samw 
1219*5521Sas200622 /*
1220*5521Sas200622  * smb_ace_mask_g2s
1221*5521Sas200622  *
1222*5521Sas200622  * Converts generic access bits in the given mask (if any)
1223*5521Sas200622  * to file specific bits. Generic access masks shouldn't be
1224*5521Sas200622  * stored in filesystem ACEs.
1225*5521Sas200622  */
1226*5521Sas200622 static uint32_t
1227*5521Sas200622 smb_ace_mask_g2s(uint32_t mask)
1228*5521Sas200622 {
1229*5521Sas200622 	if (mask & GENERIC_ALL) {
1230*5521Sas200622 		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
1231*5521Sas200622 		    | GENERIC_EXECUTE);
1232*5521Sas200622 
1233*5521Sas200622 		mask |= FILE_ALL_ACCESS;
1234*5521Sas200622 		return (mask);
1235*5521Sas200622 	}
1236*5521Sas200622 
1237*5521Sas200622 	if (mask & GENERIC_READ) {
1238*5521Sas200622 		mask &= ~GENERIC_READ;
1239*5521Sas200622 		mask |= FILE_GENERIC_READ;
1240*5521Sas200622 	}
1241*5521Sas200622 
1242*5521Sas200622 	if (mask & GENERIC_WRITE) {
1243*5521Sas200622 		mask &= ~GENERIC_WRITE;
1244*5521Sas200622 		mask |= FILE_GENERIC_WRITE;
1245*5521Sas200622 	}
1246*5521Sas200622 
1247*5521Sas200622 	if (mask & GENERIC_EXECUTE) {
1248*5521Sas200622 		mask &= ~GENERIC_EXECUTE;
1249*5521Sas200622 		mask |= FILE_GENERIC_EXECUTE;
1250*5521Sas200622 	}
1251*5521Sas200622 
1252*5521Sas200622 	return (mask);
1253*5521Sas200622 }
1254*5521Sas200622 
12555331Samw static uint16_t
12565331Samw smb_ace_flags_tozfs(uint8_t c_flags, int isdir)
12575331Samw {
12585331Samw 	uint16_t z_flags = 0;
12595331Samw 
12605331Samw 	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
12615331Samw 		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
12625331Samw 
12635331Samw 	if (c_flags & FAILED_ACCESS_ACE_FLAG)
12645331Samw 		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
12655331Samw 
12665331Samw 	if (c_flags & INHERITED_ACE)
12675331Samw 		z_flags |= ACE_INHERITED_ACE;
12685331Samw 
12695331Samw 	/*
12705331Samw 	 * ZFS doesn't like any inheritance flags to be set on a
12715331Samw 	 * file's ACE, only directories. Windows doesn't care.
12725331Samw 	 */
12735331Samw 	if (isdir)
12745331Samw 		z_flags |= (c_flags & ACE_INHERIT_FLAGS);
12755331Samw 
12765331Samw 	return (z_flags);
12775331Samw }
12785331Samw 
12795331Samw static uint8_t
12805331Samw smb_ace_flags_fromzfs(uint16_t z_flags)
12815331Samw {
12825331Samw 	uint8_t c_flags;
12835331Samw 
12845331Samw 	c_flags = z_flags & ACE_INHERIT_FLAGS;
12855331Samw 
12865331Samw 	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
12875331Samw 		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
12885331Samw 
12895331Samw 	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
12905331Samw 		c_flags |= FAILED_ACCESS_ACE_FLAG;
12915331Samw 
12925331Samw 	if (z_flags & ACE_INHERITED_ACE)
12935331Samw 		c_flags |= INHERITED_ACE;
12945331Samw 
12955331Samw 	return (c_flags);
12965331Samw }
12975331Samw 
1298*5521Sas200622 static boolean_t
1299*5521Sas200622 smb_ace_isvalid(smb_ace_t *ace, int which_acl)
13005331Samw {
1301*5521Sas200622 	uint16_t min_len;
1302*5521Sas200622 
1303*5521Sas200622 	min_len = sizeof (smb_acehdr_t);
1304*5521Sas200622 
1305*5521Sas200622 	if (ace->se_hdr.se_bsize < min_len)
1306*5521Sas200622 		return (B_FALSE);
1307*5521Sas200622 
1308*5521Sas200622 	if (smb_ace_is_access(ace->se_hdr.se_type) &&
1309*5521Sas200622 	    (which_acl != SMB_DACL_SECINFO))
1310*5521Sas200622 		return (B_FALSE);
13115331Samw 
1312*5521Sas200622 	if (smb_ace_is_audit(ace->se_hdr.se_type) &&
1313*5521Sas200622 	    (which_acl != SMB_SACL_SECINFO))
1314*5521Sas200622 		return (B_FALSE);
1315*5521Sas200622 
1316*5521Sas200622 	if (smb_ace_is_generic(ace->se_hdr.se_type)) {
1317*5521Sas200622 		if (nt_sid_is_valid(ace->se_sid) == 0)
1318*5521Sas200622 			return (B_FALSE);
1319*5521Sas200622 
1320*5521Sas200622 		min_len += sizeof (ace->se_mask);
1321*5521Sas200622 		min_len += nt_sid_length(ace->se_sid);
1322*5521Sas200622 
1323*5521Sas200622 		if (ace->se_hdr.se_bsize < min_len)
1324*5521Sas200622 			return (B_FALSE);
13255331Samw 	}
13265331Samw 
1327*5521Sas200622 	/*
1328*5521Sas200622 	 * object-specific ACE validation will be added later.
1329*5521Sas200622 	 */
1330*5521Sas200622 	return (B_TRUE);
13315331Samw }
1332