xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision b3d141f8c7a5335d670721a81f797b1834ee327b)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
22e6032be1Smarks  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/types.h>
29fa9e4066Sahrens #include <sys/param.h>
30fa9e4066Sahrens #include <sys/time.h>
31fa9e4066Sahrens #include <sys/systm.h>
32fa9e4066Sahrens #include <sys/sysmacros.h>
33fa9e4066Sahrens #include <sys/resource.h>
34fa9e4066Sahrens #include <sys/vfs.h>
35fa9e4066Sahrens #include <sys/vnode.h>
36da6c28aaSamw #include <sys/sid.h>
37fa9e4066Sahrens #include <sys/file.h>
38fa9e4066Sahrens #include <sys/stat.h>
39fa9e4066Sahrens #include <sys/kmem.h>
40fa9e4066Sahrens #include <sys/cmn_err.h>
41fa9e4066Sahrens #include <sys/errno.h>
42fa9e4066Sahrens #include <sys/unistd.h>
43169cdae2Smarks #include <sys/sdt.h>
44fa9e4066Sahrens #include <sys/fs/zfs.h>
45fa9e4066Sahrens #include <sys/mode.h>
46fa9e4066Sahrens #include <sys/policy.h>
47fa9e4066Sahrens #include <sys/zfs_znode.h>
48da6c28aaSamw #include <sys/zfs_fuid.h>
49fa9e4066Sahrens #include <sys/zfs_acl.h>
50fa9e4066Sahrens #include <sys/zfs_dir.h>
51fa9e4066Sahrens #include <sys/zfs_vfsops.h>
52fa9e4066Sahrens #include <sys/dmu.h>
53da6c28aaSamw #include <sys/dnode.h>
54fa9e4066Sahrens #include <sys/zap.h>
55fa9e4066Sahrens #include "fs/fs_subr.h"
56fa9e4066Sahrens #include <acl/acl_common.h>
57fa9e4066Sahrens 
58fa9e4066Sahrens #define	ALLOW	ACE_ACCESS_ALLOWED_ACE_TYPE
59fa9e4066Sahrens #define	DENY	ACE_ACCESS_DENIED_ACE_TYPE
60da6c28aaSamw #define	MAX_ACE_TYPE	ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
61fa9e4066Sahrens 
62fa9e4066Sahrens #define	OWNING_GROUP		(ACE_GROUP|ACE_IDENTIFIER_GROUP)
63fa9e4066Sahrens #define	EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
64fa9e4066Sahrens     ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
65fa9e4066Sahrens #define	EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
66fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
67fa9e4066Sahrens #define	OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
68fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
69da6c28aaSamw #define	WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
70da6c28aaSamw 
71da6c28aaSamw #define	ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
72da6c28aaSamw     ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
73da6c28aaSamw     ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
74da6c28aaSamw     ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
75da6c28aaSamw 
76da6c28aaSamw #define	WRITE_MASK (WRITE_MASK_DATA|ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|\
77da6c28aaSamw     ACE_WRITE_OWNER)
78fa9e4066Sahrens 
79fa9e4066Sahrens #define	OGE_CLEAR	(ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
80fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
81fa9e4066Sahrens 
82fa9e4066Sahrens #define	OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
83fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
84fa9e4066Sahrens 
85fa9e4066Sahrens #define	ALL_INHERIT	(ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
86da6c28aaSamw     ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
87fa9e4066Sahrens 
88*b3d141f8Smarks #define	RESTRICTED_CLEAR	(ACE_WRITE_ACL|ACE_WRITE_OWNER)
89fa9e4066Sahrens 
90da6c28aaSamw #define	V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
91da6c28aaSamw     ZFS_ACL_PROTECTED)
92da6c28aaSamw 
93da6c28aaSamw #define	ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
94da6c28aaSamw     ZFS_ACL_OBJ_ACE)
95da6c28aaSamw 
96da6c28aaSamw static uint16_t
97da6c28aaSamw zfs_ace_v0_get_type(void *acep)
98da6c28aaSamw {
99da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_type);
100da6c28aaSamw }
101da6c28aaSamw 
102da6c28aaSamw static uint16_t
103da6c28aaSamw zfs_ace_v0_get_flags(void *acep)
104da6c28aaSamw {
105da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_flags);
106da6c28aaSamw }
107fa9e4066Sahrens 
108da6c28aaSamw static uint32_t
109da6c28aaSamw zfs_ace_v0_get_mask(void *acep)
110da6c28aaSamw {
111da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_access_mask);
112da6c28aaSamw }
113da6c28aaSamw 
114da6c28aaSamw static uint64_t
115da6c28aaSamw zfs_ace_v0_get_who(void *acep)
116da6c28aaSamw {
117da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_fuid);
118da6c28aaSamw }
119da6c28aaSamw 
120da6c28aaSamw static void
121da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type)
122da6c28aaSamw {
123da6c28aaSamw 	((zfs_oldace_t *)acep)->z_type = type;
124da6c28aaSamw }
125da6c28aaSamw 
126da6c28aaSamw static void
127da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags)
128da6c28aaSamw {
129da6c28aaSamw 	((zfs_oldace_t *)acep)->z_flags = flags;
130da6c28aaSamw }
131da6c28aaSamw 
132da6c28aaSamw static void
133da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask)
134da6c28aaSamw {
135da6c28aaSamw 	((zfs_oldace_t *)acep)->z_access_mask = mask;
136da6c28aaSamw }
137da6c28aaSamw 
138da6c28aaSamw static void
139da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who)
140da6c28aaSamw {
141da6c28aaSamw 	((zfs_oldace_t *)acep)->z_fuid = who;
142da6c28aaSamw }
143da6c28aaSamw 
144da6c28aaSamw /*ARGSUSED*/
145da6c28aaSamw static size_t
146da6c28aaSamw zfs_ace_v0_size(void *acep)
147da6c28aaSamw {
148da6c28aaSamw 	return (sizeof (zfs_oldace_t));
149da6c28aaSamw }
150da6c28aaSamw 
151da6c28aaSamw static size_t
152da6c28aaSamw zfs_ace_v0_abstract_size(void)
153da6c28aaSamw {
154da6c28aaSamw 	return (sizeof (zfs_oldace_t));
155da6c28aaSamw }
156da6c28aaSamw 
157da6c28aaSamw static int
158da6c28aaSamw zfs_ace_v0_mask_off(void)
159da6c28aaSamw {
160da6c28aaSamw 	return (offsetof(zfs_oldace_t, z_access_mask));
161da6c28aaSamw }
162da6c28aaSamw 
163da6c28aaSamw /*ARGSUSED*/
164da6c28aaSamw static int
165da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap)
166da6c28aaSamw {
167da6c28aaSamw 	*datap = NULL;
168da6c28aaSamw 	return (0);
169da6c28aaSamw }
170da6c28aaSamw 
171da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = {
172da6c28aaSamw 	zfs_ace_v0_get_mask,
173da6c28aaSamw 	zfs_ace_v0_set_mask,
174da6c28aaSamw 	zfs_ace_v0_get_flags,
175da6c28aaSamw 	zfs_ace_v0_set_flags,
176da6c28aaSamw 	zfs_ace_v0_get_type,
177da6c28aaSamw 	zfs_ace_v0_set_type,
178da6c28aaSamw 	zfs_ace_v0_get_who,
179da6c28aaSamw 	zfs_ace_v0_set_who,
180da6c28aaSamw 	zfs_ace_v0_size,
181da6c28aaSamw 	zfs_ace_v0_abstract_size,
182da6c28aaSamw 	zfs_ace_v0_mask_off,
183da6c28aaSamw 	zfs_ace_v0_data
184da6c28aaSamw };
185da6c28aaSamw 
186da6c28aaSamw static uint16_t
187da6c28aaSamw zfs_ace_fuid_get_type(void *acep)
188da6c28aaSamw {
189da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_type);
190da6c28aaSamw }
191da6c28aaSamw 
192da6c28aaSamw static uint16_t
193da6c28aaSamw zfs_ace_fuid_get_flags(void *acep)
194da6c28aaSamw {
195da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_flags);
196da6c28aaSamw }
197da6c28aaSamw 
198da6c28aaSamw static uint32_t
199da6c28aaSamw zfs_ace_fuid_get_mask(void *acep)
200da6c28aaSamw {
201da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_access_mask);
202da6c28aaSamw }
203da6c28aaSamw 
204da6c28aaSamw static uint64_t
205da6c28aaSamw zfs_ace_fuid_get_who(void *args)
206da6c28aaSamw {
207da6c28aaSamw 	uint16_t entry_type;
208da6c28aaSamw 	zfs_ace_t *acep = args;
209da6c28aaSamw 
210da6c28aaSamw 	entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
211da6c28aaSamw 
212da6c28aaSamw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
213da6c28aaSamw 	    entry_type == ACE_EVERYONE)
214da6c28aaSamw 		return (-1);
215da6c28aaSamw 	return (((zfs_ace_t *)acep)->z_fuid);
216da6c28aaSamw }
217da6c28aaSamw 
218da6c28aaSamw static void
219da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type)
220da6c28aaSamw {
221da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_type = type;
222da6c28aaSamw }
223da6c28aaSamw 
224da6c28aaSamw static void
225da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
226da6c28aaSamw {
227da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_flags = flags;
228da6c28aaSamw }
229da6c28aaSamw 
230da6c28aaSamw static void
231da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
232da6c28aaSamw {
233da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
234da6c28aaSamw }
235da6c28aaSamw 
236da6c28aaSamw static void
237da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who)
238da6c28aaSamw {
239da6c28aaSamw 	zfs_ace_t *acep = arg;
240da6c28aaSamw 
241da6c28aaSamw 	uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
242da6c28aaSamw 
243da6c28aaSamw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
244da6c28aaSamw 	    entry_type == ACE_EVERYONE)
245da6c28aaSamw 		return;
246da6c28aaSamw 	acep->z_fuid = who;
247da6c28aaSamw }
248da6c28aaSamw 
249da6c28aaSamw static size_t
250da6c28aaSamw zfs_ace_fuid_size(void *acep)
251da6c28aaSamw {
252da6c28aaSamw 	zfs_ace_hdr_t *zacep = acep;
253da6c28aaSamw 	uint16_t entry_type;
254da6c28aaSamw 
255da6c28aaSamw 	switch (zacep->z_type) {
256da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
257da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
258da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
259da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
260da6c28aaSamw 		return (sizeof (zfs_object_ace_t));
261da6c28aaSamw 	case ALLOW:
262da6c28aaSamw 	case DENY:
263da6c28aaSamw 		entry_type =
264da6c28aaSamw 		    (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
265da6c28aaSamw 		if (entry_type == ACE_OWNER ||
266da6c28aaSamw 		    entry_type == (ACE_GROUP | ACE_IDENTIFIER_GROUP) ||
267da6c28aaSamw 		    entry_type == ACE_EVERYONE)
268da6c28aaSamw 			return (sizeof (zfs_ace_hdr_t));
269da6c28aaSamw 		/*FALLTHROUGH*/
270da6c28aaSamw 	default:
271da6c28aaSamw 		return (sizeof (zfs_ace_t));
272da6c28aaSamw 	}
273da6c28aaSamw }
274da6c28aaSamw 
275da6c28aaSamw static size_t
276da6c28aaSamw zfs_ace_fuid_abstract_size(void)
277da6c28aaSamw {
278da6c28aaSamw 	return (sizeof (zfs_ace_hdr_t));
279da6c28aaSamw }
280da6c28aaSamw 
281da6c28aaSamw static int
282da6c28aaSamw zfs_ace_fuid_mask_off(void)
283da6c28aaSamw {
284da6c28aaSamw 	return (offsetof(zfs_ace_hdr_t, z_access_mask));
285da6c28aaSamw }
286da6c28aaSamw 
287da6c28aaSamw static int
288da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap)
289da6c28aaSamw {
290da6c28aaSamw 	zfs_ace_t *zacep = acep;
291da6c28aaSamw 	zfs_object_ace_t *zobjp;
292da6c28aaSamw 
293da6c28aaSamw 	switch (zacep->z_hdr.z_type) {
294da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
295da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
296da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
297da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
298da6c28aaSamw 		zobjp = acep;
299da6c28aaSamw 		*datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
300da6c28aaSamw 		return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
301da6c28aaSamw 	default:
302da6c28aaSamw 		*datap = NULL;
303da6c28aaSamw 		return (0);
304da6c28aaSamw 	}
305da6c28aaSamw }
306da6c28aaSamw 
307da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = {
308da6c28aaSamw 	zfs_ace_fuid_get_mask,
309da6c28aaSamw 	zfs_ace_fuid_set_mask,
310da6c28aaSamw 	zfs_ace_fuid_get_flags,
311da6c28aaSamw 	zfs_ace_fuid_set_flags,
312da6c28aaSamw 	zfs_ace_fuid_get_type,
313da6c28aaSamw 	zfs_ace_fuid_set_type,
314da6c28aaSamw 	zfs_ace_fuid_get_who,
315da6c28aaSamw 	zfs_ace_fuid_set_who,
316da6c28aaSamw 	zfs_ace_fuid_size,
317da6c28aaSamw 	zfs_ace_fuid_abstract_size,
318da6c28aaSamw 	zfs_ace_fuid_mask_off,
319da6c28aaSamw 	zfs_ace_fuid_data
320da6c28aaSamw };
321da6c28aaSamw 
322da6c28aaSamw static int
323da6c28aaSamw zfs_acl_version(int version)
324da6c28aaSamw {
325da6c28aaSamw 	if (version < ZPL_VERSION_FUID)
326da6c28aaSamw 		return (ZFS_ACL_VERSION_INITIAL);
327da6c28aaSamw 	else
328da6c28aaSamw 		return (ZFS_ACL_VERSION_FUID);
329da6c28aaSamw }
330da6c28aaSamw 
331da6c28aaSamw static int
332da6c28aaSamw zfs_acl_version_zp(znode_t *zp)
333da6c28aaSamw {
334da6c28aaSamw 	return (zfs_acl_version(zp->z_zfsvfs->z_version));
335da6c28aaSamw }
336fa9e4066Sahrens 
337fa9e4066Sahrens static zfs_acl_t *
338da6c28aaSamw zfs_acl_alloc(int vers)
339fa9e4066Sahrens {
340fa9e4066Sahrens 	zfs_acl_t *aclp;
341fa9e4066Sahrens 
342fa9e4066Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
343da6c28aaSamw 	list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
344da6c28aaSamw 	    offsetof(zfs_acl_node_t, z_next));
345da6c28aaSamw 	aclp->z_version = vers;
346da6c28aaSamw 	if (vers == ZFS_ACL_VERSION_FUID)
347da6c28aaSamw 		aclp->z_ops = zfs_acl_fuid_ops;
348da6c28aaSamw 	else
349da6c28aaSamw 		aclp->z_ops = zfs_acl_v0_ops;
350fa9e4066Sahrens 	return (aclp);
351fa9e4066Sahrens }
352fa9e4066Sahrens 
353da6c28aaSamw static zfs_acl_node_t *
354da6c28aaSamw zfs_acl_node_alloc(size_t bytes)
355da6c28aaSamw {
356da6c28aaSamw 	zfs_acl_node_t *aclnode;
357da6c28aaSamw 
358da6c28aaSamw 	aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
359da6c28aaSamw 	if (bytes) {
360da6c28aaSamw 		aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
361da6c28aaSamw 		aclnode->z_allocdata = aclnode->z_acldata;
362da6c28aaSamw 		aclnode->z_allocsize = bytes;
363da6c28aaSamw 		aclnode->z_size = bytes;
364da6c28aaSamw 	}
365da6c28aaSamw 
366da6c28aaSamw 	return (aclnode);
367da6c28aaSamw }
368da6c28aaSamw 
369da6c28aaSamw static void
370da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode)
371da6c28aaSamw {
372da6c28aaSamw 	if (aclnode->z_allocsize)
373da6c28aaSamw 		kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
374da6c28aaSamw 	kmem_free(aclnode, sizeof (zfs_acl_node_t));
375da6c28aaSamw }
376da6c28aaSamw 
3772459a9eaSmarks static void
3782459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp)
379fa9e4066Sahrens {
380da6c28aaSamw 	zfs_acl_node_t *aclnode;
381da6c28aaSamw 
382da6c28aaSamw 	while (aclnode = list_head(&aclp->z_acl)) {
383da6c28aaSamw 		list_remove(&aclp->z_acl, aclnode);
384da6c28aaSamw 		zfs_acl_node_free(aclnode);
385fa9e4066Sahrens 	}
3862459a9eaSmarks 	aclp->z_acl_count = 0;
3872459a9eaSmarks 	aclp->z_acl_bytes = 0;
3882459a9eaSmarks }
389da6c28aaSamw 
3902459a9eaSmarks void
3912459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp)
3922459a9eaSmarks {
3932459a9eaSmarks 	zfs_acl_release_nodes(aclp);
394da6c28aaSamw 	list_destroy(&aclp->z_acl);
395fa9e4066Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
396fa9e4066Sahrens }
397fa9e4066Sahrens 
398da6c28aaSamw static boolean_t
399da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
400fa9e4066Sahrens {
401da6c28aaSamw 	/*
402da6c28aaSamw 	 * first check type of entry
403da6c28aaSamw 	 */
404da6c28aaSamw 
405da6c28aaSamw 	switch (iflags & ACE_TYPE_FLAGS) {
406da6c28aaSamw 	case ACE_OWNER:
407da6c28aaSamw 	case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
408da6c28aaSamw 	case ACE_IDENTIFIER_GROUP:
409da6c28aaSamw 	case ACE_EVERYONE:
410da6c28aaSamw 	case 0:	/* User entry */
411da6c28aaSamw 		break;
412da6c28aaSamw 	default:
413da6c28aaSamw 		return (B_FALSE);
414da6c28aaSamw 
415da6c28aaSamw 	}
416fa9e4066Sahrens 
417169cdae2Smarks 	/*
418da6c28aaSamw 	 * next check inheritance level flags
419169cdae2Smarks 	 */
420fa9e4066Sahrens 
421da6c28aaSamw 	if (type != ALLOW && type > MAX_ACE_TYPE) {
422da6c28aaSamw 		return (B_FALSE);
423da6c28aaSamw 	}
424da6c28aaSamw 
425da6c28aaSamw 	switch (type) {
426da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
427da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
428da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
429da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
430da6c28aaSamw 		if (aclp->z_version < ZFS_ACL_VERSION_FUID)
431da6c28aaSamw 			return (B_FALSE);
432da6c28aaSamw 		aclp->z_hints |= ZFS_ACL_OBJ_ACE;
433da6c28aaSamw 	}
434da6c28aaSamw 
435da6c28aaSamw 	/*
436da6c28aaSamw 	 * Only directories should have inheritance flags.
437da6c28aaSamw 	 */
438da6c28aaSamw 	if (obj_type != VDIR && (iflags &
439da6c28aaSamw 	    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
440da6c28aaSamw 	    ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
441da6c28aaSamw 		return (B_FALSE);
442da6c28aaSamw 	}
443da6c28aaSamw 
444da6c28aaSamw 	if (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
445da6c28aaSamw 		aclp->z_hints |= ZFS_INHERIT_ACE;
446da6c28aaSamw 
447da6c28aaSamw 	if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
448da6c28aaSamw 		if ((iflags & (ACE_FILE_INHERIT_ACE|
449da6c28aaSamw 		    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
450da6c28aaSamw 			return (B_FALSE);
451da6c28aaSamw 		}
452da6c28aaSamw 	}
453da6c28aaSamw 
454da6c28aaSamw 	return (B_TRUE);
455da6c28aaSamw }
456da6c28aaSamw 
457da6c28aaSamw static void *
458da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
459da6c28aaSamw     uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
460da6c28aaSamw {
461da6c28aaSamw 	zfs_acl_node_t *aclnode;
462da6c28aaSamw 
463da6c28aaSamw 	if (start == NULL) {
464da6c28aaSamw 		aclnode = list_head(&aclp->z_acl);
465da6c28aaSamw 		if (aclnode == NULL)
466da6c28aaSamw 			return (NULL);
467da6c28aaSamw 
468da6c28aaSamw 		aclp->z_next_ace = aclnode->z_acldata;
469da6c28aaSamw 		aclp->z_curr_node = aclnode;
470da6c28aaSamw 		aclnode->z_ace_idx = 0;
471da6c28aaSamw 	}
472da6c28aaSamw 
473da6c28aaSamw 	aclnode = aclp->z_curr_node;
474da6c28aaSamw 
475da6c28aaSamw 	if (aclnode == NULL)
476da6c28aaSamw 		return (NULL);
477da6c28aaSamw 
478da6c28aaSamw 	if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
479da6c28aaSamw 		aclnode = list_next(&aclp->z_acl, aclnode);
480da6c28aaSamw 		if (aclnode == NULL)
481da6c28aaSamw 			return (NULL);
482da6c28aaSamw 		else {
483da6c28aaSamw 			aclp->z_curr_node = aclnode;
484da6c28aaSamw 			aclnode->z_ace_idx = 0;
485da6c28aaSamw 			aclp->z_next_ace = aclnode->z_acldata;
486da6c28aaSamw 		}
487da6c28aaSamw 	}
488da6c28aaSamw 
489da6c28aaSamw 	if (aclnode->z_ace_idx < aclnode->z_ace_count) {
490da6c28aaSamw 		void *acep = aclp->z_next_ace;
491da6c28aaSamw 		*iflags = aclp->z_ops.ace_flags_get(acep);
492da6c28aaSamw 		*type = aclp->z_ops.ace_type_get(acep);
493da6c28aaSamw 		*access_mask = aclp->z_ops.ace_mask_get(acep);
494da6c28aaSamw 		*who = aclp->z_ops.ace_who_get(acep);
495da6c28aaSamw 		aclp->z_next_ace = (caddr_t)aclp->z_next_ace +
496da6c28aaSamw 		    aclp->z_ops.ace_size(acep);
497da6c28aaSamw 		aclnode->z_ace_idx++;
498da6c28aaSamw 		return ((void *)acep);
499da6c28aaSamw 	}
500da6c28aaSamw 	return (NULL);
501da6c28aaSamw }
502da6c28aaSamw 
503da6c28aaSamw /*ARGSUSED*/
504da6c28aaSamw static uint64_t
505da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
506da6c28aaSamw     uint16_t *flags, uint16_t *type, uint32_t *mask)
507da6c28aaSamw {
508da6c28aaSamw 	zfs_acl_t *aclp = datap;
509da6c28aaSamw 	zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
510da6c28aaSamw 	uint64_t who;
511da6c28aaSamw 
512da6c28aaSamw 	acep = zfs_acl_next_ace(aclp, acep, &who, mask,
513da6c28aaSamw 	    flags, type);
514da6c28aaSamw 	return ((uint64_t)(uintptr_t)acep);
515da6c28aaSamw }
516da6c28aaSamw 
517da6c28aaSamw static zfs_acl_node_t *
518da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp)
519da6c28aaSamw {
520da6c28aaSamw 	ASSERT(aclp->z_curr_node);
521da6c28aaSamw 	return (aclp->z_curr_node);
522da6c28aaSamw }
523da6c28aaSamw 
524da6c28aaSamw /*
525da6c28aaSamw  * Copy ACE to internal ZFS format.
526da6c28aaSamw  * While processing the ACL each ACE will be validated for correctness.
527da6c28aaSamw  * ACE FUIDs will be created later.
528da6c28aaSamw  */
529da6c28aaSamw int
530da6c28aaSamw zfs_copy_ace_2_fuid(vtype_t obj_type, zfs_acl_t *aclp, void *datap,
531da6c28aaSamw     zfs_ace_t *z_acl, int aclcnt, size_t *size)
532da6c28aaSamw {
533da6c28aaSamw 	int i;
534da6c28aaSamw 	uint16_t entry_type;
535da6c28aaSamw 	zfs_ace_t *aceptr = z_acl;
536da6c28aaSamw 	ace_t *acep = datap;
537da6c28aaSamw 	zfs_object_ace_t *zobjacep;
538da6c28aaSamw 	ace_object_t *aceobjp;
539da6c28aaSamw 
540da6c28aaSamw 	for (i = 0; i != aclcnt; i++) {
541da6c28aaSamw 		aceptr->z_hdr.z_access_mask = acep->a_access_mask;
542da6c28aaSamw 		aceptr->z_hdr.z_flags = acep->a_flags;
543da6c28aaSamw 		aceptr->z_hdr.z_type = acep->a_type;
544da6c28aaSamw 		entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
545da6c28aaSamw 		if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
5464c841f60Smarks 		    entry_type != ACE_EVERYONE) {
5474c841f60Smarks 			if (!aclp->z_has_fuids)
548e0d35c44Smarks 				aclp->z_has_fuids = IS_EPHEMERAL(acep->a_who);
549da6c28aaSamw 			aceptr->z_fuid = (uint64_t)acep->a_who;
5504c841f60Smarks 		}
5514c841f60Smarks 
552da6c28aaSamw 		/*
553da6c28aaSamw 		 * Make sure ACE is valid
554da6c28aaSamw 		 */
555da6c28aaSamw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
556da6c28aaSamw 		    aceptr->z_hdr.z_flags) != B_TRUE)
557da6c28aaSamw 			return (EINVAL);
558da6c28aaSamw 
559da6c28aaSamw 		switch (acep->a_type) {
560da6c28aaSamw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
561da6c28aaSamw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
562da6c28aaSamw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
563da6c28aaSamw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
564da6c28aaSamw 			zobjacep = (zfs_object_ace_t *)aceptr;
565da6c28aaSamw 			aceobjp = (ace_object_t *)acep;
566da6c28aaSamw 
567da6c28aaSamw 			bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
568da6c28aaSamw 			    sizeof (aceobjp->a_obj_type));
569da6c28aaSamw 			bcopy(aceobjp->a_inherit_obj_type,
570da6c28aaSamw 			    zobjacep->z_inherit_type,
571da6c28aaSamw 			    sizeof (aceobjp->a_inherit_obj_type));
572da6c28aaSamw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
573da6c28aaSamw 			break;
574da6c28aaSamw 		default:
575da6c28aaSamw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
576da6c28aaSamw 		}
577da6c28aaSamw 
578da6c28aaSamw 		aceptr = (zfs_ace_t *)((caddr_t)aceptr +
579da6c28aaSamw 		    aclp->z_ops.ace_size(aceptr));
580da6c28aaSamw 	}
581da6c28aaSamw 
582da6c28aaSamw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
583da6c28aaSamw 
584da6c28aaSamw 	return (0);
585da6c28aaSamw }
586da6c28aaSamw 
587da6c28aaSamw /*
588da6c28aaSamw  * Copy ZFS ACEs to fixed size ace_t layout
589da6c28aaSamw  */
590da6c28aaSamw static void
591bda89588Sjp zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
592bda89588Sjp     void *datap, int filter)
593da6c28aaSamw {
594da6c28aaSamw 	uint64_t who;
595da6c28aaSamw 	uint32_t access_mask;
596da6c28aaSamw 	uint16_t iflags, type;
597da6c28aaSamw 	zfs_ace_hdr_t *zacep = NULL;
598da6c28aaSamw 	ace_t *acep = datap;
599da6c28aaSamw 	ace_object_t *objacep;
600da6c28aaSamw 	zfs_object_ace_t *zobjacep;
601da6c28aaSamw 	size_t ace_size;
602da6c28aaSamw 	uint16_t entry_type;
603da6c28aaSamw 
604da6c28aaSamw 	while (zacep = zfs_acl_next_ace(aclp, zacep,
605da6c28aaSamw 	    &who, &access_mask, &iflags, &type)) {
606da6c28aaSamw 
607da6c28aaSamw 		switch (type) {
608da6c28aaSamw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
609da6c28aaSamw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
610da6c28aaSamw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
611da6c28aaSamw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
612da6c28aaSamw 			if (filter) {
613da6c28aaSamw 				continue;
614da6c28aaSamw 			}
615da6c28aaSamw 			zobjacep = (zfs_object_ace_t *)zacep;
616da6c28aaSamw 			objacep = (ace_object_t *)acep;
617da6c28aaSamw 			bcopy(zobjacep->z_object_type,
618da6c28aaSamw 			    objacep->a_obj_type,
619da6c28aaSamw 			    sizeof (zobjacep->z_object_type));
620da6c28aaSamw 			bcopy(zobjacep->z_inherit_type,
621da6c28aaSamw 			    objacep->a_inherit_obj_type,
622da6c28aaSamw 			    sizeof (zobjacep->z_inherit_type));
623da6c28aaSamw 			ace_size = sizeof (ace_object_t);
624da6c28aaSamw 			break;
625da6c28aaSamw 		default:
626da6c28aaSamw 			ace_size = sizeof (ace_t);
627da6c28aaSamw 			break;
628da6c28aaSamw 		}
629da6c28aaSamw 
630da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
631da6c28aaSamw 		if ((entry_type != ACE_OWNER &&
632da6c28aaSamw 		    entry_type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
633e0d35c44Smarks 		    entry_type != ACE_EVERYONE)) {
634e0d35c44Smarks 			acep->a_who = zfs_fuid_map_id(zfsvfs, who,
635e0d35c44Smarks 			    cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
636e0d35c44Smarks 			    ZFS_ACE_GROUP : ZFS_ACE_USER);
637e0d35c44Smarks 		} else {
638da6c28aaSamw 			acep->a_who = (uid_t)(int64_t)who;
639e0d35c44Smarks 		}
640da6c28aaSamw 		acep->a_access_mask = access_mask;
641da6c28aaSamw 		acep->a_flags = iflags;
642da6c28aaSamw 		acep->a_type = type;
643da6c28aaSamw 		acep = (ace_t *)((caddr_t)acep + ace_size);
644da6c28aaSamw 	}
645da6c28aaSamw }
646da6c28aaSamw 
647da6c28aaSamw static int
648da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
649da6c28aaSamw     zfs_oldace_t *z_acl, int aclcnt, size_t *size)
650da6c28aaSamw {
651da6c28aaSamw 	int i;
652da6c28aaSamw 	zfs_oldace_t *aceptr = z_acl;
653da6c28aaSamw 
654da6c28aaSamw 	for (i = 0; i != aclcnt; i++, aceptr++) {
655da6c28aaSamw 		aceptr->z_access_mask = acep[i].a_access_mask;
656da6c28aaSamw 		aceptr->z_type = acep[i].a_type;
657da6c28aaSamw 		aceptr->z_flags = acep[i].a_flags;
658da6c28aaSamw 		aceptr->z_fuid = acep[i].a_who;
659da6c28aaSamw 		/*
660da6c28aaSamw 		 * Make sure ACE is valid
661da6c28aaSamw 		 */
662da6c28aaSamw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
663da6c28aaSamw 		    aceptr->z_flags) != B_TRUE)
664da6c28aaSamw 			return (EINVAL);
665da6c28aaSamw 	}
666da6c28aaSamw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
667da6c28aaSamw 	return (0);
668da6c28aaSamw }
669da6c28aaSamw 
670da6c28aaSamw /*
671da6c28aaSamw  * convert old ACL format to new
672da6c28aaSamw  */
673da6c28aaSamw void
674da6c28aaSamw zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp)
675da6c28aaSamw {
676da6c28aaSamw 	zfs_oldace_t *oldaclp;
677da6c28aaSamw 	int i;
678da6c28aaSamw 	uint16_t type, iflags;
679da6c28aaSamw 	uint32_t access_mask;
680da6c28aaSamw 	uint64_t who;
681da6c28aaSamw 	void *cookie = NULL;
6822459a9eaSmarks 	zfs_acl_node_t *newaclnode;
683da6c28aaSamw 
684da6c28aaSamw 	ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
685da6c28aaSamw 	/*
686da6c28aaSamw 	 * First create the ACE in a contiguous piece of memory
687da6c28aaSamw 	 * for zfs_copy_ace_2_fuid().
688da6c28aaSamw 	 *
689da6c28aaSamw 	 * We only convert an ACL once, so this won't happen
690da6c28aaSamw 	 * everytime.
691da6c28aaSamw 	 */
692da6c28aaSamw 	oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
693da6c28aaSamw 	    KM_SLEEP);
694da6c28aaSamw 	i = 0;
695da6c28aaSamw 	while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
696da6c28aaSamw 	    &access_mask, &iflags, &type)) {
697da6c28aaSamw 		oldaclp[i].z_flags = iflags;
698da6c28aaSamw 		oldaclp[i].z_type = type;
699da6c28aaSamw 		oldaclp[i].z_fuid = who;
700da6c28aaSamw 		oldaclp[i++].z_access_mask = access_mask;
701da6c28aaSamw 	}
702da6c28aaSamw 
703da6c28aaSamw 	newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
704da6c28aaSamw 	    sizeof (zfs_object_ace_t));
705da6c28aaSamw 	aclp->z_ops = zfs_acl_fuid_ops;
706da6c28aaSamw 	VERIFY(zfs_copy_ace_2_fuid(ZTOV(zp)->v_type, aclp, oldaclp,
707da6c28aaSamw 	    newaclnode->z_acldata, aclp->z_acl_count,
708da6c28aaSamw 	    &newaclnode->z_size) == 0);
709da6c28aaSamw 	newaclnode->z_ace_count = aclp->z_acl_count;
710da6c28aaSamw 	aclp->z_version = ZFS_ACL_VERSION;
711da6c28aaSamw 	kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
712da6c28aaSamw 
713da6c28aaSamw 	/*
714da6c28aaSamw 	 * Release all previous ACL nodes
715da6c28aaSamw 	 */
716da6c28aaSamw 
7172459a9eaSmarks 	zfs_acl_release_nodes(aclp);
7182459a9eaSmarks 
719da6c28aaSamw 	list_insert_head(&aclp->z_acl, newaclnode);
7202459a9eaSmarks 
7212459a9eaSmarks 	aclp->z_acl_bytes = newaclnode->z_size;
7222459a9eaSmarks 	aclp->z_acl_count = newaclnode->z_ace_count;
7232459a9eaSmarks 
724fa9e4066Sahrens }
725fa9e4066Sahrens 
726fa9e4066Sahrens /*
727fa9e4066Sahrens  * Convert unix access mask to v4 access mask
728fa9e4066Sahrens  */
729fa9e4066Sahrens static uint32_t
730fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask)
731fa9e4066Sahrens {
732fa9e4066Sahrens 	uint32_t new_mask = 0;
733fa9e4066Sahrens 
734da6c28aaSamw 	if (access_mask & S_IXOTH)
735da6c28aaSamw 		new_mask |= ACE_EXECUTE;
736da6c28aaSamw 	if (access_mask & S_IWOTH)
737da6c28aaSamw 		new_mask |= ACE_WRITE_DATA;
738da6c28aaSamw 	if (access_mask & S_IROTH)
739fa9e4066Sahrens 		new_mask |= ACE_READ_DATA;
740fa9e4066Sahrens 	return (new_mask);
741fa9e4066Sahrens }
742fa9e4066Sahrens 
743fa9e4066Sahrens static void
744da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
745da6c28aaSamw     uint16_t access_type, uint64_t fuid, uint16_t entry_type)
746fa9e4066Sahrens {
747da6c28aaSamw 	uint16_t type = entry_type & ACE_TYPE_FLAGS;
748da6c28aaSamw 
749da6c28aaSamw 	aclp->z_ops.ace_mask_set(acep, access_mask);
750da6c28aaSamw 	aclp->z_ops.ace_type_set(acep, access_type);
751da6c28aaSamw 	aclp->z_ops.ace_flags_set(acep, entry_type);
752da6c28aaSamw 	if ((type != ACE_OWNER && type != (ACE_GROUP | ACE_IDENTIFIER_GROUP) &&
753da6c28aaSamw 	    type != ACE_EVERYONE))
754da6c28aaSamw 		aclp->z_ops.ace_who_set(acep, fuid);
755fa9e4066Sahrens }
756fa9e4066Sahrens 
757da6c28aaSamw /*
758da6c28aaSamw  * Determine mode of file based on ACL.
759da6c28aaSamw  * Also, create FUIDs for any User/Group ACEs
760da6c28aaSamw  */
761fa9e4066Sahrens static uint64_t
762bda89588Sjp zfs_mode_fuid_compute(znode_t *zp, zfs_acl_t *aclp, cred_t *cr,
763bda89588Sjp     zfs_fuid_info_t **fuidp, dmu_tx_t *tx)
764fa9e4066Sahrens {
765da6c28aaSamw 	int		entry_type;
766da6c28aaSamw 	mode_t		mode;
767da6c28aaSamw 	mode_t		seen = 0;
768da6c28aaSamw 	zfs_ace_hdr_t 	*acep = NULL;
769da6c28aaSamw 	uint64_t	who;
770da6c28aaSamw 	uint16_t	iflags, type;
771da6c28aaSamw 	uint32_t	access_mask;
772da6c28aaSamw 
773da6c28aaSamw 	mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
774fa9e4066Sahrens 
775da6c28aaSamw 	while (acep = zfs_acl_next_ace(aclp, acep, &who,
776da6c28aaSamw 	    &access_mask, &iflags, &type)) {
77729a0b737Smarks 
77829a0b737Smarks 		/*
77929a0b737Smarks 		 * Skip over inherit only ACEs
78029a0b737Smarks 		 */
781e6032be1Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE)
78229a0b737Smarks 			continue;
78329a0b737Smarks 
784e6032be1Smarks 		entry_type = (iflags & ACE_TYPE_FLAGS);
785e6032be1Smarks 
786fa9e4066Sahrens 		if (entry_type == ACE_OWNER) {
787da6c28aaSamw 			if ((access_mask & ACE_READ_DATA) &&
788fa9e4066Sahrens 			    (!(seen & S_IRUSR))) {
789fa9e4066Sahrens 				seen |= S_IRUSR;
790da6c28aaSamw 				if (type == ALLOW) {
791fa9e4066Sahrens 					mode |= S_IRUSR;
792fa9e4066Sahrens 				}
793fa9e4066Sahrens 			}
794da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA) &&
795fa9e4066Sahrens 			    (!(seen & S_IWUSR))) {
796fa9e4066Sahrens 				seen |= S_IWUSR;
797da6c28aaSamw 				if (type == ALLOW) {
798fa9e4066Sahrens 					mode |= S_IWUSR;
799fa9e4066Sahrens 				}
800fa9e4066Sahrens 			}
801da6c28aaSamw 			if ((access_mask & ACE_EXECUTE) &&
802fa9e4066Sahrens 			    (!(seen & S_IXUSR))) {
803fa9e4066Sahrens 				seen |= S_IXUSR;
804da6c28aaSamw 				if (type == ALLOW) {
805fa9e4066Sahrens 					mode |= S_IXUSR;
806fa9e4066Sahrens 				}
807fa9e4066Sahrens 			}
808fa9e4066Sahrens 		} else if (entry_type == OWNING_GROUP) {
809da6c28aaSamw 			if ((access_mask & ACE_READ_DATA) &&
810fa9e4066Sahrens 			    (!(seen & S_IRGRP))) {
811fa9e4066Sahrens 				seen |= S_IRGRP;
812da6c28aaSamw 				if (type == ALLOW) {
813fa9e4066Sahrens 					mode |= S_IRGRP;
814fa9e4066Sahrens 				}
815fa9e4066Sahrens 			}
816da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA) &&
817fa9e4066Sahrens 			    (!(seen & S_IWGRP))) {
818fa9e4066Sahrens 				seen |= S_IWGRP;
819da6c28aaSamw 				if (type == ALLOW) {
820fa9e4066Sahrens 					mode |= S_IWGRP;
821fa9e4066Sahrens 				}
822fa9e4066Sahrens 			}
823da6c28aaSamw 			if ((access_mask & ACE_EXECUTE) &&
824fa9e4066Sahrens 			    (!(seen & S_IXGRP))) {
825fa9e4066Sahrens 				seen |= S_IXGRP;
826da6c28aaSamw 				if (type == ALLOW) {
827fa9e4066Sahrens 					mode |= S_IXGRP;
828fa9e4066Sahrens 				}
829fa9e4066Sahrens 			}
830fa9e4066Sahrens 		} else if (entry_type == ACE_EVERYONE) {
831da6c28aaSamw 			if ((access_mask & ACE_READ_DATA)) {
832fa9e4066Sahrens 				if (!(seen & S_IRUSR)) {
833fa9e4066Sahrens 					seen |= S_IRUSR;
834da6c28aaSamw 					if (type == ALLOW) {
835fa9e4066Sahrens 						mode |= S_IRUSR;
836fa9e4066Sahrens 					}
837fa9e4066Sahrens 				}
838fa9e4066Sahrens 				if (!(seen & S_IRGRP)) {
839fa9e4066Sahrens 					seen |= S_IRGRP;
840da6c28aaSamw 					if (type == ALLOW) {
841fa9e4066Sahrens 						mode |= S_IRGRP;
842fa9e4066Sahrens 					}
843fa9e4066Sahrens 				}
844fa9e4066Sahrens 				if (!(seen & S_IROTH)) {
845fa9e4066Sahrens 					seen |= S_IROTH;
846da6c28aaSamw 					if (type == ALLOW) {
847fa9e4066Sahrens 						mode |= S_IROTH;
848fa9e4066Sahrens 					}
849fa9e4066Sahrens 				}
850fa9e4066Sahrens 			}
851da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA)) {
852fa9e4066Sahrens 				if (!(seen & S_IWUSR)) {
853fa9e4066Sahrens 					seen |= S_IWUSR;
854da6c28aaSamw 					if (type == ALLOW) {
855fa9e4066Sahrens 						mode |= S_IWUSR;
856fa9e4066Sahrens 					}
857fa9e4066Sahrens 				}
858fa9e4066Sahrens 				if (!(seen & S_IWGRP)) {
859fa9e4066Sahrens 					seen |= S_IWGRP;
860da6c28aaSamw 					if (type == ALLOW) {
861fa9e4066Sahrens 						mode |= S_IWGRP;
862fa9e4066Sahrens 					}
863fa9e4066Sahrens 				}
864fa9e4066Sahrens 				if (!(seen & S_IWOTH)) {
865fa9e4066Sahrens 					seen |= S_IWOTH;
866da6c28aaSamw 					if (type == ALLOW) {
867fa9e4066Sahrens 						mode |= S_IWOTH;
868fa9e4066Sahrens 					}
869fa9e4066Sahrens 				}
870fa9e4066Sahrens 			}
871da6c28aaSamw 			if ((access_mask & ACE_EXECUTE)) {
872fa9e4066Sahrens 				if (!(seen & S_IXUSR)) {
873fa9e4066Sahrens 					seen |= S_IXUSR;
874da6c28aaSamw 					if (type == ALLOW) {
875fa9e4066Sahrens 						mode |= S_IXUSR;
876fa9e4066Sahrens 					}
877fa9e4066Sahrens 				}
878fa9e4066Sahrens 				if (!(seen & S_IXGRP)) {
879fa9e4066Sahrens 					seen |= S_IXGRP;
880da6c28aaSamw 					if (type == ALLOW) {
881fa9e4066Sahrens 						mode |= S_IXGRP;
882fa9e4066Sahrens 					}
883fa9e4066Sahrens 				}
884fa9e4066Sahrens 				if (!(seen & S_IXOTH)) {
885fa9e4066Sahrens 					seen |= S_IXOTH;
886da6c28aaSamw 					if (type == ALLOW) {
887fa9e4066Sahrens 						mode |= S_IXOTH;
888fa9e4066Sahrens 					}
889fa9e4066Sahrens 				}
890fa9e4066Sahrens 			}
891fa9e4066Sahrens 		}
892da6c28aaSamw 		/*
893da6c28aaSamw 		 * Now handle FUID create for user/group ACEs
894da6c28aaSamw 		 */
895da6c28aaSamw 		if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
896da6c28aaSamw 			aclp->z_ops.ace_who_set(acep,
897bda89588Sjp 			    zfs_fuid_create(zp->z_zfsvfs, who, cr,
898e0d35c44Smarks 			    (entry_type == 0) ? ZFS_ACE_USER : ZFS_ACE_GROUP,
899e0d35c44Smarks 			    tx, fuidp));
900da6c28aaSamw 		}
901fa9e4066Sahrens 	}
902fa9e4066Sahrens 	return (mode);
903fa9e4066Sahrens }
904fa9e4066Sahrens 
905fa9e4066Sahrens static zfs_acl_t *
906da6c28aaSamw zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify)
907fa9e4066Sahrens {
908fa9e4066Sahrens 	zfs_acl_t	*aclp;
909da6c28aaSamw 	zfs_acl_node_t	*aclnode;
910da6c28aaSamw 
911da6c28aaSamw 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
912da6c28aaSamw 
913da6c28aaSamw 	/*
914da6c28aaSamw 	 * Version 0 to 1 znode_acl_phys has the size/count fields swapped.
915da6c28aaSamw 	 * Version 0 didn't have a size field, only a count.
916da6c28aaSamw 	 */
917da6c28aaSamw 	if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
918da6c28aaSamw 		aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size;
919da6c28aaSamw 		aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count);
920da6c28aaSamw 	} else {
921da6c28aaSamw 		aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
922da6c28aaSamw 		aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size;
923da6c28aaSamw 	}
924da6c28aaSamw 
925da6c28aaSamw 	aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0);
926da6c28aaSamw 	aclnode->z_ace_count = aclp->z_acl_count;
927da6c28aaSamw 	if (will_modify) {
928da6c28aaSamw 		bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata,
929da6c28aaSamw 		    aclp->z_acl_bytes);
930da6c28aaSamw 	} else {
931da6c28aaSamw 		aclnode->z_size = aclp->z_acl_bytes;
932da6c28aaSamw 		aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0];
933da6c28aaSamw 	}
934fa9e4066Sahrens 
935da6c28aaSamw 	list_insert_head(&aclp->z_acl, aclnode);
936fa9e4066Sahrens 
937fa9e4066Sahrens 	return (aclp);
938fa9e4066Sahrens }
939fa9e4066Sahrens 
940fa9e4066Sahrens /*
941fa9e4066Sahrens  * Read an external acl object.
942fa9e4066Sahrens  */
943ea8dc4b6Seschrock static int
944da6c28aaSamw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
945fa9e4066Sahrens {
946fa9e4066Sahrens 	uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
947fa9e4066Sahrens 	zfs_acl_t	*aclp;
948da6c28aaSamw 	size_t		aclsize;
949da6c28aaSamw 	size_t		acl_count;
950da6c28aaSamw 	zfs_acl_node_t	*aclnode;
951ea8dc4b6Seschrock 	int error;
952fa9e4066Sahrens 
953fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
954fa9e4066Sahrens 
955ea8dc4b6Seschrock 	if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) {
956da6c28aaSamw 		*aclpp = zfs_acl_node_read_internal(zp, will_modify);
957ea8dc4b6Seschrock 		return (0);
958ea8dc4b6Seschrock 	}
959fa9e4066Sahrens 
960da6c28aaSamw 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
961da6c28aaSamw 	if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
962da6c28aaSamw 		zfs_acl_phys_v0_t *zacl0 =
963da6c28aaSamw 		    (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl;
964fa9e4066Sahrens 
965da6c28aaSamw 		aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count);
966da6c28aaSamw 		acl_count = zacl0->z_acl_count;
967da6c28aaSamw 	} else {
968da6c28aaSamw 		aclsize = zp->z_phys->zp_acl.z_acl_size;
969da6c28aaSamw 		acl_count = zp->z_phys->zp_acl.z_acl_count;
970da6c28aaSamw 		if (aclsize == 0)
971da6c28aaSamw 			aclsize = acl_count * sizeof (zfs_ace_t);
972da6c28aaSamw 	}
973da6c28aaSamw 	aclnode = zfs_acl_node_alloc(aclsize);
974da6c28aaSamw 	list_insert_head(&aclp->z_acl, aclnode);
975ea8dc4b6Seschrock 	error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
976da6c28aaSamw 	    aclsize, aclnode->z_acldata);
977da6c28aaSamw 	aclnode->z_ace_count = acl_count;
978da6c28aaSamw 	aclp->z_acl_count = acl_count;
979da6c28aaSamw 	aclp->z_acl_bytes = aclsize;
980da6c28aaSamw 
981ea8dc4b6Seschrock 	if (error != 0) {
982ea8dc4b6Seschrock 		zfs_acl_free(aclp);
983ea8dc4b6Seschrock 		return (error);
984ea8dc4b6Seschrock 	}
985fa9e4066Sahrens 
986ea8dc4b6Seschrock 	*aclpp = aclp;
987ea8dc4b6Seschrock 	return (0);
988fa9e4066Sahrens }
989fa9e4066Sahrens 
990fa9e4066Sahrens /*
991da6c28aaSamw  * common code for setting ACLs.
992fa9e4066Sahrens  *
993fa9e4066Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
994fa9e4066Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
995fa9e4066Sahrens  * already checked the acl and knows whether to inherit.
996fa9e4066Sahrens  */
997fa9e4066Sahrens int
998bda89588Sjp zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr,
999bda89588Sjp     zfs_fuid_info_t **fuidp, dmu_tx_t *tx)
1000fa9e4066Sahrens {
1001fa9e4066Sahrens 	int		error;
1002fa9e4066Sahrens 	znode_phys_t	*zphys = zp->z_phys;
1003da6c28aaSamw 	zfs_acl_phys_t	*zacl = &zphys->zp_acl;
1004fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1005fa9e4066Sahrens 	uint64_t	aoid = zphys->zp_acl.z_acl_extern_obj;
1006da6c28aaSamw 	uint64_t	off = 0;
1007da6c28aaSamw 	dmu_object_type_t otype;
1008da6c28aaSamw 	zfs_acl_node_t	*aclnode;
1009fa9e4066Sahrens 
1010fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
1011fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
1012fa9e4066Sahrens 
1013fa9e4066Sahrens 	dmu_buf_will_dirty(zp->z_dbuf, tx);
1014fa9e4066Sahrens 
1015bda89588Sjp 	zphys->zp_mode = zfs_mode_fuid_compute(zp, aclp, cr, fuidp, tx);
1016da6c28aaSamw 
1017fa9e4066Sahrens 	/*
1018da6c28aaSamw 	 * Decide which opbject type to use.  If we are forced to
1019da6c28aaSamw 	 * use old ACL format than transform ACL into zfs_oldace_t
1020da6c28aaSamw 	 * layout.
1021fa9e4066Sahrens 	 */
1022da6c28aaSamw 	if (!zfsvfs->z_use_fuids) {
1023da6c28aaSamw 		otype = DMU_OT_OLDACL;
1024da6c28aaSamw 	} else {
1025da6c28aaSamw 		if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
1026da6c28aaSamw 		    (zfsvfs->z_version >= ZPL_VERSION_FUID))
1027da6c28aaSamw 			zfs_acl_xform(zp, aclp);
1028da6c28aaSamw 		ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
1029da6c28aaSamw 		otype = DMU_OT_ACL;
1030da6c28aaSamw 	}
1031da6c28aaSamw 
1032da6c28aaSamw 	if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
1033da6c28aaSamw 		/*
1034da6c28aaSamw 		 * If ACL was previously external and we are now
1035da6c28aaSamw 		 * converting to new ACL format then release old
1036da6c28aaSamw 		 * ACL object and create a new one.
1037da6c28aaSamw 		 */
1038da6c28aaSamw 		if (aoid && aclp->z_version != zacl->z_acl_version) {
1039da6c28aaSamw 			error = dmu_object_free(zfsvfs->z_os,
1040da6c28aaSamw 			    zp->z_phys->zp_acl.z_acl_extern_obj, tx);
1041da6c28aaSamw 			if (error)
1042da6c28aaSamw 				return (error);
1043da6c28aaSamw 			aoid = 0;
1044da6c28aaSamw 		}
1045fa9e4066Sahrens 		if (aoid == 0) {
1046fa9e4066Sahrens 			aoid = dmu_object_alloc(zfsvfs->z_os,
1047da6c28aaSamw 			    otype, aclp->z_acl_bytes,
1048da6c28aaSamw 			    otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE,
1049da6c28aaSamw 			    otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx);
1050fa9e4066Sahrens 		} else {
1051fa9e4066Sahrens 			(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
1052da6c28aaSamw 			    aclp->z_acl_bytes, 0, tx);
1053fa9e4066Sahrens 		}
1054fa9e4066Sahrens 		zphys->zp_acl.z_acl_extern_obj = aoid;
1055da6c28aaSamw 		for (aclnode = list_head(&aclp->z_acl); aclnode;
1056da6c28aaSamw 		    aclnode = list_next(&aclp->z_acl, aclnode)) {
1057da6c28aaSamw 			if (aclnode->z_ace_count == 0)
1058da6c28aaSamw 				continue;
1059da6c28aaSamw 			dmu_write(zfsvfs->z_os, aoid, off,
1060da6c28aaSamw 			    aclnode->z_size, aclnode->z_acldata, tx);
1061da6c28aaSamw 			off += aclnode->z_size;
1062da6c28aaSamw 		}
1063fa9e4066Sahrens 	} else {
1064da6c28aaSamw 		void *start = zacl->z_ace_data;
1065fa9e4066Sahrens 		/*
1066fa9e4066Sahrens 		 * Migrating back embedded?
1067fa9e4066Sahrens 		 */
1068fa9e4066Sahrens 		if (zphys->zp_acl.z_acl_extern_obj) {
1069fa9e4066Sahrens 			error = dmu_object_free(zfsvfs->z_os,
10707106075aSmarks 			    zp->z_phys->zp_acl.z_acl_extern_obj, tx);
1071fa9e4066Sahrens 			if (error)
1072fa9e4066Sahrens 				return (error);
1073fa9e4066Sahrens 			zphys->zp_acl.z_acl_extern_obj = 0;
1074fa9e4066Sahrens 		}
1075da6c28aaSamw 
1076da6c28aaSamw 		for (aclnode = list_head(&aclp->z_acl); aclnode;
1077da6c28aaSamw 		    aclnode = list_next(&aclp->z_acl, aclnode)) {
1078da6c28aaSamw 			if (aclnode->z_ace_count == 0)
1079da6c28aaSamw 				continue;
1080da6c28aaSamw 			bcopy(aclnode->z_acldata, start, aclnode->z_size);
1081da6c28aaSamw 			start = (caddr_t)start + aclnode->z_size;
1082da6c28aaSamw 		}
1083fa9e4066Sahrens 	}
1084de122929Smarks 
1085da6c28aaSamw 	/*
1086da6c28aaSamw 	 * If Old version then swap count/bytes to match old
1087da6c28aaSamw 	 * layout of znode_acl_phys_t.
1088da6c28aaSamw 	 */
1089da6c28aaSamw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
1090da6c28aaSamw 		zphys->zp_acl.z_acl_size = aclp->z_acl_count;
1091da6c28aaSamw 		zphys->zp_acl.z_acl_count = aclp->z_acl_bytes;
1092da6c28aaSamw 	} else {
1093da6c28aaSamw 		zphys->zp_acl.z_acl_size = aclp->z_acl_bytes;
1094da6c28aaSamw 		zphys->zp_acl.z_acl_count = aclp->z_acl_count;
1095de122929Smarks 	}
1096fa9e4066Sahrens 
1097da6c28aaSamw 	zphys->zp_acl.z_acl_version = aclp->z_version;
1098da6c28aaSamw 
1099da6c28aaSamw 	/*
1100da6c28aaSamw 	 * Replace ACL wide bits, but first clear them.
1101da6c28aaSamw 	 */
1102da6c28aaSamw 	zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS;
1103da6c28aaSamw 
1104da6c28aaSamw 	zp->z_phys->zp_flags |= aclp->z_hints;
1105fa9e4066Sahrens 
1106da6c28aaSamw 	if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
1107da6c28aaSamw 		zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
1108da6c28aaSamw 
1109da6c28aaSamw 	zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
1110fa9e4066Sahrens 	return (0);
1111fa9e4066Sahrens }
1112fa9e4066Sahrens 
1113fa9e4066Sahrens /*
1114fa9e4066Sahrens  * Update access mask for prepended ACE
1115fa9e4066Sahrens  *
1116fa9e4066Sahrens  * This applies the "groupmask" value for aclmode property.
1117fa9e4066Sahrens  */
1118fa9e4066Sahrens static void
1119da6c28aaSamw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void  *acep, void  *origacep,
1120da6c28aaSamw     mode_t mode, uint64_t owner)
1121fa9e4066Sahrens {
1122fa9e4066Sahrens 	int	rmask, wmask, xmask;
1123fa9e4066Sahrens 	int	user_ace;
1124da6c28aaSamw 	uint16_t aceflags;
1125da6c28aaSamw 	uint32_t origmask, acepmask;
1126da6c28aaSamw 	uint64_t fuid;
1127da6c28aaSamw 
1128da6c28aaSamw 	aceflags = aclp->z_ops.ace_flags_get(acep);
1129da6c28aaSamw 	fuid = aclp->z_ops.ace_who_get(acep);
1130da6c28aaSamw 	origmask = aclp->z_ops.ace_mask_get(origacep);
1131da6c28aaSamw 	acepmask = aclp->z_ops.ace_mask_get(acep);
1132fa9e4066Sahrens 
1133da6c28aaSamw 	user_ace = (!(aceflags &
1134fa9e4066Sahrens 	    (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
1135fa9e4066Sahrens 
1136da6c28aaSamw 	if (user_ace && (fuid == owner)) {
1137fa9e4066Sahrens 		rmask = S_IRUSR;
1138fa9e4066Sahrens 		wmask = S_IWUSR;
1139fa9e4066Sahrens 		xmask = S_IXUSR;
1140fa9e4066Sahrens 	} else {
1141fa9e4066Sahrens 		rmask = S_IRGRP;
1142fa9e4066Sahrens 		wmask = S_IWGRP;
1143fa9e4066Sahrens 		xmask = S_IXGRP;
1144fa9e4066Sahrens 	}
1145fa9e4066Sahrens 
1146da6c28aaSamw 	if (origmask & ACE_READ_DATA) {
1147da6c28aaSamw 		if (mode & rmask) {
1148da6c28aaSamw 			acepmask &= ~ACE_READ_DATA;
1149da6c28aaSamw 		} else {
1150da6c28aaSamw 			acepmask |= ACE_READ_DATA;
1151da6c28aaSamw 		}
1152fa9e4066Sahrens 	}
1153fa9e4066Sahrens 
1154da6c28aaSamw 	if (origmask & ACE_WRITE_DATA) {
1155da6c28aaSamw 		if (mode & wmask) {
1156da6c28aaSamw 			acepmask &= ~ACE_WRITE_DATA;
1157da6c28aaSamw 		} else {
1158da6c28aaSamw 			acepmask |= ACE_WRITE_DATA;
1159da6c28aaSamw 		}
1160fa9e4066Sahrens 	}
1161fa9e4066Sahrens 
1162da6c28aaSamw 	if (origmask & ACE_APPEND_DATA) {
1163da6c28aaSamw 		if (mode & wmask) {
1164da6c28aaSamw 			acepmask &= ~ACE_APPEND_DATA;
1165da6c28aaSamw 		} else {
1166da6c28aaSamw 			acepmask |= ACE_APPEND_DATA;
1167da6c28aaSamw 		}
1168fa9e4066Sahrens 	}
1169fa9e4066Sahrens 
1170da6c28aaSamw 	if (origmask & ACE_EXECUTE) {
1171da6c28aaSamw 		if (mode & xmask) {
1172da6c28aaSamw 			acepmask &= ~ACE_EXECUTE;
1173da6c28aaSamw 		} else {
1174da6c28aaSamw 			acepmask |= ACE_EXECUTE;
1175da6c28aaSamw 		}
1176fa9e4066Sahrens 	}
1177da6c28aaSamw 	aclp->z_ops.ace_mask_set(acep, acepmask);
1178fa9e4066Sahrens }
1179fa9e4066Sahrens 
1180fa9e4066Sahrens /*
1181fa9e4066Sahrens  * Apply mode to canonical six ACEs.
1182fa9e4066Sahrens  */
1183fa9e4066Sahrens static void
1184fa9e4066Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
1185fa9e4066Sahrens {
1186da6c28aaSamw 	zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
1187da6c28aaSamw 	void	*acep;
1188da6c28aaSamw 	int	maskoff = aclp->z_ops.ace_mask_off();
1189da6c28aaSamw 	size_t abstract_size = aclp->z_ops.ace_abstract_size();
1190fa9e4066Sahrens 
1191da6c28aaSamw 	ASSERT(aclnode != NULL);
1192da6c28aaSamw 
1193da6c28aaSamw 	acep = (void *)((caddr_t)aclnode->z_acldata +
1194da6c28aaSamw 	    aclnode->z_size - (abstract_size * 6));
1195fa9e4066Sahrens 
1196fa9e4066Sahrens 	/*
1197fa9e4066Sahrens 	 * Fixup final ACEs to match the mode
1198fa9e4066Sahrens 	 */
1199fa9e4066Sahrens 
1200da6c28aaSamw 	adjust_ace_pair_common(acep, maskoff, abstract_size,
1201da6c28aaSamw 	    (mode & 0700) >> 6);	/* owner@ */
1202da6c28aaSamw 
1203da6c28aaSamw 	acep = (caddr_t)acep + (abstract_size * 2);
1204da6c28aaSamw 
1205da6c28aaSamw 	adjust_ace_pair_common(acep, maskoff, abstract_size,
1206da6c28aaSamw 	    (mode & 0070) >> 3);	/* group@ */
1207da6c28aaSamw 
1208da6c28aaSamw 	acep = (caddr_t)acep + (abstract_size * 2);
1209da6c28aaSamw 	adjust_ace_pair_common(acep, maskoff,
1210da6c28aaSamw 	    abstract_size, mode);	/* everyone@ */
1211fa9e4066Sahrens }
1212fa9e4066Sahrens 
1213fa9e4066Sahrens 
1214fa9e4066Sahrens static int
1215da6c28aaSamw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny,
1216da6c28aaSamw     int entry_type, int accessmask)
1217fa9e4066Sahrens {
1218da6c28aaSamw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
1219da6c28aaSamw 	uint16_t type = aclp->z_ops.ace_type_get(acep);
1220da6c28aaSamw 	uint16_t flags = aclp->z_ops.ace_flags_get(acep);
1221da6c28aaSamw 
1222da6c28aaSamw 	return (mask == accessmask && type == allow_deny &&
1223da6c28aaSamw 	    ((flags & ACE_TYPE_FLAGS) == entry_type));
1224fa9e4066Sahrens }
1225fa9e4066Sahrens 
1226fa9e4066Sahrens /*
1227fa9e4066Sahrens  * Can prepended ACE be reused?
1228fa9e4066Sahrens  */
1229fa9e4066Sahrens static int
1230da6c28aaSamw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep)
1231fa9e4066Sahrens {
1232fa9e4066Sahrens 	int okay_masks;
1233da6c28aaSamw 	uint16_t prevtype;
1234da6c28aaSamw 	uint16_t prevflags;
1235da6c28aaSamw 	uint16_t flags;
1236da6c28aaSamw 	uint32_t mask, prevmask;
1237fa9e4066Sahrens 
1238da6c28aaSamw 	if (prevacep == NULL)
1239fa9e4066Sahrens 		return (B_FALSE);
1240fa9e4066Sahrens 
1241da6c28aaSamw 	prevtype = aclp->z_ops.ace_type_get(prevacep);
1242da6c28aaSamw 	prevflags = aclp->z_ops.ace_flags_get(prevacep);
1243da6c28aaSamw 	flags = aclp->z_ops.ace_flags_get(acep);
1244da6c28aaSamw 	mask = aclp->z_ops.ace_mask_get(acep);
1245da6c28aaSamw 	prevmask = aclp->z_ops.ace_mask_get(prevacep);
1246da6c28aaSamw 
1247da6c28aaSamw 	if (prevtype != DENY)
1248fa9e4066Sahrens 		return (B_FALSE);
1249fa9e4066Sahrens 
1250da6c28aaSamw 	if (prevflags != (flags & ACE_IDENTIFIER_GROUP))
1251fa9e4066Sahrens 		return (B_FALSE);
1252fa9e4066Sahrens 
1253da6c28aaSamw 	okay_masks = (mask & OKAY_MASK_BITS);
1254fa9e4066Sahrens 
1255da6c28aaSamw 	if (prevmask & ~okay_masks)
1256fa9e4066Sahrens 		return (B_FALSE);
1257fa9e4066Sahrens 
1258fa9e4066Sahrens 	return (B_TRUE);
1259fa9e4066Sahrens }
1260fa9e4066Sahrens 
1261da6c28aaSamw 
1262fa9e4066Sahrens /*
1263da6c28aaSamw  * Insert new ACL node into chain of zfs_acl_node_t's
1264da6c28aaSamw  *
1265da6c28aaSamw  * This will result in two possible results.
1266da6c28aaSamw  * 1. If the ACL is currently just a single zfs_acl_node and
1267da6c28aaSamw  *    we are prepending the entry then current acl node will have
1268da6c28aaSamw  *    a new node inserted above it.
1269da6c28aaSamw  *
1270da6c28aaSamw  * 2. If we are inserting in the middle of current acl node then
1271da6c28aaSamw  *    the current node will be split in two and new node will be inserted
1272da6c28aaSamw  *    in between the two split nodes.
1273fa9e4066Sahrens  */
1274da6c28aaSamw static zfs_acl_node_t *
1275da6c28aaSamw zfs_acl_ace_insert(zfs_acl_t *aclp, void  *acep)
1276da6c28aaSamw {
1277da6c28aaSamw 	zfs_acl_node_t 	*newnode;
1278da6c28aaSamw 	zfs_acl_node_t 	*trailernode = NULL;
1279da6c28aaSamw 	zfs_acl_node_t 	*currnode = zfs_acl_curr_node(aclp);
1280da6c28aaSamw 	int		curr_idx = aclp->z_curr_node->z_ace_idx;
1281da6c28aaSamw 	int		trailer_count;
1282da6c28aaSamw 	size_t		oldsize;
1283da6c28aaSamw 
1284da6c28aaSamw 	newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep));
1285da6c28aaSamw 	newnode->z_ace_count = 1;
1286da6c28aaSamw 
1287da6c28aaSamw 	oldsize = currnode->z_size;
1288da6c28aaSamw 
1289da6c28aaSamw 	if (curr_idx != 1) {
1290da6c28aaSamw 		trailernode = zfs_acl_node_alloc(0);
1291da6c28aaSamw 		trailernode->z_acldata = acep;
1292da6c28aaSamw 
1293da6c28aaSamw 		trailer_count = currnode->z_ace_count - curr_idx + 1;
1294da6c28aaSamw 		currnode->z_ace_count = curr_idx - 1;
1295da6c28aaSamw 		currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata;
1296da6c28aaSamw 		trailernode->z_size = oldsize - currnode->z_size;
1297da6c28aaSamw 		trailernode->z_ace_count = trailer_count;
1298fa9e4066Sahrens 	}
1299fa9e4066Sahrens 
1300da6c28aaSamw 	aclp->z_acl_count += 1;
1301da6c28aaSamw 	aclp->z_acl_bytes += aclp->z_ops.ace_size(acep);
1302da6c28aaSamw 
1303da6c28aaSamw 	if (curr_idx == 1)
1304da6c28aaSamw 		list_insert_before(&aclp->z_acl, currnode, newnode);
1305da6c28aaSamw 	else
1306da6c28aaSamw 		list_insert_after(&aclp->z_acl, currnode, newnode);
1307da6c28aaSamw 	if (trailernode) {
1308da6c28aaSamw 		list_insert_after(&aclp->z_acl, newnode, trailernode);
1309da6c28aaSamw 		aclp->z_curr_node = trailernode;
1310da6c28aaSamw 		trailernode->z_ace_idx = 1;
1311fa9e4066Sahrens 	}
1312fa9e4066Sahrens 
1313da6c28aaSamw 	return (newnode);
1314fa9e4066Sahrens }
1315fa9e4066Sahrens 
1316fa9e4066Sahrens /*
1317fa9e4066Sahrens  * Prepend deny ACE
1318fa9e4066Sahrens  */
1319da6c28aaSamw static void *
1320da6c28aaSamw zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, void *acep,
1321fa9e4066Sahrens     mode_t mode)
1322fa9e4066Sahrens {
1323da6c28aaSamw 	zfs_acl_node_t *aclnode;
1324da6c28aaSamw 	void  *newacep;
1325da6c28aaSamw 	uint64_t fuid;
1326da6c28aaSamw 	uint16_t flags;
1327da6c28aaSamw 
1328da6c28aaSamw 	aclnode = zfs_acl_ace_insert(aclp, acep);
1329da6c28aaSamw 	newacep = aclnode->z_acldata;
1330da6c28aaSamw 	fuid = aclp->z_ops.ace_who_get(acep);
1331da6c28aaSamw 	flags = aclp->z_ops.ace_flags_get(acep);
1332da6c28aaSamw 	zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS));
1333da6c28aaSamw 	zfs_acl_prepend_fixup(aclp, newacep, acep, mode, zp->z_phys->zp_uid);
1334da6c28aaSamw 
1335da6c28aaSamw 	return (newacep);
1336fa9e4066Sahrens }
1337fa9e4066Sahrens 
1338fa9e4066Sahrens /*
1339fa9e4066Sahrens  * Split an inherited ACE into inherit_only ACE
1340fa9e4066Sahrens  * and original ACE with inheritance flags stripped off.
1341fa9e4066Sahrens  */
1342fa9e4066Sahrens static void
1343da6c28aaSamw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep)
1344fa9e4066Sahrens {
1345da6c28aaSamw 	zfs_acl_node_t *aclnode;
1346569e6c63Smarks 	zfs_acl_node_t *currnode;
1347da6c28aaSamw 	void  *newacep;
1348da6c28aaSamw 	uint16_t type, flags;
1349da6c28aaSamw 	uint32_t mask;
1350da6c28aaSamw 	uint64_t fuid;
1351da6c28aaSamw 
1352da6c28aaSamw 	type = aclp->z_ops.ace_type_get(acep);
1353da6c28aaSamw 	flags = aclp->z_ops.ace_flags_get(acep);
1354da6c28aaSamw 	mask = aclp->z_ops.ace_mask_get(acep);
1355da6c28aaSamw 	fuid = aclp->z_ops.ace_who_get(acep);
1356da6c28aaSamw 
1357da6c28aaSamw 	aclnode = zfs_acl_ace_insert(aclp, acep);
1358da6c28aaSamw 	newacep = aclnode->z_acldata;
1359da6c28aaSamw 
1360da6c28aaSamw 	aclp->z_ops.ace_type_set(newacep, type);
1361da6c28aaSamw 	aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE);
1362da6c28aaSamw 	aclp->z_ops.ace_mask_set(newacep, mask);
1363da6c28aaSamw 	aclp->z_ops.ace_type_set(newacep, type);
1364da6c28aaSamw 	aclp->z_ops.ace_who_set(newacep, fuid);
1365da6c28aaSamw 	aclp->z_next_ace = acep;
1366da6c28aaSamw 	flags &= ~ALL_INHERIT;
1367da6c28aaSamw 	aclp->z_ops.ace_flags_set(acep, flags);
1368569e6c63Smarks 	currnode = zfs_acl_curr_node(aclp);
1369569e6c63Smarks 	ASSERT(currnode->z_ace_idx >= 1);
1370da6c28aaSamw 	currnode->z_ace_idx -= 1;
1371fa9e4066Sahrens }
1372fa9e4066Sahrens 
1373fa9e4066Sahrens /*
1374fa9e4066Sahrens  * Are ACES started at index i, the canonical six ACES?
1375fa9e4066Sahrens  */
1376fa9e4066Sahrens static int
1377da6c28aaSamw zfs_have_canonical_six(zfs_acl_t *aclp)
1378fa9e4066Sahrens {
1379da6c28aaSamw 	void *acep;
1380da6c28aaSamw 	zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
1381da6c28aaSamw 	int		i = 0;
1382da6c28aaSamw 	size_t abstract_size = aclp->z_ops.ace_abstract_size();
1383da6c28aaSamw 
1384da6c28aaSamw 	ASSERT(aclnode != NULL);
1385da6c28aaSamw 
1386da6c28aaSamw 	if (aclnode->z_ace_count < 6)
1387da6c28aaSamw 		return (0);
1388fa9e4066Sahrens 
1389da6c28aaSamw 	acep = (void *)((caddr_t)aclnode->z_acldata +
1390da6c28aaSamw 	    aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6));
1391da6c28aaSamw 
1392da6c28aaSamw 	if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1393fa9e4066Sahrens 	    DENY, ACE_OWNER, 0) &&
1394da6c28aaSamw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1395da6c28aaSamw 	    ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) &&
1396da6c28aaSamw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY,
1397da6c28aaSamw 	    OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep +
1398da6c28aaSamw 	    (abstract_size * i++),
1399da6c28aaSamw 	    ALLOW, OWNING_GROUP, 0) &&
1400da6c28aaSamw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1401fa9e4066Sahrens 	    DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
1402da6c28aaSamw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1403da6c28aaSamw 	    ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) {
1404fa9e4066Sahrens 		return (1);
1405fa9e4066Sahrens 	} else {
1406fa9e4066Sahrens 		return (0);
1407fa9e4066Sahrens 	}
1408fa9e4066Sahrens }
1409fa9e4066Sahrens 
1410da6c28aaSamw 
1411fa9e4066Sahrens /*
1412fa9e4066Sahrens  * Apply step 1g, to group entries
1413fa9e4066Sahrens  *
1414fa9e4066Sahrens  * Need to deal with corner case where group may have
1415fa9e4066Sahrens  * greater permissions than owner.  If so then limit
1416fa9e4066Sahrens  * group permissions, based on what extra permissions
1417fa9e4066Sahrens  * group has.
1418fa9e4066Sahrens  */
1419fa9e4066Sahrens static void
1420da6c28aaSamw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep,
1421da6c28aaSamw     mode_t mode)
1422fa9e4066Sahrens {
1423da6c28aaSamw 	uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep);
1424da6c28aaSamw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
1425da6c28aaSamw 	uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep);
1426fa9e4066Sahrens 	mode_t extramode = (mode >> 3) & 07;
1427fa9e4066Sahrens 	mode_t ownermode = (mode >> 6);
1428fa9e4066Sahrens 
1429da6c28aaSamw 	if (prevflags & ACE_IDENTIFIER_GROUP) {
1430fa9e4066Sahrens 
1431fa9e4066Sahrens 		extramode &= ~ownermode;
1432fa9e4066Sahrens 
1433fa9e4066Sahrens 		if (extramode) {
1434da6c28aaSamw 			if (extramode & S_IROTH) {
1435da6c28aaSamw 				prevmask &= ~ACE_READ_DATA;
1436da6c28aaSamw 				mask &= ~ACE_READ_DATA;
1437fa9e4066Sahrens 			}
1438da6c28aaSamw 			if (extramode & S_IWOTH) {
1439da6c28aaSamw 				prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
1440da6c28aaSamw 				mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
1441fa9e4066Sahrens 			}
1442da6c28aaSamw 			if (extramode & S_IXOTH) {
1443da6c28aaSamw 				prevmask  &= ~ACE_EXECUTE;
1444da6c28aaSamw 				mask &= ~ACE_EXECUTE;
1445fa9e4066Sahrens 			}
1446fa9e4066Sahrens 		}
1447fa9e4066Sahrens 	}
1448da6c28aaSamw 	aclp->z_ops.ace_mask_set(acep, mask);
1449da6c28aaSamw 	aclp->z_ops.ace_mask_set(prevacep, prevmask);
1450fa9e4066Sahrens }
1451fa9e4066Sahrens 
1452fa9e4066Sahrens /*
1453fa9e4066Sahrens  * Apply the chmod algorithm as described
1454fa9e4066Sahrens  * in PSARC/2002/240
1455fa9e4066Sahrens  */
14564c841f60Smarks static void
14574c841f60Smarks zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp)
1458fa9e4066Sahrens {
1459fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1460da6c28aaSamw 	void		*acep = NULL, *prevacep = NULL;
1461da6c28aaSamw 	uint64_t	who;
1462fa9e4066Sahrens 	int 		i;
1463fa9e4066Sahrens 	int 		entry_type;
1464fa9e4066Sahrens 	int 		reuse_deny;
1465fa9e4066Sahrens 	int 		need_canonical_six = 1;
1466da6c28aaSamw 	uint16_t	iflags, type;
1467da6c28aaSamw 	uint32_t	access_mask;
1468fa9e4066Sahrens 
1469fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
1470fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
1471fa9e4066Sahrens 
1472da6c28aaSamw 	aclp->z_hints = (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
14732459a9eaSmarks 
14742459a9eaSmarks 	/*
14752459a9eaSmarks 	 * If discard then just discard all ACL nodes which
14762459a9eaSmarks 	 * represent the ACEs.
14772459a9eaSmarks 	 *
14782459a9eaSmarks 	 * New owner@/group@/everone@ ACEs will be added
14792459a9eaSmarks 	 * later.
14802459a9eaSmarks 	 */
14812459a9eaSmarks 	if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD)
14822459a9eaSmarks 		zfs_acl_release_nodes(aclp);
14832459a9eaSmarks 
1484da6c28aaSamw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
1485da6c28aaSamw 	    &iflags, &type)) {
1486fa9e4066Sahrens 
1487da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
1488da6c28aaSamw 		iflags = (iflags & ALL_INHERIT);
1489da6c28aaSamw 
1490da6c28aaSamw 		if ((type != ALLOW && type != DENY) ||
1491de122929Smarks 		    (iflags & ACE_INHERIT_ONLY_ACE)) {
1492de122929Smarks 			if (iflags)
1493da6c28aaSamw 				aclp->z_hints |= ZFS_INHERIT_ACE;
1494da6c28aaSamw 			switch (type) {
1495da6c28aaSamw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1496da6c28aaSamw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1497da6c28aaSamw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1498da6c28aaSamw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1499da6c28aaSamw 				aclp->z_hints |= ZFS_ACL_OBJ_ACE;
1500da6c28aaSamw 				break;
1501da6c28aaSamw 			}
1502da6c28aaSamw 			goto nextace;
1503fa9e4066Sahrens 		}
1504fa9e4066Sahrens 
1505fa9e4066Sahrens 		/*
1506fa9e4066Sahrens 		 * Need to split ace into two?
1507fa9e4066Sahrens 		 */
1508de122929Smarks 		if ((iflags & (ACE_FILE_INHERIT_ACE|
1509fa9e4066Sahrens 		    ACE_DIRECTORY_INHERIT_ACE)) &&
1510de122929Smarks 		    (!(iflags & ACE_INHERIT_ONLY_ACE))) {
1511da6c28aaSamw 			zfs_acl_split_ace(aclp, acep);
1512da6c28aaSamw 			aclp->z_hints |= ZFS_INHERIT_ACE;
1513da6c28aaSamw 			goto nextace;
1514fa9e4066Sahrens 		}
1515fa9e4066Sahrens 
1516fa9e4066Sahrens 		if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
1517fa9e4066Sahrens 		    (entry_type == OWNING_GROUP)) {
1518da6c28aaSamw 			access_mask &= ~OGE_CLEAR;
1519da6c28aaSamw 			aclp->z_ops.ace_mask_set(acep, access_mask);
1520da6c28aaSamw 			goto nextace;
1521fa9e4066Sahrens 		} else {
1522da6c28aaSamw 			reuse_deny = B_TRUE;
1523da6c28aaSamw 			if (type == ALLOW) {
1524fa9e4066Sahrens 
1525fa9e4066Sahrens 				/*
1526fa9e4066Sahrens 				 * Check preceding ACE if any, to see
1527fa9e4066Sahrens 				 * if we need to prepend a DENY ACE.
1528fa9e4066Sahrens 				 * This is only applicable when the acl_mode
1529fa9e4066Sahrens 				 * property == groupmask.
1530fa9e4066Sahrens 				 */
1531e9dbad6fSeschrock 				if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) {
1532fa9e4066Sahrens 
1533da6c28aaSamw 					reuse_deny = zfs_reuse_deny(aclp, acep,
1534da6c28aaSamw 					    prevacep);
1535fa9e4066Sahrens 
1536e0d35c44Smarks 					if (!reuse_deny) {
1537da6c28aaSamw 						prevacep =
1538da6c28aaSamw 						    zfs_acl_prepend_deny(zp,
1539da6c28aaSamw 						    aclp, acep, mode);
1540fa9e4066Sahrens 					} else {
1541fa9e4066Sahrens 						zfs_acl_prepend_fixup(
1542da6c28aaSamw 						    aclp, prevacep,
1543da6c28aaSamw 						    acep, mode,
1544fa9e4066Sahrens 						    zp->z_phys->zp_uid);
1545fa9e4066Sahrens 					}
1546da6c28aaSamw 					zfs_fixup_group_entries(aclp, acep,
1547da6c28aaSamw 					    prevacep, mode);
1548da6c28aaSamw 
1549fa9e4066Sahrens 				}
1550fa9e4066Sahrens 			}
1551fa9e4066Sahrens 		}
1552da6c28aaSamw nextace:
1553da6c28aaSamw 		prevacep = acep;
1554fa9e4066Sahrens 	}
1555fa9e4066Sahrens 
1556fa9e4066Sahrens 	/*
1557fa9e4066Sahrens 	 * Check out last six aces, if we have six.
1558fa9e4066Sahrens 	 */
1559fa9e4066Sahrens 
1560fa9e4066Sahrens 	if (aclp->z_acl_count >= 6) {
1561da6c28aaSamw 		if (zfs_have_canonical_six(aclp)) {
1562fa9e4066Sahrens 			need_canonical_six = 0;
1563fa9e4066Sahrens 		}
1564fa9e4066Sahrens 	}
1565fa9e4066Sahrens 
1566fa9e4066Sahrens 	if (need_canonical_six) {
1567da6c28aaSamw 		size_t abstract_size = aclp->z_ops.ace_abstract_size();
1568da6c28aaSamw 		void *zacep;
1569da6c28aaSamw 		zfs_acl_node_t *aclnode =
1570da6c28aaSamw 		    zfs_acl_node_alloc(abstract_size * 6);
1571da6c28aaSamw 
1572da6c28aaSamw 		aclnode->z_size = abstract_size * 6;
1573da6c28aaSamw 		aclnode->z_ace_count = 6;
1574da6c28aaSamw 		aclp->z_acl_bytes += aclnode->z_size;
1575da6c28aaSamw 		list_insert_tail(&aclp->z_acl, aclnode);
1576da6c28aaSamw 
1577da6c28aaSamw 		zacep = aclnode->z_acldata;
1578da6c28aaSamw 
1579da6c28aaSamw 		i = 0;
1580da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
1581da6c28aaSamw 		    0, DENY, -1, ACE_OWNER);
1582da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
1583da6c28aaSamw 		    OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
1584da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
1585da6c28aaSamw 		    DENY, -1, OWNING_GROUP);
1586da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
1587da6c28aaSamw 		    ALLOW, -1, OWNING_GROUP);
1588da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
1589da6c28aaSamw 		    EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE);
1590da6c28aaSamw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
1591da6c28aaSamw 		    EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE);
1592fa9e4066Sahrens 		aclp->z_acl_count += 6;
1593fa9e4066Sahrens 	}
1594fa9e4066Sahrens 
1595fa9e4066Sahrens 	zfs_acl_fixup_canonical_six(aclp, mode);
1596fa9e4066Sahrens }
1597fa9e4066Sahrens 
1598fa9e4066Sahrens int
15994c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
1600fa9e4066Sahrens {
1601fa9e4066Sahrens 	int error;
1602fa9e4066Sahrens 
16034c841f60Smarks 	mutex_enter(&zp->z_lock);
1604fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
16054c841f60Smarks 	*aclp = NULL;
16064c841f60Smarks 	error = zfs_acl_node_read(zp, aclp, B_TRUE);
1607ea8dc4b6Seschrock 	if (error == 0)
16084c841f60Smarks 		zfs_acl_chmod(zp, mode, *aclp);
1609fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
16104c841f60Smarks 	mutex_exit(&zp->z_lock);
1611fa9e4066Sahrens 	return (error);
1612fa9e4066Sahrens }
1613fa9e4066Sahrens 
1614fa9e4066Sahrens /*
1615fa9e4066Sahrens  * strip off write_owner and write_acl
1616fa9e4066Sahrens  */
1617fa9e4066Sahrens static void
1618*b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
1619fa9e4066Sahrens {
1620da6c28aaSamw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
1621da6c28aaSamw 
1622*b3d141f8Smarks 	if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) &&
1623da6c28aaSamw 	    (aclp->z_ops.ace_type_get(acep) == ALLOW)) {
1624*b3d141f8Smarks 		mask &= ~RESTRICTED_CLEAR;
1625da6c28aaSamw 		aclp->z_ops.ace_mask_set(acep, mask);
1626da6c28aaSamw 	}
1627da6c28aaSamw }
1628da6c28aaSamw 
1629da6c28aaSamw /*
1630da6c28aaSamw  * Should ACE be inherited?
1631da6c28aaSamw  */
1632da6c28aaSamw static int
1633da6c28aaSamw zfs_ace_can_use(znode_t *zp, uint16_t acep_flags)
1634da6c28aaSamw {
1635da6c28aaSamw 	int vtype = ZTOV(zp)->v_type;
1636da6c28aaSamw 	int	iflags = (acep_flags & 0xf);
1637da6c28aaSamw 
1638da6c28aaSamw 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
1639da6c28aaSamw 		return (1);
1640da6c28aaSamw 	else if (iflags & ACE_FILE_INHERIT_ACE)
1641da6c28aaSamw 		return (!((vtype == VDIR) &&
1642da6c28aaSamw 		    (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
1643da6c28aaSamw 	return (0);
1644fa9e4066Sahrens }
1645fa9e4066Sahrens 
1646fa9e4066Sahrens /*
1647fa9e4066Sahrens  * inherit inheritable ACEs from parent
1648fa9e4066Sahrens  */
1649fa9e4066Sahrens static zfs_acl_t *
1650*b3d141f8Smarks zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp, boolean_t *need_chmod)
1651fa9e4066Sahrens {
1652fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1653da6c28aaSamw 	void		*pacep;
1654da6c28aaSamw 	void		*acep, *acep2;
1655da6c28aaSamw 	zfs_acl_node_t  *aclnode, *aclnode2;
1656fa9e4066Sahrens 	zfs_acl_t	*aclp = NULL;
1657da6c28aaSamw 	uint64_t	who;
1658da6c28aaSamw 	uint32_t	access_mask;
1659da6c28aaSamw 	uint16_t	iflags, newflags, type;
1660da6c28aaSamw 	size_t		ace_size;
1661da6c28aaSamw 	void		*data1, *data2;
1662da6c28aaSamw 	size_t		data1sz, data2sz;
1663*b3d141f8Smarks 	enum vtype	vntype = ZTOV(zp)->v_type;
1664da6c28aaSamw 
1665*b3d141f8Smarks 	*need_chmod = B_TRUE;
1666da6c28aaSamw 	pacep = NULL;
1667da6c28aaSamw 	aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
1668e9dbad6fSeschrock 	if (zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
1669da6c28aaSamw 		while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
1670da6c28aaSamw 		    &access_mask, &iflags, &type)) {
1671fa9e4066Sahrens 
1672e9dbad6fSeschrock 			if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
1673da6c28aaSamw 			    type == ALLOW)
1674fa9e4066Sahrens 				continue;
1675fa9e4066Sahrens 
1676da6c28aaSamw 			ace_size = aclp->z_ops.ace_size(pacep);
1677169cdae2Smarks 
1678*b3d141f8Smarks 			if (!zfs_ace_can_use(zp, iflags))
1679*b3d141f8Smarks 				continue;
1680*b3d141f8Smarks 
1681*b3d141f8Smarks 			/*
1682*b3d141f8Smarks 			 * If owner@, group@, or everyone@ inheritable
1683*b3d141f8Smarks 			 * then zfs_acl_chmod() isn't needed.
1684*b3d141f8Smarks 			 */
1685*b3d141f8Smarks 			if (zfsvfs->z_acl_inherit ==
1686*b3d141f8Smarks 			    ZFS_ACL_PASSTHROUGH &&
1687*b3d141f8Smarks 			    ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
1688*b3d141f8Smarks 			    ((iflags & OWNING_GROUP) ==
1689*b3d141f8Smarks 			    OWNING_GROUP)) && (vntype == VREG ||
1690*b3d141f8Smarks 			    (vntype == VDIR &&
1691*b3d141f8Smarks 			    (iflags & ACE_DIRECTORY_INHERIT_ACE))))
1692*b3d141f8Smarks 				*need_chmod = B_FALSE;
1693*b3d141f8Smarks 
1694*b3d141f8Smarks 			aclnode = zfs_acl_node_alloc(ace_size);
1695*b3d141f8Smarks 			list_insert_tail(&aclp->z_acl, aclnode);
1696*b3d141f8Smarks 			acep = aclnode->z_acldata;
1697*b3d141f8Smarks 			zfs_set_ace(aclp, acep, access_mask, type,
1698*b3d141f8Smarks 			    who, iflags|ACE_INHERITED_ACE);
1699*b3d141f8Smarks 
1700*b3d141f8Smarks 			/*
1701*b3d141f8Smarks 			 * Copy special opaque data if any
1702*b3d141f8Smarks 			 */
1703*b3d141f8Smarks 			if ((data1sz = paclp->z_ops.ace_data(pacep,
1704*b3d141f8Smarks 			    &data1)) != 0) {
1705*b3d141f8Smarks 				VERIFY((data2sz = aclp->z_ops.ace_data(acep,
1706*b3d141f8Smarks 				    &data2)) == data1sz);
1707*b3d141f8Smarks 				bcopy(data1, data2, data2sz);
1708*b3d141f8Smarks 			}
1709*b3d141f8Smarks 			aclp->z_acl_count++;
1710*b3d141f8Smarks 			aclnode->z_ace_count++;
1711*b3d141f8Smarks 			aclp->z_acl_bytes += aclnode->z_size;
1712*b3d141f8Smarks 			newflags = aclp->z_ops.ace_flags_get(acep);
1713*b3d141f8Smarks 
1714*b3d141f8Smarks 			if (vntype == VDIR)
1715*b3d141f8Smarks 				aclp->z_hints |= ZFS_INHERIT_ACE;
1716*b3d141f8Smarks 
1717*b3d141f8Smarks 			if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) ||
1718*b3d141f8Smarks 			    (vntype != VDIR)) {
1719*b3d141f8Smarks 				newflags &= ~ALL_INHERIT;
1720*b3d141f8Smarks 				aclp->z_ops.ace_flags_set(acep,
1721*b3d141f8Smarks 				    newflags|ACE_INHERITED_ACE);
1722*b3d141f8Smarks 				zfs_restricted_update(zfsvfs, aclp, acep);
1723*b3d141f8Smarks 				continue;
1724*b3d141f8Smarks 			}
1725fa9e4066Sahrens 
1726*b3d141f8Smarks 			ASSERT(vntype == VDIR);
1727*b3d141f8Smarks 
1728*b3d141f8Smarks 			newflags = aclp->z_ops.ace_flags_get(acep);
1729*b3d141f8Smarks 			if ((iflags & (ACE_FILE_INHERIT_ACE |
1730*b3d141f8Smarks 			    ACE_DIRECTORY_INHERIT_ACE)) !=
1731*b3d141f8Smarks 			    ACE_FILE_INHERIT_ACE) {
1732*b3d141f8Smarks 				aclnode2 = zfs_acl_node_alloc(ace_size);
1733*b3d141f8Smarks 				list_insert_tail(&aclp->z_acl, aclnode2);
1734*b3d141f8Smarks 				acep2 = aclnode2->z_acldata;
1735*b3d141f8Smarks 				zfs_set_ace(aclp, acep2,
1736*b3d141f8Smarks 				    access_mask, type, who,
1737*b3d141f8Smarks 				    iflags|ACE_INHERITED_ACE);
1738*b3d141f8Smarks 				newflags |= ACE_INHERIT_ONLY_ACE;
1739*b3d141f8Smarks 				aclp->z_ops.ace_flags_set(acep, newflags);
1740*b3d141f8Smarks 				newflags &= ~ALL_INHERIT;
1741*b3d141f8Smarks 				aclp->z_ops.ace_flags_set(acep2,
1742*b3d141f8Smarks 				    newflags|ACE_INHERITED_ACE);
1743fa9e4066Sahrens 
1744169cdae2Smarks 				/*
1745da6c28aaSamw 				 * Copy special opaque data if any
1746169cdae2Smarks 				 */
1747*b3d141f8Smarks 				if ((data1sz = aclp->z_ops.ace_data(acep,
1748da6c28aaSamw 				    &data1)) != 0) {
1749da6c28aaSamw 					VERIFY((data2sz =
1750*b3d141f8Smarks 					    aclp->z_ops.ace_data(acep2,
1751da6c28aaSamw 					    &data2)) == data1sz);
1752*b3d141f8Smarks 					bcopy(data1, data2, data1sz);
1753da6c28aaSamw 				}
1754da6c28aaSamw 				aclp->z_acl_count++;
1755*b3d141f8Smarks 				aclnode2->z_ace_count++;
1756da6c28aaSamw 				aclp->z_acl_bytes += aclnode->z_size;
1757*b3d141f8Smarks 				zfs_restricted_update(zfsvfs, aclp, acep2);
1758*b3d141f8Smarks 			} else {
1759*b3d141f8Smarks 				newflags |= ACE_INHERIT_ONLY_ACE;
1760*b3d141f8Smarks 				aclp->z_ops.ace_flags_set(acep,
1761*b3d141f8Smarks 				    newflags|ACE_INHERITED_ACE);
1762fa9e4066Sahrens 			}
1763fa9e4066Sahrens 		}
1764fa9e4066Sahrens 	}
1765fa9e4066Sahrens 	return (aclp);
1766fa9e4066Sahrens }
1767fa9e4066Sahrens 
1768fa9e4066Sahrens /*
1769fa9e4066Sahrens  * Create file system object initial permissions
1770fa9e4066Sahrens  * including inheritable ACEs.
1771fa9e4066Sahrens  */
1772fa9e4066Sahrens void
1773fa9e4066Sahrens zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
1774da6c28aaSamw     vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
1775da6c28aaSamw     zfs_acl_t *setaclp, zfs_fuid_info_t **fuidp)
1776fa9e4066Sahrens {
1777e0d35c44Smarks 	uint64_t	mode, fuid, fgid;
1778fa9e4066Sahrens 	int		error;
1779da6c28aaSamw 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1780da6c28aaSamw 	zfs_acl_t	*aclp = NULL;
1781da6c28aaSamw 	zfs_acl_t	*paclp;
1782da6c28aaSamw 	xvattr_t	*xvap = (xvattr_t *)vap;
1783e0d35c44Smarks 	gid_t		gid;
1784*b3d141f8Smarks 	boolean_t	need_chmod = B_TRUE;
1785da6c28aaSamw 
1786da6c28aaSamw 	if (setaclp)
1787da6c28aaSamw 		aclp = setaclp;
1788fa9e4066Sahrens 
1789fa9e4066Sahrens 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
1790fa9e4066Sahrens 
1791fa9e4066Sahrens 	/*
1792fa9e4066Sahrens 	 * Determine uid and gid.
1793fa9e4066Sahrens 	 */
1794fa9e4066Sahrens 	if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
1795fa9e4066Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
1796e0d35c44Smarks 		fuid = zfs_fuid_create(zfsvfs, vap->va_uid, cr,
1797da6c28aaSamw 		    ZFS_OWNER, tx, fuidp);
1798e0d35c44Smarks 		fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
1799da6c28aaSamw 		    ZFS_GROUP, tx, fuidp);
1800e0d35c44Smarks 		gid = vap->va_gid;
1801fa9e4066Sahrens 	} else {
1802e0d35c44Smarks 		fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, tx, cr, fuidp);
1803e0d35c44Smarks 		fgid = 0;
1804e0d35c44Smarks 		if (vap->va_mask & AT_GID)  {
1805e0d35c44Smarks 			fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
1806e0d35c44Smarks 			    ZFS_GROUP, tx, fuidp);
1807e0d35c44Smarks 			gid = vap->va_gid;
1808e0d35c44Smarks 			if (fgid != parent->z_phys->zp_gid &&
1809e0d35c44Smarks 			    !groupmember(vap->va_gid, cr) &&
1810e0d35c44Smarks 			    secpolicy_vnode_create_gid(cr) != 0)
1811e0d35c44Smarks 				fgid = 0;
1812e0d35c44Smarks 		}
1813e0d35c44Smarks 		if (fgid == 0) {
1814e0d35c44Smarks 			if (parent->z_phys->zp_mode & S_ISGID) {
1815e0d35c44Smarks 				fgid = parent->z_phys->zp_gid;
1816e0d35c44Smarks 				gid = zfs_fuid_map_id(zfsvfs, fgid,
1817e0d35c44Smarks 				    cr, ZFS_GROUP);
1818e0d35c44Smarks 			} else {
1819e0d35c44Smarks 				fgid = zfs_fuid_create_cred(zfsvfs,
1820e0d35c44Smarks 				    ZFS_GROUP, tx, cr, fuidp);
1821e0d35c44Smarks 				gid = crgetgid(cr);
1822e0d35c44Smarks 			}
1823da6c28aaSamw 		}
1824fa9e4066Sahrens 	}
1825fa9e4066Sahrens 
1826fa9e4066Sahrens 	/*
1827fa9e4066Sahrens 	 * If we're creating a directory, and the parent directory has the
1828fa9e4066Sahrens 	 * set-GID bit set, set in on the new directory.
1829fa9e4066Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1830fa9e4066Sahrens 	 * file's new group, clear the file's set-GID bit.
1831fa9e4066Sahrens 	 */
1832fa9e4066Sahrens 
1833e0d35c44Smarks 	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR)) {
1834fa9e4066Sahrens 		mode |= S_ISGID;
1835e0d35c44Smarks 	} else {
1836fa9e4066Sahrens 		if ((mode & S_ISGID) &&
1837fa9e4066Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
1838fa9e4066Sahrens 			mode &= ~S_ISGID;
1839fa9e4066Sahrens 	}
1840fa9e4066Sahrens 
1841e0d35c44Smarks 	zp->z_phys->zp_uid = fuid;
1842e0d35c44Smarks 	zp->z_phys->zp_gid = fgid;
1843fa9e4066Sahrens 	zp->z_phys->zp_mode = mode;
1844fa9e4066Sahrens 
1845da6c28aaSamw 	if (aclp == NULL) {
1846da6c28aaSamw 		mutex_enter(&parent->z_lock);
1847e0d35c44Smarks 		if (parent->z_phys->zp_flags & ZFS_INHERIT_ACE) {
1848da6c28aaSamw 			mutex_enter(&parent->z_acl_lock);
1849da6c28aaSamw 			VERIFY(0 == zfs_acl_node_read(parent, &paclp, B_FALSE));
1850da6c28aaSamw 			mutex_exit(&parent->z_acl_lock);
1851*b3d141f8Smarks 			aclp = zfs_acl_inherit(zp, paclp, &need_chmod);
1852da6c28aaSamw 			zfs_acl_free(paclp);
1853da6c28aaSamw 		} else {
1854da6c28aaSamw 			aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
1855da6c28aaSamw 		}
1856da6c28aaSamw 		mutex_exit(&parent->z_lock);
1857da6c28aaSamw 		mutex_enter(&zp->z_lock);
1858da6c28aaSamw 		mutex_enter(&zp->z_acl_lock);
1859*b3d141f8Smarks 		if (need_chmod)
1860*b3d141f8Smarks 			zfs_acl_chmod(zp, mode, aclp);
1861fa9e4066Sahrens 	} else {
1862da6c28aaSamw 		mutex_enter(&zp->z_lock);
1863da6c28aaSamw 		mutex_enter(&zp->z_acl_lock);
1864fa9e4066Sahrens 	}
1865da6c28aaSamw 
1866da6c28aaSamw 	/* Force auto_inherit on all new directory objects */
1867da6c28aaSamw 	if (vap->va_type == VDIR)
1868da6c28aaSamw 		aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
1869da6c28aaSamw 
1870bda89588Sjp 	error = zfs_aclset_common(zp, aclp, cr, fuidp, tx);
1871da6c28aaSamw 
1872da6c28aaSamw 	/* Set optional attributes if any */
1873da6c28aaSamw 	if (vap->va_mask & AT_XVATTR)
1874da6c28aaSamw 		zfs_xvattr_set(zp, xvap);
1875da6c28aaSamw 
1876fa9e4066Sahrens 	mutex_exit(&zp->z_lock);
1877fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1878fa9e4066Sahrens 	ASSERT3U(error, ==, 0);
1879fa9e4066Sahrens 
1880e0d35c44Smarks 	if (aclp != setaclp)
1881da6c28aaSamw 		zfs_acl_free(aclp);
1882fa9e4066Sahrens }
1883fa9e4066Sahrens 
1884fa9e4066Sahrens /*
1885fa9e4066Sahrens  * Retrieve a files ACL
1886fa9e4066Sahrens  */
1887fa9e4066Sahrens int
1888da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1889fa9e4066Sahrens {
1890fa9e4066Sahrens 	zfs_acl_t	*aclp;
1891da6c28aaSamw 	ulong_t		mask;
1892fa9e4066Sahrens 	int		error;
1893da6c28aaSamw 	int 		count = 0;
1894da6c28aaSamw 	int		largeace = 0;
1895fa9e4066Sahrens 
1896da6c28aaSamw 	mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
1897da6c28aaSamw 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
1898da6c28aaSamw 
1899da6c28aaSamw 	if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
1900da6c28aaSamw 		return (error);
1901fa9e4066Sahrens 
1902fa9e4066Sahrens 	if (mask == 0)
1903fa9e4066Sahrens 		return (ENOSYS);
1904fa9e4066Sahrens 
1905fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
1906fa9e4066Sahrens 
1907da6c28aaSamw 	error = zfs_acl_node_read(zp, &aclp, B_FALSE);
1908ea8dc4b6Seschrock 	if (error != 0) {
1909ea8dc4b6Seschrock 		mutex_exit(&zp->z_acl_lock);
1910ea8dc4b6Seschrock 		return (error);
1911ea8dc4b6Seschrock 	}
1912ea8dc4b6Seschrock 
1913da6c28aaSamw 	/*
1914da6c28aaSamw 	 * Scan ACL to determine number of ACEs
1915da6c28aaSamw 	 */
1916da6c28aaSamw 	if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) &&
1917da6c28aaSamw 	    !(mask & VSA_ACE_ALLTYPES)) {
1918da6c28aaSamw 		void *zacep = NULL;
1919da6c28aaSamw 		uint64_t who;
1920da6c28aaSamw 		uint32_t access_mask;
1921da6c28aaSamw 		uint16_t type, iflags;
1922da6c28aaSamw 
1923da6c28aaSamw 		while (zacep = zfs_acl_next_ace(aclp, zacep,
1924da6c28aaSamw 		    &who, &access_mask, &iflags, &type)) {
1925da6c28aaSamw 			switch (type) {
1926da6c28aaSamw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1927da6c28aaSamw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1928da6c28aaSamw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1929da6c28aaSamw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1930da6c28aaSamw 				largeace++;
1931da6c28aaSamw 				continue;
1932da6c28aaSamw 			default:
1933da6c28aaSamw 				count++;
1934da6c28aaSamw 			}
1935da6c28aaSamw 		}
1936da6c28aaSamw 		vsecp->vsa_aclcnt = count;
1937da6c28aaSamw 	} else
1938da6c28aaSamw 		count = aclp->z_acl_count;
1939fa9e4066Sahrens 
1940fa9e4066Sahrens 	if (mask & VSA_ACECNT) {
1941da6c28aaSamw 		vsecp->vsa_aclcnt = count;
1942fa9e4066Sahrens 	}
1943fa9e4066Sahrens 
1944fa9e4066Sahrens 	if (mask & VSA_ACE) {
1945da6c28aaSamw 		size_t aclsz;
1946da6c28aaSamw 
1947da6c28aaSamw 		zfs_acl_node_t *aclnode = list_head(&aclp->z_acl);
1948da6c28aaSamw 
1949da6c28aaSamw 		aclsz = count * sizeof (ace_t) +
1950da6c28aaSamw 		    sizeof (ace_object_t) * largeace;
1951da6c28aaSamw 
1952da6c28aaSamw 		vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
1953da6c28aaSamw 		vsecp->vsa_aclentsz = aclsz;
1954da6c28aaSamw 
1955da6c28aaSamw 		if (aclp->z_version == ZFS_ACL_VERSION_FUID)
1956bda89588Sjp 			zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr,
1957da6c28aaSamw 			    vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
1958da6c28aaSamw 		else {
1959da6c28aaSamw 			bcopy(aclnode->z_acldata, vsecp->vsa_aclentp,
1960da6c28aaSamw 			    count * sizeof (ace_t));
1961da6c28aaSamw 		}
1962da6c28aaSamw 	}
1963da6c28aaSamw 	if (mask & VSA_ACE_ACLFLAGS) {
1964da6c28aaSamw 		vsecp->vsa_aclflags = 0;
1965da6c28aaSamw 		if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED)
1966da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_DEFAULTED;
1967da6c28aaSamw 		if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED)
1968da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_PROTECTED;
1969da6c28aaSamw 		if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT)
1970da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
1971fa9e4066Sahrens 	}
1972fa9e4066Sahrens 
1973fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1974fa9e4066Sahrens 
1975fa9e4066Sahrens 	zfs_acl_free(aclp);
1976fa9e4066Sahrens 
1977fa9e4066Sahrens 	return (0);
1978fa9e4066Sahrens }
1979fa9e4066Sahrens 
1980da6c28aaSamw int
1981da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
1982da6c28aaSamw     vsecattr_t *vsecp, zfs_acl_t **zaclp)
1983da6c28aaSamw {
1984da6c28aaSamw 	zfs_acl_t *aclp;
1985da6c28aaSamw 	zfs_acl_node_t *aclnode;
1986da6c28aaSamw 	int aclcnt = vsecp->vsa_aclcnt;
1987da6c28aaSamw 	int error;
1988da6c28aaSamw 
1989da6c28aaSamw 	if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
1990da6c28aaSamw 		return (EINVAL);
1991da6c28aaSamw 
1992da6c28aaSamw 	aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
1993da6c28aaSamw 
1994da6c28aaSamw 	aclp->z_hints = 0;
1995da6c28aaSamw 	aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
1996da6c28aaSamw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
1997da6c28aaSamw 		if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
1998da6c28aaSamw 		    (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
1999da6c28aaSamw 		    aclcnt, &aclnode->z_size)) != 0) {
2000da6c28aaSamw 			zfs_acl_free(aclp);
2001da6c28aaSamw 			zfs_acl_node_free(aclnode);
2002da6c28aaSamw 			return (error);
2003da6c28aaSamw 		}
2004da6c28aaSamw 	} else {
2005da6c28aaSamw 		if ((error = zfs_copy_ace_2_fuid(obj_type, aclp,
2006da6c28aaSamw 		    vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
2007da6c28aaSamw 		    &aclnode->z_size)) != 0) {
2008da6c28aaSamw 			zfs_acl_free(aclp);
2009da6c28aaSamw 			zfs_acl_node_free(aclnode);
2010da6c28aaSamw 			return (error);
2011da6c28aaSamw 		}
2012da6c28aaSamw 	}
2013da6c28aaSamw 	aclp->z_acl_bytes = aclnode->z_size;
2014da6c28aaSamw 	aclnode->z_ace_count = aclcnt;
2015da6c28aaSamw 	aclp->z_acl_count = aclcnt;
2016da6c28aaSamw 	list_insert_head(&aclp->z_acl, aclnode);
2017da6c28aaSamw 
2018da6c28aaSamw 	/*
2019da6c28aaSamw 	 * If flags are being set then add them to z_hints
2020da6c28aaSamw 	 */
2021da6c28aaSamw 	if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
2022da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_PROTECTED)
2023da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_PROTECTED;
2024da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_DEFAULTED)
2025da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_DEFAULTED;
2026da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
2027da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
2028da6c28aaSamw 	}
2029da6c28aaSamw 
2030da6c28aaSamw 	*zaclp = aclp;
2031da6c28aaSamw 
2032da6c28aaSamw 	return (0);
2033da6c28aaSamw }
2034da6c28aaSamw 
2035fa9e4066Sahrens /*
2036fa9e4066Sahrens  * Set a files ACL
2037fa9e4066Sahrens  */
2038fa9e4066Sahrens int
2039da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
2040fa9e4066Sahrens {
2041fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2042fa9e4066Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
2043fa9e4066Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
2044fa9e4066Sahrens 	dmu_tx_t	*tx;
2045fa9e4066Sahrens 	int		error;
2046fa9e4066Sahrens 	zfs_acl_t	*aclp;
2047da6c28aaSamw 	zfs_fuid_info_t	*fuidp = NULL;
2048fa9e4066Sahrens 
2049fa9e4066Sahrens 	if (mask == 0)
20507106075aSmarks 		return (ENOSYS);
2051fa9e4066Sahrens 
2052da6c28aaSamw 	if (zp->z_phys->zp_flags & ZFS_IMMUTABLE)
2053da6c28aaSamw 		return (EPERM);
2054da6c28aaSamw 
2055da6c28aaSamw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
2056da6c28aaSamw 		return (error);
2057da6c28aaSamw 
2058da6c28aaSamw 	error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, &aclp);
2059da6c28aaSamw 	if (error)
2060da6c28aaSamw 		return (error);
2061da6c28aaSamw 
2062da6c28aaSamw 	/*
2063da6c28aaSamw 	 * If ACL wide flags aren't being set then preserve any
2064da6c28aaSamw 	 * existing flags.
2065da6c28aaSamw 	 */
2066da6c28aaSamw 	if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
2067da6c28aaSamw 		aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
2068da6c28aaSamw 	}
2069fa9e4066Sahrens top:
2070da6c28aaSamw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) {
2071da6c28aaSamw 		zfs_acl_free(aclp);
2072da6c28aaSamw 		return (error);
2073fa9e4066Sahrens 	}
2074fa9e4066Sahrens 
2075fa9e4066Sahrens 	mutex_enter(&zp->z_lock);
2076fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
2077fa9e4066Sahrens 
2078fa9e4066Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
2079fa9e4066Sahrens 	dmu_tx_hold_bonus(tx, zp->z_id);
2080fa9e4066Sahrens 
2081fa9e4066Sahrens 	if (zp->z_phys->zp_acl.z_acl_extern_obj) {
2082da6c28aaSamw 		/* Are we upgrading ACL? */
2083da6c28aaSamw 		if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
2084da6c28aaSamw 		    zp->z_phys->zp_acl.z_acl_version ==
2085da6c28aaSamw 		    ZFS_ACL_VERSION_INITIAL) {
2086da6c28aaSamw 			dmu_tx_hold_free(tx,
2087da6c28aaSamw 			    zp->z_phys->zp_acl.z_acl_extern_obj,
2088da6c28aaSamw 			    0, DMU_OBJECT_END);
2089da6c28aaSamw 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
20904c841f60Smarks 			    0, aclp->z_acl_bytes);
2091da6c28aaSamw 		} else {
2092da6c28aaSamw 			dmu_tx_hold_write(tx,
2093da6c28aaSamw 			    zp->z_phys->zp_acl.z_acl_extern_obj,
2094da6c28aaSamw 			    0, aclp->z_acl_bytes);
2095da6c28aaSamw 		}
2096da6c28aaSamw 	} else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
2097da6c28aaSamw 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
2098da6c28aaSamw 	}
20994c841f60Smarks 	if (aclp->z_has_fuids) {
21004c841f60Smarks 		if (zfsvfs->z_fuid_obj == 0) {
21014c841f60Smarks 			dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
2102da6c28aaSamw 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
21034c841f60Smarks 			    FUID_SIZE_ESTIMATE(zfsvfs));
21044c841f60Smarks 			dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
21054c841f60Smarks 		} else {
21064c841f60Smarks 			dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
21074c841f60Smarks 			dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
21084c841f60Smarks 			    FUID_SIZE_ESTIMATE(zfsvfs));
21094c841f60Smarks 		}
2110fa9e4066Sahrens 	}
2111fa9e4066Sahrens 
2112fa9e4066Sahrens 	error = dmu_tx_assign(tx, zfsvfs->z_assign);
2113fa9e4066Sahrens 	if (error) {
2114fa9e4066Sahrens 		mutex_exit(&zp->z_acl_lock);
2115fa9e4066Sahrens 		mutex_exit(&zp->z_lock);
2116fa9e4066Sahrens 
2117fa9e4066Sahrens 		if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT) {
21188a2f1b91Sahrens 			dmu_tx_wait(tx);
21198a2f1b91Sahrens 			dmu_tx_abort(tx);
2120fa9e4066Sahrens 			goto top;
2121fa9e4066Sahrens 		}
21228a2f1b91Sahrens 		dmu_tx_abort(tx);
2123da6c28aaSamw 		zfs_acl_free(aclp);
2124fa9e4066Sahrens 		return (error);
2125fa9e4066Sahrens 	}
2126fa9e4066Sahrens 
2127bda89588Sjp 	error = zfs_aclset_common(zp, aclp, cr, &fuidp, tx);
2128fa9e4066Sahrens 	ASSERT(error == 0);
2129fa9e4066Sahrens 
2130da6c28aaSamw 	zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
2131da6c28aaSamw 
2132da6c28aaSamw 	if (fuidp)
2133da6c28aaSamw 		zfs_fuid_info_free(fuidp);
2134fa9e4066Sahrens 	zfs_acl_free(aclp);
2135fa9e4066Sahrens 	dmu_tx_commit(tx);
2136fa9e4066Sahrens done:
2137fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
2138fa9e4066Sahrens 	mutex_exit(&zp->z_lock);
2139fa9e4066Sahrens 
2140fa9e4066Sahrens 	return (error);
2141fa9e4066Sahrens }
2142fa9e4066Sahrens 
2143da6c28aaSamw /*
2144da6c28aaSamw  * working_mode returns the permissions that were not granted
2145da6c28aaSamw  */
2146fa9e4066Sahrens static int
2147da6c28aaSamw zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
2148da6c28aaSamw     boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
2149fa9e4066Sahrens {
2150fa9e4066Sahrens 	zfs_acl_t	*aclp;
2151fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2152ea8dc4b6Seschrock 	int		error;
2153fa9e4066Sahrens 	uid_t		uid = crgetuid(cr);
2154da6c28aaSamw 	uint64_t 	who;
2155da6c28aaSamw 	uint16_t	type, iflags;
2156da6c28aaSamw 	uint16_t	entry_type;
2157da6c28aaSamw 	uint32_t	access_mask;
215890fafcf0Smarks 	uint32_t	deny_mask = 0;
2159da6c28aaSamw 	zfs_ace_hdr_t	*acep = NULL;
2160da6c28aaSamw 	boolean_t	checkit;
2161da6c28aaSamw 	uid_t		fowner;
2162da6c28aaSamw 	uid_t		gowner;
2163da6c28aaSamw 
2164da6c28aaSamw 	/*
2165da6c28aaSamw 	 * Short circuit empty requests
2166da6c28aaSamw 	 */
2167da6c28aaSamw 	if (v4_mode == 0)
2168da6c28aaSamw 		return (0);
2169da6c28aaSamw 
2170da6c28aaSamw 	*check_privs = B_TRUE;
2171fa9e4066Sahrens 
2172b19a79ecSperrin 	if (zfsvfs->z_assign >= TXG_INITIAL) {		/* ZIL replay */
2173b19a79ecSperrin 		*working_mode = 0;
2174fa9e4066Sahrens 		return (0);
2175b19a79ecSperrin 	}
2176b19a79ecSperrin 
2177b19a79ecSperrin 	*working_mode = v4_mode;
2178fa9e4066Sahrens 
2179fa9e4066Sahrens 	if ((v4_mode & WRITE_MASK) &&
2180fa9e4066Sahrens 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
2181fa9e4066Sahrens 	    (!IS_DEVVP(ZTOV(zp)))) {
2182da6c28aaSamw 		*check_privs = B_FALSE;
2183fa9e4066Sahrens 		return (EROFS);
2184fa9e4066Sahrens 	}
2185fa9e4066Sahrens 
2186da6c28aaSamw 	/*
2187da6c28aaSamw 	 * Only check for READONLY on non-directories.
2188da6c28aaSamw 	 */
2189da6c28aaSamw 	if ((v4_mode & WRITE_MASK_DATA) &&
2190da6c28aaSamw 	    (((ZTOV(zp)->v_type != VDIR) &&
2191da6c28aaSamw 	    (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
2192da6c28aaSamw 	    (ZTOV(zp)->v_type == VDIR &&
2193da6c28aaSamw 	    (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) {
2194da6c28aaSamw 		*check_privs = B_FALSE;
2195da6c28aaSamw 		return (EPERM);
2196da6c28aaSamw 	}
2197da6c28aaSamw 
2198da6c28aaSamw 	if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
2199da6c28aaSamw 	    (zp->z_phys->zp_flags & ZFS_NOUNLINK)) {
2200da6c28aaSamw 		*check_privs = B_FALSE;
2201da6c28aaSamw 		return (EPERM);
2202da6c28aaSamw 	}
2203da6c28aaSamw 
2204da6c28aaSamw 	if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
2205da6c28aaSamw 	    (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) {
2206da6c28aaSamw 		*check_privs = B_FALSE;
2207da6c28aaSamw 		return (EACCES);
2208da6c28aaSamw 	}
2209da6c28aaSamw 
2210da6c28aaSamw 	/*
2211da6c28aaSamw 	 * The caller requested that the ACL check be skipped.  This
2212da6c28aaSamw 	 * would only happen if the caller checked VOP_ACCESS() with a
2213da6c28aaSamw 	 * 32 bit ACE mask and already had the appropriate permissions.
2214da6c28aaSamw 	 */
2215da6c28aaSamw 	if (skipaclchk) {
2216da6c28aaSamw 		*working_mode = 0;
2217da6c28aaSamw 		return (0);
2218da6c28aaSamw 	}
2219da6c28aaSamw 
2220bda89588Sjp 	zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
2221da6c28aaSamw 
2222fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
2223fa9e4066Sahrens 
2224da6c28aaSamw 	error = zfs_acl_node_read(zp, &aclp, B_FALSE);
2225ea8dc4b6Seschrock 	if (error != 0) {
2226ea8dc4b6Seschrock 		mutex_exit(&zp->z_acl_lock);
2227ea8dc4b6Seschrock 		return (error);
2228ea8dc4b6Seschrock 	}
2229ea8dc4b6Seschrock 
2230da6c28aaSamw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
2231da6c28aaSamw 	    &iflags, &type)) {
2232fa9e4066Sahrens 
2233da6c28aaSamw 		if (iflags & ACE_INHERIT_ONLY_ACE)
2234da6c28aaSamw 			continue;
2235fa9e4066Sahrens 
2236da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
2237169cdae2Smarks 
2238da6c28aaSamw 		checkit = B_FALSE;
2239fa9e4066Sahrens 
2240fa9e4066Sahrens 		switch (entry_type) {
2241fa9e4066Sahrens 		case ACE_OWNER:
2242da6c28aaSamw 			if (uid == fowner)
2243da6c28aaSamw 				checkit = B_TRUE;
2244fa9e4066Sahrens 			break;
2245da6c28aaSamw 		case OWNING_GROUP:
2246da6c28aaSamw 			who = gowner;
2247da6c28aaSamw 			/*FALLTHROUGH*/
2248fa9e4066Sahrens 		case ACE_IDENTIFIER_GROUP:
2249da6c28aaSamw 			checkit = zfs_groupmember(zfsvfs, who, cr);
2250fa9e4066Sahrens 			break;
2251fa9e4066Sahrens 		case ACE_EVERYONE:
2252da6c28aaSamw 			checkit = B_TRUE;
2253fa9e4066Sahrens 			break;
2254fa9e4066Sahrens 
2255fa9e4066Sahrens 		/* USER Entry */
2256fa9e4066Sahrens 		default:
2257fa9e4066Sahrens 			if (entry_type == 0) {
2258da6c28aaSamw 				uid_t newid;
2259da6c28aaSamw 
2260e0d35c44Smarks 				newid = zfs_fuid_map_id(zfsvfs, who, cr,
2261e0d35c44Smarks 				    ZFS_ACE_USER);
2262da6c28aaSamw 				if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
2263da6c28aaSamw 				    uid == newid)
2264da6c28aaSamw 					checkit = B_TRUE;
2265fa9e4066Sahrens 				break;
2266da6c28aaSamw 			} else {
2267da6c28aaSamw 				zfs_acl_free(aclp);
2268da6c28aaSamw 				mutex_exit(&zp->z_acl_lock);
2269da6c28aaSamw 				return (EIO);
2270da6c28aaSamw 			}
2271da6c28aaSamw 		}
2272da6c28aaSamw 
2273da6c28aaSamw 		if (checkit) {
227490fafcf0Smarks 			uint32_t mask_matched = (access_mask & *working_mode);
227590fafcf0Smarks 
227690fafcf0Smarks 			if (mask_matched) {
227790fafcf0Smarks 				if (type == DENY)
227890fafcf0Smarks 					deny_mask |= mask_matched;
227990fafcf0Smarks 
228090fafcf0Smarks 				*working_mode &= ~mask_matched;
2281fa9e4066Sahrens 			}
2282fa9e4066Sahrens 		}
2283fa9e4066Sahrens 
228490fafcf0Smarks 		/* Are we done? */
228590fafcf0Smarks 		if (*working_mode == 0)
2286fa9e4066Sahrens 			break;
2287fa9e4066Sahrens 	}
2288fa9e4066Sahrens 
2289fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
2290fa9e4066Sahrens 	zfs_acl_free(aclp);
229190fafcf0Smarks 
229290fafcf0Smarks 	/* Put the found 'denies' back on the working mode */
229323d5bb1fSmarks 	*working_mode |= deny_mask;
229423d5bb1fSmarks 
229523d5bb1fSmarks 	if (*working_mode)
229690fafcf0Smarks 		return (EACCES);
229790fafcf0Smarks 
229890fafcf0Smarks 	return (0);
2299fa9e4066Sahrens }
2300fa9e4066Sahrens 
2301da6c28aaSamw static int
2302da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
2303da6c28aaSamw     cred_t *cr)
2304da6c28aaSamw {
2305da6c28aaSamw 	if (*working_mode != ACE_WRITE_DATA)
2306da6c28aaSamw 		return (EACCES);
2307da6c28aaSamw 
2308da6c28aaSamw 	return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
2309da6c28aaSamw 	    check_privs, B_FALSE, cr));
2310da6c28aaSamw }
2311fa9e4066Sahrens 
2312fa9e4066Sahrens /*
2313fa9e4066Sahrens  * Determine whether Access should be granted/denied, invoking least
2314fa9e4066Sahrens  * priv subsytem when a deny is determined.
2315fa9e4066Sahrens  */
2316fa9e4066Sahrens int
2317da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
2318fa9e4066Sahrens {
2319da6c28aaSamw 	uint32_t	working_mode;
2320da6c28aaSamw 	int		error;
2321da6c28aaSamw 	int		is_attr;
2322da6c28aaSamw 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2323da6c28aaSamw 	boolean_t 	check_privs;
2324da6c28aaSamw 	znode_t		*xzp;
2325da6c28aaSamw 	znode_t 	*check_zp = zp;
2326fa9e4066Sahrens 
2327fa9e4066Sahrens 	is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
2328fa9e4066Sahrens 	    (ZTOV(zp)->v_type == VDIR));
2329fa9e4066Sahrens 
2330fa9e4066Sahrens 	/*
2331fa9e4066Sahrens 	 * If attribute then validate against base file
2332fa9e4066Sahrens 	 */
2333fa9e4066Sahrens 	if (is_attr) {
2334fa9e4066Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
2335fa9e4066Sahrens 		    zp->z_phys->zp_parent, &xzp)) != 0)	{
2336fa9e4066Sahrens 			return (error);
2337fa9e4066Sahrens 		}
2338da6c28aaSamw 
2339fa9e4066Sahrens 		check_zp = xzp;
2340da6c28aaSamw 
2341fa9e4066Sahrens 		/*
2342fa9e4066Sahrens 		 * fixup mode to map to xattr perms
2343fa9e4066Sahrens 		 */
2344fa9e4066Sahrens 
2345fa9e4066Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
2346fa9e4066Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
2347fa9e4066Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
2348fa9e4066Sahrens 		}
2349fa9e4066Sahrens 
2350fa9e4066Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
2351fa9e4066Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
2352fa9e4066Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
2353fa9e4066Sahrens 		}
2354fa9e4066Sahrens 	}
2355fa9e4066Sahrens 
2356da6c28aaSamw 	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
2357da6c28aaSamw 	    &check_privs, skipaclchk, cr)) == 0) {
2358da6c28aaSamw 		if (is_attr)
2359da6c28aaSamw 			VN_RELE(ZTOV(xzp));
2360da6c28aaSamw 		return (0);
2361da6c28aaSamw 	}
2362fa9e4066Sahrens 
2363e0d35c44Smarks 	if (error && !check_privs) {
2364fa9e4066Sahrens 		if (is_attr)
2365fa9e4066Sahrens 			VN_RELE(ZTOV(xzp));
2366fa9e4066Sahrens 		return (error);
2367fa9e4066Sahrens 	}
2368fa9e4066Sahrens 
2369da6c28aaSamw 	if (error && (flags & V_APPEND)) {
2370da6c28aaSamw 		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
2371da6c28aaSamw 	}
2372da6c28aaSamw 
2373da6c28aaSamw 	if (error && check_privs) {
2374da6c28aaSamw 		uid_t		owner;
2375da6c28aaSamw 		mode_t		checkmode = 0;
2376da6c28aaSamw 
2377e0d35c44Smarks 		owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr,
2378e0d35c44Smarks 		    ZFS_OWNER);
2379da6c28aaSamw 
2380da6c28aaSamw 		/*
2381da6c28aaSamw 		 * First check for implicit owner permission on
2382da6c28aaSamw 		 * read_acl/read_attributes
2383da6c28aaSamw 		 */
2384da6c28aaSamw 
2385da6c28aaSamw 		error = 0;
2386da6c28aaSamw 		ASSERT(working_mode != 0);
2387da6c28aaSamw 
2388da6c28aaSamw 		if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
2389da6c28aaSamw 		    owner == crgetuid(cr)))
2390da6c28aaSamw 			working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
2391da6c28aaSamw 
2392da6c28aaSamw 		if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
2393da6c28aaSamw 		    ACE_READ_ACL|ACE_READ_ATTRIBUTES))
2394da6c28aaSamw 			checkmode |= VREAD;
2395da6c28aaSamw 		if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
2396da6c28aaSamw 		    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES))
2397da6c28aaSamw 			checkmode |= VWRITE;
2398da6c28aaSamw 		if (working_mode & ACE_EXECUTE)
2399da6c28aaSamw 			checkmode |= VEXEC;
2400da6c28aaSamw 
2401da6c28aaSamw 		if (checkmode)
2402da6c28aaSamw 			error = secpolicy_vnode_access(cr, ZTOV(check_zp),
2403da6c28aaSamw 			    owner, checkmode);
2404da6c28aaSamw 
2405da6c28aaSamw 		if (error == 0 && (working_mode & ACE_WRITE_OWNER))
2406da6c28aaSamw 			error = secpolicy_vnode_create_gid(cr);
2407da6c28aaSamw 		if (error == 0 && (working_mode & ACE_WRITE_ACL))
2408da6c28aaSamw 			error = secpolicy_vnode_setdac(cr, owner);
2409da6c28aaSamw 
2410da6c28aaSamw 		if (error == 0 && (working_mode &
2411da6c28aaSamw 		    (ACE_DELETE|ACE_DELETE_CHILD)))
2412da6c28aaSamw 			error = secpolicy_vnode_remove(cr);
2413da6c28aaSamw 
2414da6c28aaSamw 		if (error == 0 && (working_mode & ACE_SYNCHRONIZE))
2415da6c28aaSamw 			error = secpolicy_vnode_owner(cr, owner);
2416da6c28aaSamw 
2417da6c28aaSamw 		if (error == 0) {
2418da6c28aaSamw 			/*
2419da6c28aaSamw 			 * See if any bits other than those already checked
2420da6c28aaSamw 			 * for are still present.  If so then return EACCES
2421da6c28aaSamw 			 */
2422da6c28aaSamw 			if (working_mode & ~(ZFS_CHECKED_MASKS)) {
2423da6c28aaSamw 				error = EACCES;
2424da6c28aaSamw 			}
2425da6c28aaSamw 		}
2426fa9e4066Sahrens 	}
2427fa9e4066Sahrens 
2428fa9e4066Sahrens 	if (is_attr)
2429fa9e4066Sahrens 		VN_RELE(ZTOV(xzp));
2430fa9e4066Sahrens 
2431fa9e4066Sahrens 	return (error);
2432fa9e4066Sahrens }
2433fa9e4066Sahrens 
2434fa9e4066Sahrens /*
2435da6c28aaSamw  * Translate traditional unix VREAD/VWRITE/VEXEC mode into
2436da6c28aaSamw  * native ACL format and call zfs_zaccess()
2437fa9e4066Sahrens  */
2438fa9e4066Sahrens int
2439da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
2440fa9e4066Sahrens {
2441da6c28aaSamw 	return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
2442fa9e4066Sahrens }
2443fa9e4066Sahrens 
2444fa9e4066Sahrens /*
2445da6c28aaSamw  * Access function for secpolicy_vnode_setattr
2446fa9e4066Sahrens  */
2447fa9e4066Sahrens int
2448da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
2449fa9e4066Sahrens {
2450fa9e4066Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
2451fa9e4066Sahrens 
2452da6c28aaSamw 	return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
2453fa9e4066Sahrens }
2454fa9e4066Sahrens 
245547db7e74Smarks static int
245623d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp,
245723d5bb1fSmarks     mode_t missing_perms, cred_t *cr)
245847db7e74Smarks {
245947db7e74Smarks 	int error;
2460da6c28aaSamw 	uid_t downer;
2461da6c28aaSamw 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
2462da6c28aaSamw 
2463e0d35c44Smarks 	downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER);
246447db7e74Smarks 
246523d5bb1fSmarks 	error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms);
246647db7e74Smarks 
246747db7e74Smarks 	if (error == 0)
246847db7e74Smarks 		error = zfs_sticky_remove_access(dzp, zp, cr);
246947db7e74Smarks 
247047db7e74Smarks 	return (error);
247147db7e74Smarks }
247247db7e74Smarks 
2473fa9e4066Sahrens /*
2474fa9e4066Sahrens  * Determine whether Access should be granted/deny, without
2475fa9e4066Sahrens  * consulting least priv subsystem.
2476fa9e4066Sahrens  *
2477fa9e4066Sahrens  *
2478fa9e4066Sahrens  * The following chart is the recommended NFSv4 enforcement for
2479fa9e4066Sahrens  * ability to delete an object.
2480fa9e4066Sahrens  *
2481fa9e4066Sahrens  *      -------------------------------------------------------
2482fa9e4066Sahrens  *      |   Parent Dir  |           Target Object Permissions |
2483fa9e4066Sahrens  *      |  permissions  |                                     |
2484fa9e4066Sahrens  *      -------------------------------------------------------
2485fa9e4066Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
2486fa9e4066Sahrens  *      |               |  Delete    |  Delete   | unspecified|
2487fa9e4066Sahrens  *      -------------------------------------------------------
2488fa9e4066Sahrens  *      |  ACL Allows   | Permit     | Permit    | Permit     |
2489fa9e4066Sahrens  *      |  DELETE_CHILD |                                     |
2490fa9e4066Sahrens  *      -------------------------------------------------------
2491fa9e4066Sahrens  *      |  ACL Denies   | Permit     | Deny      | Deny       |
2492fa9e4066Sahrens  *      |  DELETE_CHILD |            |           |            |
2493fa9e4066Sahrens  *      -------------------------------------------------------
2494fa9e4066Sahrens  *      | ACL specifies |            |           |            |
2495fa9e4066Sahrens  *      | only allow    | Permit     | Permit    | Permit     |
2496fa9e4066Sahrens  *      | write and     |            |           |            |
2497fa9e4066Sahrens  *      | execute       |            |           |            |
2498fa9e4066Sahrens  *      -------------------------------------------------------
2499fa9e4066Sahrens  *      | ACL denies    |            |           |            |
2500fa9e4066Sahrens  *      | write and     | Permit     | Deny      | Deny       |
2501fa9e4066Sahrens  *      | execute       |            |           |            |
2502fa9e4066Sahrens  *      -------------------------------------------------------
2503fa9e4066Sahrens  *         ^
2504fa9e4066Sahrens  *         |
2505fa9e4066Sahrens  *         No search privilege, can't even look up file?
2506fa9e4066Sahrens  *
2507fa9e4066Sahrens  */
2508fa9e4066Sahrens int
2509fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
2510fa9e4066Sahrens {
2511da6c28aaSamw 	uint32_t dzp_working_mode = 0;
2512da6c28aaSamw 	uint32_t zp_working_mode = 0;
2513fa9e4066Sahrens 	int dzp_error, zp_error;
251423d5bb1fSmarks 	mode_t missing_perms;
2515da6c28aaSamw 	boolean_t dzpcheck_privs = B_TRUE;
2516da6c28aaSamw 	boolean_t zpcheck_privs = B_TRUE;
2517fa9e4066Sahrens 
2518fa9e4066Sahrens 	/*
251923d5bb1fSmarks 	 * We want specific DELETE permissions to
2520fa9e4066Sahrens 	 * take precedence over WRITE/EXECUTE.  We don't
2521fa9e4066Sahrens 	 * want an ACL such as this to mess us up.
252247db7e74Smarks 	 * user:joe:write_data:deny,user:joe:delete:allow
2523fa9e4066Sahrens 	 *
2524fa9e4066Sahrens 	 * However, deny permissions may ultimately be overridden
2525fa9e4066Sahrens 	 * by secpolicy_vnode_access().
252623d5bb1fSmarks 	 *
252723d5bb1fSmarks 	 * We will ask for all of the necessary permissions and then
252823d5bb1fSmarks 	 * look at the working modes from the directory and target object
252923d5bb1fSmarks 	 * to determine what was found.
2530fa9e4066Sahrens 	 */
2531fa9e4066Sahrens 
2532da6c28aaSamw 	if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
2533da6c28aaSamw 		return (EPERM);
2534da6c28aaSamw 
253523d5bb1fSmarks 	/*
253623d5bb1fSmarks 	 * If the directory permissions allow the delete, we are done.
253723d5bb1fSmarks 	 */
253823d5bb1fSmarks 	if ((dzp_error = zfs_zaccess_common(dzp,
253923d5bb1fSmarks 	    ACE_DELETE_CHILD|ACE_EXECUTE|ACE_WRITE_DATA,
254023d5bb1fSmarks 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
254123d5bb1fSmarks 		return (0);
2542fa9e4066Sahrens 
254323d5bb1fSmarks 	/*
254423d5bb1fSmarks 	 * If target object has delete permission then we are done
254523d5bb1fSmarks 	 */
254623d5bb1fSmarks 	if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
254723d5bb1fSmarks 	    &zpcheck_privs, B_FALSE, cr)) == 0)
254823d5bb1fSmarks 		return (0);
254923d5bb1fSmarks 
255023d5bb1fSmarks 	if (!dzpcheck_privs)
2551fa9e4066Sahrens 		return (dzp_error);
255223d5bb1fSmarks 	else if (!zpcheck_privs)
255323d5bb1fSmarks 		return (zp_error);
2554fa9e4066Sahrens 
2555fa9e4066Sahrens 	/*
255647db7e74Smarks 	 * First check the first row.
255747db7e74Smarks 	 * We only need to see if parent Allows delete_child
2558fa9e4066Sahrens 	 */
2559169cdae2Smarks 	if ((dzp_working_mode & ACE_DELETE_CHILD) == 0)
2560fa9e4066Sahrens 		return (0);
2561fa9e4066Sahrens 
2562fa9e4066Sahrens 	/*
2563fa9e4066Sahrens 	 * Second row
256447db7e74Smarks 	 * we already have the necessary information in
256547db7e74Smarks 	 * zp_working_mode, zp_error and dzp_error.
2566fa9e4066Sahrens 	 */
2567fa9e4066Sahrens 
2568169cdae2Smarks 	if ((zp_working_mode & ACE_DELETE) == 0)
2569fa9e4066Sahrens 		return (0);
2570fa9e4066Sahrens 
257147db7e74Smarks 	/*
257223d5bb1fSmarks 	 * determine the needed permissions based off of the directories
257323d5bb1fSmarks 	 * working mode
257447db7e74Smarks 	 */
257547db7e74Smarks 
257623d5bb1fSmarks 	missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0;
257723d5bb1fSmarks 	missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0;
257823d5bb1fSmarks 
257947db7e74Smarks 	if (dzp_error == EACCES)
258023d5bb1fSmarks 		return (zfs_delete_final_check(zp, dzp, missing_perms, cr));
258147db7e74Smarks 
2582fa9e4066Sahrens 	/*
2583fa9e4066Sahrens 	 * Third Row
258423d5bb1fSmarks 	 * only need to see if we have write/execute on directory.
2585fa9e4066Sahrens 	 */
2586fa9e4066Sahrens 
258723d5bb1fSmarks 	if (missing_perms == 0)
258847db7e74Smarks 		return (zfs_sticky_remove_access(dzp, zp, cr));
2589fa9e4066Sahrens 
2590fa9e4066Sahrens 	/*
2591fa9e4066Sahrens 	 * Fourth Row
2592fa9e4066Sahrens 	 */
2593fa9e4066Sahrens 
259423d5bb1fSmarks 	if (missing_perms && ((zp_working_mode & ACE_DELETE) == 0))
259547db7e74Smarks 		return (zfs_sticky_remove_access(dzp, zp, cr));
2596fa9e4066Sahrens 
259723d5bb1fSmarks 	return (zfs_delete_final_check(zp, dzp, missing_perms, cr));
2598fa9e4066Sahrens }
2599fa9e4066Sahrens 
2600fa9e4066Sahrens int
2601fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
2602fa9e4066Sahrens     znode_t *tzp, cred_t *cr)
2603fa9e4066Sahrens {
2604fa9e4066Sahrens 	int add_perm;
2605fa9e4066Sahrens 	int error;
2606fa9e4066Sahrens 
2607da6c28aaSamw 	if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED)
2608da6c28aaSamw 		return (EACCES);
2609da6c28aaSamw 
2610fa9e4066Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
2611fa9e4066Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
2612fa9e4066Sahrens 
2613fa9e4066Sahrens 	/*
2614fa9e4066Sahrens 	 * Rename permissions are combination of delete permission +
2615fa9e4066Sahrens 	 * add file/subdir permission.
2616fa9e4066Sahrens 	 */
2617fa9e4066Sahrens 
2618fa9e4066Sahrens 	/*
2619fa9e4066Sahrens 	 * first make sure we do the delete portion.
2620fa9e4066Sahrens 	 *
2621fa9e4066Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
2622fa9e4066Sahrens 	 */
2623fa9e4066Sahrens 
2624fa9e4066Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
2625fa9e4066Sahrens 		return (error);
2626fa9e4066Sahrens 
2627fa9e4066Sahrens 	/*
2628fa9e4066Sahrens 	 * If we have a tzp, see if we can delete it?
2629fa9e4066Sahrens 	 */
2630fa9e4066Sahrens 	if (tzp) {
2631fa9e4066Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
2632fa9e4066Sahrens 			return (error);
2633fa9e4066Sahrens 	}
2634fa9e4066Sahrens 
2635fa9e4066Sahrens 	/*
2636fa9e4066Sahrens 	 * Now check for add permissions
2637fa9e4066Sahrens 	 */
2638da6c28aaSamw 	error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
2639fa9e4066Sahrens 
2640fa9e4066Sahrens 	return (error);
2641fa9e4066Sahrens }
2642