xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision 06799660)
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 /*
2227dd1e87SMark Shellenbaum  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23be6fd75aSMatthew Ahrens  * Copyright (c) 2013 by Delphix. All rights reserved.
24f37b3cbbSMatt Barden  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
2570561057SGordon Ross  * Copyright 2019-2023 RackTop Systems, Inc.
26fa9e4066Sahrens  */
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>
550a586ceaSMark Shellenbaum #include <sys/sa.h>
56fa9e4066Sahrens #include "fs/fs_subr.h"
57fa9e4066Sahrens #include <acl/acl_common.h>
58fa9e4066Sahrens 
59fa9e4066Sahrens #define	ALLOW	ACE_ACCESS_ALLOWED_ACE_TYPE
60fa9e4066Sahrens #define	DENY	ACE_ACCESS_DENIED_ACE_TYPE
61da6c28aaSamw #define	MAX_ACE_TYPE	ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
62003c2582SMark Shellenbaum #define	MIN_ACE_TYPE	ALLOW
63fa9e4066Sahrens 
64fa9e4066Sahrens #define	OWNING_GROUP		(ACE_GROUP|ACE_IDENTIFIER_GROUP)
65fa9e4066Sahrens #define	EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
66fa9e4066Sahrens     ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
67fa9e4066Sahrens #define	EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
68fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
69fa9e4066Sahrens #define	OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
70fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
71da6c28aaSamw 
72da6c28aaSamw #define	ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
73da6c28aaSamw     ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
74da6c28aaSamw     ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
75da6c28aaSamw     ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
76da6c28aaSamw 
77f52e0e2bSMark Shellenbaum #define	WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
78f52e0e2bSMark Shellenbaum #define	WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
79f52e0e2bSMark Shellenbaum     ACE_DELETE|ACE_DELETE_CHILD)
80f52e0e2bSMark Shellenbaum #define	WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS)
81fa9e4066Sahrens 
82fa9e4066Sahrens #define	OGE_CLEAR	(ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
83fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
84fa9e4066Sahrens 
85fa9e4066Sahrens #define	OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
86fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
87fa9e4066Sahrens 
88fa9e4066Sahrens #define	ALL_INHERIT	(ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
89da6c28aaSamw     ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
90fa9e4066Sahrens 
91b3d141f8Smarks #define	RESTRICTED_CLEAR	(ACE_WRITE_ACL|ACE_WRITE_OWNER)
92fa9e4066Sahrens 
93da6c28aaSamw #define	V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
94da6c28aaSamw     ZFS_ACL_PROTECTED)
95da6c28aaSamw 
96da6c28aaSamw #define	ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
97da6c28aaSamw     ZFS_ACL_OBJ_ACE)
98da6c28aaSamw 
994929fd5eSTim Haley #define	ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH)
1004929fd5eSTim Haley 
101*06799660SGordon Ross typedef struct zfs_acl_iter {
102*06799660SGordon Ross 	zfs_acl_t	*zai_aclp;	/* The ACL we're iterating */
103*06799660SGordon Ross 	zfs_acl_node_t	*zai_curr_node;	/* current node iterator is in */
104*06799660SGordon Ross 	void		*zai_next_ace;	/* pointer to next ACE */
105*06799660SGordon Ross 	int		zai_ace_idx;	/* ace iterator positioned on */
106*06799660SGordon Ross } zfs_acl_iter_t;
107*06799660SGordon Ross 
108da6c28aaSamw static uint16_t
zfs_ace_v0_get_type(void * acep)109da6c28aaSamw zfs_ace_v0_get_type(void *acep)
110da6c28aaSamw {
111da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_type);
112da6c28aaSamw }
113da6c28aaSamw 
114da6c28aaSamw static uint16_t
zfs_ace_v0_get_flags(void * acep)115da6c28aaSamw zfs_ace_v0_get_flags(void *acep)
116da6c28aaSamw {
117da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_flags);
118da6c28aaSamw }
119fa9e4066Sahrens 
120da6c28aaSamw static uint32_t
zfs_ace_v0_get_mask(void * acep)121da6c28aaSamw zfs_ace_v0_get_mask(void *acep)
122da6c28aaSamw {
123da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_access_mask);
124da6c28aaSamw }
125da6c28aaSamw 
126da6c28aaSamw static uint64_t
zfs_ace_v0_get_who(void * acep)127da6c28aaSamw zfs_ace_v0_get_who(void *acep)
128da6c28aaSamw {
129da6c28aaSamw 	return (((zfs_oldace_t *)acep)->z_fuid);
130da6c28aaSamw }
131da6c28aaSamw 
132da6c28aaSamw static void
zfs_ace_v0_set_type(void * acep,uint16_t type)133da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type)
134da6c28aaSamw {
135da6c28aaSamw 	((zfs_oldace_t *)acep)->z_type = type;
136da6c28aaSamw }
137da6c28aaSamw 
138da6c28aaSamw static void
zfs_ace_v0_set_flags(void * acep,uint16_t flags)139da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags)
140da6c28aaSamw {
141da6c28aaSamw 	((zfs_oldace_t *)acep)->z_flags = flags;
142da6c28aaSamw }
143da6c28aaSamw 
144da6c28aaSamw static void
zfs_ace_v0_set_mask(void * acep,uint32_t mask)145da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask)
146da6c28aaSamw {
147da6c28aaSamw 	((zfs_oldace_t *)acep)->z_access_mask = mask;
148da6c28aaSamw }
149da6c28aaSamw 
150da6c28aaSamw static void
zfs_ace_v0_set_who(void * acep,uint64_t who)151da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who)
152da6c28aaSamw {
153da6c28aaSamw 	((zfs_oldace_t *)acep)->z_fuid = who;
154da6c28aaSamw }
155da6c28aaSamw 
156da6c28aaSamw /*ARGSUSED*/
157da6c28aaSamw static size_t
zfs_ace_v0_size(void * acep)158da6c28aaSamw zfs_ace_v0_size(void *acep)
159da6c28aaSamw {
160da6c28aaSamw 	return (sizeof (zfs_oldace_t));
161da6c28aaSamw }
162da6c28aaSamw 
163da6c28aaSamw static size_t
zfs_ace_v0_abstract_size(void)164da6c28aaSamw zfs_ace_v0_abstract_size(void)
165da6c28aaSamw {
166da6c28aaSamw 	return (sizeof (zfs_oldace_t));
167da6c28aaSamw }
168da6c28aaSamw 
169da6c28aaSamw static int
zfs_ace_v0_mask_off(void)170da6c28aaSamw zfs_ace_v0_mask_off(void)
171da6c28aaSamw {
172da6c28aaSamw 	return (offsetof(zfs_oldace_t, z_access_mask));
173da6c28aaSamw }
174da6c28aaSamw 
175da6c28aaSamw /*ARGSUSED*/
176da6c28aaSamw static int
zfs_ace_v0_data(void * acep,void ** datap)177da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap)
178da6c28aaSamw {
179da6c28aaSamw 	*datap = NULL;
180da6c28aaSamw 	return (0);
181da6c28aaSamw }
182da6c28aaSamw 
183da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = {
184da6c28aaSamw 	zfs_ace_v0_get_mask,
185da6c28aaSamw 	zfs_ace_v0_set_mask,
186da6c28aaSamw 	zfs_ace_v0_get_flags,
187da6c28aaSamw 	zfs_ace_v0_set_flags,
188da6c28aaSamw 	zfs_ace_v0_get_type,
189da6c28aaSamw 	zfs_ace_v0_set_type,
190da6c28aaSamw 	zfs_ace_v0_get_who,
191da6c28aaSamw 	zfs_ace_v0_set_who,
192da6c28aaSamw 	zfs_ace_v0_size,
193da6c28aaSamw 	zfs_ace_v0_abstract_size,
194da6c28aaSamw 	zfs_ace_v0_mask_off,
195da6c28aaSamw 	zfs_ace_v0_data
196da6c28aaSamw };
197da6c28aaSamw 
198da6c28aaSamw static uint16_t
zfs_ace_fuid_get_type(void * acep)199da6c28aaSamw zfs_ace_fuid_get_type(void *acep)
200da6c28aaSamw {
201da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_type);
202da6c28aaSamw }
203da6c28aaSamw 
204da6c28aaSamw static uint16_t
zfs_ace_fuid_get_flags(void * acep)205da6c28aaSamw zfs_ace_fuid_get_flags(void *acep)
206da6c28aaSamw {
207da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_flags);
208da6c28aaSamw }
209da6c28aaSamw 
210da6c28aaSamw static uint32_t
zfs_ace_fuid_get_mask(void * acep)211da6c28aaSamw zfs_ace_fuid_get_mask(void *acep)
212da6c28aaSamw {
213da6c28aaSamw 	return (((zfs_ace_hdr_t *)acep)->z_access_mask);
214da6c28aaSamw }
215da6c28aaSamw 
216da6c28aaSamw static uint64_t
zfs_ace_fuid_get_who(void * args)217da6c28aaSamw zfs_ace_fuid_get_who(void *args)
218da6c28aaSamw {
219da6c28aaSamw 	uint16_t entry_type;
220da6c28aaSamw 	zfs_ace_t *acep = args;
221da6c28aaSamw 
222da6c28aaSamw 	entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
223da6c28aaSamw 
224da6c28aaSamw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
225da6c28aaSamw 	    entry_type == ACE_EVERYONE)
226da6c28aaSamw 		return (-1);
227da6c28aaSamw 	return (((zfs_ace_t *)acep)->z_fuid);
228da6c28aaSamw }
229da6c28aaSamw 
230da6c28aaSamw static void
zfs_ace_fuid_set_type(void * acep,uint16_t type)231da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type)
232da6c28aaSamw {
233da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_type = type;
234da6c28aaSamw }
235da6c28aaSamw 
236da6c28aaSamw static void
zfs_ace_fuid_set_flags(void * acep,uint16_t flags)237da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
238da6c28aaSamw {
239da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_flags = flags;
240da6c28aaSamw }
241da6c28aaSamw 
242da6c28aaSamw static void
zfs_ace_fuid_set_mask(void * acep,uint32_t mask)243da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
244da6c28aaSamw {
245da6c28aaSamw 	((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
246da6c28aaSamw }
247da6c28aaSamw 
248da6c28aaSamw static void
zfs_ace_fuid_set_who(void * arg,uint64_t who)249da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who)
250da6c28aaSamw {
251da6c28aaSamw 	zfs_ace_t *acep = arg;
252da6c28aaSamw 
253da6c28aaSamw 	uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
254da6c28aaSamw 
255da6c28aaSamw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
256da6c28aaSamw 	    entry_type == ACE_EVERYONE)
257da6c28aaSamw 		return;
258da6c28aaSamw 	acep->z_fuid = who;
259da6c28aaSamw }
260da6c28aaSamw 
261da6c28aaSamw static size_t
zfs_ace_fuid_size(void * acep)262da6c28aaSamw zfs_ace_fuid_size(void *acep)
263da6c28aaSamw {
264da6c28aaSamw 	zfs_ace_hdr_t *zacep = acep;
265da6c28aaSamw 	uint16_t entry_type;
266da6c28aaSamw 
267da6c28aaSamw 	switch (zacep->z_type) {
268da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
269da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
270da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
271da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
272da6c28aaSamw 		return (sizeof (zfs_object_ace_t));
273da6c28aaSamw 	case ALLOW:
274da6c28aaSamw 	case DENY:
275da6c28aaSamw 		entry_type =
276da6c28aaSamw 		    (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
277da6c28aaSamw 		if (entry_type == ACE_OWNER ||
2781ab99678SMark Shellenbaum 		    entry_type == OWNING_GROUP ||
279da6c28aaSamw 		    entry_type == ACE_EVERYONE)
280da6c28aaSamw 			return (sizeof (zfs_ace_hdr_t));
281da6c28aaSamw 		/*FALLTHROUGH*/
282da6c28aaSamw 	default:
283da6c28aaSamw 		return (sizeof (zfs_ace_t));
284da6c28aaSamw 	}
285da6c28aaSamw }
286da6c28aaSamw 
287da6c28aaSamw static size_t
zfs_ace_fuid_abstract_size(void)288da6c28aaSamw zfs_ace_fuid_abstract_size(void)
289da6c28aaSamw {
290da6c28aaSamw 	return (sizeof (zfs_ace_hdr_t));
291da6c28aaSamw }
292da6c28aaSamw 
293da6c28aaSamw static int
zfs_ace_fuid_mask_off(void)294da6c28aaSamw zfs_ace_fuid_mask_off(void)
295da6c28aaSamw {
296da6c28aaSamw 	return (offsetof(zfs_ace_hdr_t, z_access_mask));
297da6c28aaSamw }
298da6c28aaSamw 
299da6c28aaSamw static int
zfs_ace_fuid_data(void * acep,void ** datap)300da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap)
301da6c28aaSamw {
302da6c28aaSamw 	zfs_ace_t *zacep = acep;
303da6c28aaSamw 	zfs_object_ace_t *zobjp;
304da6c28aaSamw 
305da6c28aaSamw 	switch (zacep->z_hdr.z_type) {
306da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
307da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
308da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
309da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
310da6c28aaSamw 		zobjp = acep;
311da6c28aaSamw 		*datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
312da6c28aaSamw 		return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
313da6c28aaSamw 	default:
314da6c28aaSamw 		*datap = NULL;
315da6c28aaSamw 		return (0);
316da6c28aaSamw 	}
317da6c28aaSamw }
318da6c28aaSamw 
319da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = {
320da6c28aaSamw 	zfs_ace_fuid_get_mask,
321da6c28aaSamw 	zfs_ace_fuid_set_mask,
322da6c28aaSamw 	zfs_ace_fuid_get_flags,
323da6c28aaSamw 	zfs_ace_fuid_set_flags,
324da6c28aaSamw 	zfs_ace_fuid_get_type,
325da6c28aaSamw 	zfs_ace_fuid_set_type,
326da6c28aaSamw 	zfs_ace_fuid_get_who,
327da6c28aaSamw 	zfs_ace_fuid_set_who,
328da6c28aaSamw 	zfs_ace_fuid_size,
329da6c28aaSamw 	zfs_ace_fuid_abstract_size,
330da6c28aaSamw 	zfs_ace_fuid_mask_off,
331da6c28aaSamw 	zfs_ace_fuid_data
332da6c28aaSamw };
333da6c28aaSamw 
3340a586ceaSMark Shellenbaum /*
3350a586ceaSMark Shellenbaum  * The following three functions are provided for compatibility with
3360a586ceaSMark Shellenbaum  * older ZPL version in order to determine if the file use to have
3370a586ceaSMark Shellenbaum  * an external ACL and what version of ACL previously existed on the
3380a586ceaSMark Shellenbaum  * file.  Would really be nice to not need this, sigh.
3390a586ceaSMark Shellenbaum  */
3400a586ceaSMark Shellenbaum uint64_t
zfs_external_acl(znode_t * zp)3410a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp)
3420a586ceaSMark Shellenbaum {
3430a586ceaSMark Shellenbaum 	zfs_acl_phys_t acl_phys;
3441412a1a2SMark Shellenbaum 	int error;
3450a586ceaSMark Shellenbaum 
3460a586ceaSMark Shellenbaum 	if (zp->z_is_sa)
3470a586ceaSMark Shellenbaum 		return (0);
3480a586ceaSMark Shellenbaum 
3491412a1a2SMark Shellenbaum 	/*
3501412a1a2SMark Shellenbaum 	 * Need to deal with a potential
3511412a1a2SMark Shellenbaum 	 * race where zfs_sa_upgrade could cause
3521412a1a2SMark Shellenbaum 	 * z_isa_sa to change.
3531412a1a2SMark Shellenbaum 	 *
3541412a1a2SMark Shellenbaum 	 * If the lookup fails then the state of z_is_sa should have
3551412a1a2SMark Shellenbaum 	 * changed.
3561412a1a2SMark Shellenbaum 	 */
3570a586ceaSMark Shellenbaum 
3581412a1a2SMark Shellenbaum 	if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
3591412a1a2SMark Shellenbaum 	    &acl_phys, sizeof (acl_phys))) == 0)
3601412a1a2SMark Shellenbaum 		return (acl_phys.z_acl_extern_obj);
3611412a1a2SMark Shellenbaum 	else {
3621412a1a2SMark Shellenbaum 		/*
3631412a1a2SMark Shellenbaum 		 * after upgrade the SA_ZPL_ZNODE_ACL should have been
3641412a1a2SMark Shellenbaum 		 * removed
3651412a1a2SMark Shellenbaum 		 */
3661412a1a2SMark Shellenbaum 		VERIFY(zp->z_is_sa && error == ENOENT);
3671412a1a2SMark Shellenbaum 		return (0);
3681412a1a2SMark Shellenbaum 	}
3690a586ceaSMark Shellenbaum }
3700a586ceaSMark Shellenbaum 
3710a586ceaSMark Shellenbaum /*
3720a586ceaSMark Shellenbaum  * Determine size of ACL in bytes
3730a586ceaSMark Shellenbaum  *
3740a586ceaSMark Shellenbaum  * This is more complicated than it should be since we have to deal
3750a586ceaSMark Shellenbaum  * with old external ACLs.
3760a586ceaSMark Shellenbaum  */
3770a586ceaSMark Shellenbaum static int
zfs_acl_znode_info(znode_t * zp,int * aclsize,int * aclcount,zfs_acl_phys_t * aclphys)3780a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
3790a586ceaSMark Shellenbaum     zfs_acl_phys_t *aclphys)
3800a586ceaSMark Shellenbaum {
3810a586ceaSMark Shellenbaum 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
3820a586ceaSMark Shellenbaum 	uint64_t acl_count;
3830a586ceaSMark Shellenbaum 	int size;
3840a586ceaSMark Shellenbaum 	int error;
3850a586ceaSMark Shellenbaum 
386*06799660SGordon Ross 	ASSERT(RW_ISWRITER(&zp->z_acl_lock));
3870a586ceaSMark Shellenbaum 	if (zp->z_is_sa) {
3880a586ceaSMark Shellenbaum 		if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs),
3890a586ceaSMark Shellenbaum 		    &size)) != 0)
3900a586ceaSMark Shellenbaum 			return (error);
3910a586ceaSMark Shellenbaum 		*aclsize = size;
3920a586ceaSMark Shellenbaum 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs),
3930a586ceaSMark Shellenbaum 		    &acl_count, sizeof (acl_count))) != 0)
3940a586ceaSMark Shellenbaum 			return (error);
3950a586ceaSMark Shellenbaum 		*aclcount = acl_count;
3960a586ceaSMark Shellenbaum 	} else {
3970a586ceaSMark Shellenbaum 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
3980a586ceaSMark Shellenbaum 		    aclphys, sizeof (*aclphys))) != 0)
3990a586ceaSMark Shellenbaum 			return (error);
4000a586ceaSMark Shellenbaum 
4010a586ceaSMark Shellenbaum 		if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) {
4020a586ceaSMark Shellenbaum 			*aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size);
4030a586ceaSMark Shellenbaum 			*aclcount = aclphys->z_acl_size;
4040a586ceaSMark Shellenbaum 		} else {
4050a586ceaSMark Shellenbaum 			*aclsize = aclphys->z_acl_size;
4060a586ceaSMark Shellenbaum 			*aclcount = aclphys->z_acl_count;
4070a586ceaSMark Shellenbaum 		}
4080a586ceaSMark Shellenbaum 	}
4090a586ceaSMark Shellenbaum 	return (0);
4100a586ceaSMark Shellenbaum }
4110a586ceaSMark Shellenbaum 
4120a586ceaSMark Shellenbaum int
zfs_znode_acl_version(znode_t * zp)4130a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp)
4140a586ceaSMark Shellenbaum {
4150a586ceaSMark Shellenbaum 	zfs_acl_phys_t acl_phys;
4160a586ceaSMark Shellenbaum 
4171412a1a2SMark Shellenbaum 	if (zp->z_is_sa)
4180a586ceaSMark Shellenbaum 		return (ZFS_ACL_VERSION_FUID);
4191412a1a2SMark Shellenbaum 	else {
4201412a1a2SMark Shellenbaum 		int error;
4211412a1a2SMark Shellenbaum 
4221412a1a2SMark Shellenbaum 		/*
4231412a1a2SMark Shellenbaum 		 * Need to deal with a potential
4241412a1a2SMark Shellenbaum 		 * race where zfs_sa_upgrade could cause
4251412a1a2SMark Shellenbaum 		 * z_isa_sa to change.
4261412a1a2SMark Shellenbaum 		 *
4271412a1a2SMark Shellenbaum 		 * If the lookup fails then the state of z_is_sa should have
4281412a1a2SMark Shellenbaum 		 * changed.
4291412a1a2SMark Shellenbaum 		 */
4301412a1a2SMark Shellenbaum 		if ((error = sa_lookup(zp->z_sa_hdl,
4310a586ceaSMark Shellenbaum 		    SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
4321412a1a2SMark Shellenbaum 		    &acl_phys, sizeof (acl_phys))) == 0)
4331412a1a2SMark Shellenbaum 			return (acl_phys.z_acl_version);
4341412a1a2SMark Shellenbaum 		else {
4351412a1a2SMark Shellenbaum 			/*
4361412a1a2SMark Shellenbaum 			 * After upgrade SA_ZPL_ZNODE_ACL should have
4371412a1a2SMark Shellenbaum 			 * been removed.
4381412a1a2SMark Shellenbaum 			 */
4391412a1a2SMark Shellenbaum 			VERIFY(zp->z_is_sa && error == ENOENT);
4401412a1a2SMark Shellenbaum 			return (ZFS_ACL_VERSION_FUID);
4411412a1a2SMark Shellenbaum 		}
4420a586ceaSMark Shellenbaum 	}
4430a586ceaSMark Shellenbaum }
4440a586ceaSMark Shellenbaum 
445da6c28aaSamw static int
zfs_acl_version(int version)446da6c28aaSamw zfs_acl_version(int version)
447da6c28aaSamw {
448da6c28aaSamw 	if (version < ZPL_VERSION_FUID)
449da6c28aaSamw 		return (ZFS_ACL_VERSION_INITIAL);
450da6c28aaSamw 	else
451da6c28aaSamw 		return (ZFS_ACL_VERSION_FUID);
452da6c28aaSamw }
453da6c28aaSamw 
454da6c28aaSamw static int
zfs_acl_version_zp(znode_t * zp)455da6c28aaSamw zfs_acl_version_zp(znode_t *zp)
456da6c28aaSamw {
457da6c28aaSamw 	return (zfs_acl_version(zp->z_zfsvfs->z_version));
458da6c28aaSamw }
459fa9e4066Sahrens 
4600a586ceaSMark Shellenbaum zfs_acl_t *
zfs_acl_alloc(int vers)461da6c28aaSamw zfs_acl_alloc(int vers)
462fa9e4066Sahrens {
463fa9e4066Sahrens 	zfs_acl_t *aclp;
464fa9e4066Sahrens 
465fa9e4066Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
466da6c28aaSamw 	list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
467da6c28aaSamw 	    offsetof(zfs_acl_node_t, z_next));
468da6c28aaSamw 	aclp->z_version = vers;
469da6c28aaSamw 	if (vers == ZFS_ACL_VERSION_FUID)
470da6c28aaSamw 		aclp->z_ops = zfs_acl_fuid_ops;
471da6c28aaSamw 	else
472da6c28aaSamw 		aclp->z_ops = zfs_acl_v0_ops;
473fa9e4066Sahrens 	return (aclp);
474fa9e4066Sahrens }
475fa9e4066Sahrens 
4760a586ceaSMark Shellenbaum zfs_acl_node_t *
zfs_acl_node_alloc(size_t bytes)477da6c28aaSamw zfs_acl_node_alloc(size_t bytes)
478da6c28aaSamw {
479da6c28aaSamw 	zfs_acl_node_t *aclnode;
480da6c28aaSamw 
481da6c28aaSamw 	aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
482da6c28aaSamw 	if (bytes) {
483da6c28aaSamw 		aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
484da6c28aaSamw 		aclnode->z_allocdata = aclnode->z_acldata;
485da6c28aaSamw 		aclnode->z_allocsize = bytes;
486da6c28aaSamw 		aclnode->z_size = bytes;
487da6c28aaSamw 	}
488da6c28aaSamw 
489da6c28aaSamw 	return (aclnode);
490da6c28aaSamw }
491da6c28aaSamw 
492da6c28aaSamw static void
zfs_acl_node_free(zfs_acl_node_t * aclnode)493da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode)
494da6c28aaSamw {
495da6c28aaSamw 	if (aclnode->z_allocsize)
496da6c28aaSamw 		kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
497da6c28aaSamw 	kmem_free(aclnode, sizeof (zfs_acl_node_t));
498da6c28aaSamw }
499da6c28aaSamw 
5002459a9eaSmarks static void
zfs_acl_release_nodes(zfs_acl_t * aclp)5012459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp)
502fa9e4066Sahrens {
503da6c28aaSamw 	zfs_acl_node_t *aclnode;
504da6c28aaSamw 
505da6c28aaSamw 	while (aclnode = list_head(&aclp->z_acl)) {
506da6c28aaSamw 		list_remove(&aclp->z_acl, aclnode);
507da6c28aaSamw 		zfs_acl_node_free(aclnode);
508fa9e4066Sahrens 	}
5092459a9eaSmarks 	aclp->z_acl_count = 0;
5102459a9eaSmarks 	aclp->z_acl_bytes = 0;
5112459a9eaSmarks }
512da6c28aaSamw 
5132459a9eaSmarks void
zfs_acl_free(zfs_acl_t * aclp)5142459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp)
5152459a9eaSmarks {
5162459a9eaSmarks 	zfs_acl_release_nodes(aclp);
517da6c28aaSamw 	list_destroy(&aclp->z_acl);
518fa9e4066Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
519fa9e4066Sahrens }
520fa9e4066Sahrens 
521da6c28aaSamw static boolean_t
zfs_acl_valid_ace_type(uint_t type,uint_t flags)522003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags)
523fa9e4066Sahrens {
524003c2582SMark Shellenbaum 	uint16_t entry_type;
525da6c28aaSamw 
526003c2582SMark Shellenbaum 	switch (type) {
527003c2582SMark Shellenbaum 	case ALLOW:
528003c2582SMark Shellenbaum 	case DENY:
529003c2582SMark Shellenbaum 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
530003c2582SMark Shellenbaum 	case ACE_SYSTEM_ALARM_ACE_TYPE:
531003c2582SMark Shellenbaum 		entry_type = flags & ACE_TYPE_FLAGS;
532003c2582SMark Shellenbaum 		return (entry_type == ACE_OWNER ||
533003c2582SMark Shellenbaum 		    entry_type == OWNING_GROUP ||
534003c2582SMark Shellenbaum 		    entry_type == ACE_EVERYONE || entry_type == 0 ||
535003c2582SMark Shellenbaum 		    entry_type == ACE_IDENTIFIER_GROUP);
536da6c28aaSamw 	default:
537003c2582SMark Shellenbaum 		if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
538003c2582SMark Shellenbaum 			return (B_TRUE);
539da6c28aaSamw 	}
540003c2582SMark Shellenbaum 	return (B_FALSE);
541003c2582SMark Shellenbaum }
542fa9e4066Sahrens 
543003c2582SMark Shellenbaum static boolean_t
zfs_ace_valid(vtype_t obj_type,zfs_acl_t * aclp,uint16_t type,uint16_t iflags)544003c2582SMark Shellenbaum zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
545003c2582SMark Shellenbaum {
546169cdae2Smarks 	/*
547003c2582SMark Shellenbaum 	 * first check type of entry
548169cdae2Smarks 	 */
549fa9e4066Sahrens 
550003c2582SMark Shellenbaum 	if (!zfs_acl_valid_ace_type(type, iflags))
551da6c28aaSamw 		return (B_FALSE);
552da6c28aaSamw 
553da6c28aaSamw 	switch (type) {
554da6c28aaSamw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
555da6c28aaSamw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
556da6c28aaSamw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
557da6c28aaSamw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
558da6c28aaSamw 		if (aclp->z_version < ZFS_ACL_VERSION_FUID)
559da6c28aaSamw 			return (B_FALSE);
560da6c28aaSamw 		aclp->z_hints |= ZFS_ACL_OBJ_ACE;
561da6c28aaSamw 	}
562da6c28aaSamw 
563003c2582SMark Shellenbaum 	/*
564003c2582SMark Shellenbaum 	 * next check inheritance level flags
565003c2582SMark Shellenbaum 	 */
566003c2582SMark Shellenbaum 
567b249c65cSmarks 	if (obj_type == VDIR &&
568b249c65cSmarks 	    (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
569da6c28aaSamw 		aclp->z_hints |= ZFS_INHERIT_ACE;
570da6c28aaSamw 
571da6c28aaSamw 	if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
572da6c28aaSamw 		if ((iflags & (ACE_FILE_INHERIT_ACE|
573da6c28aaSamw 		    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
574da6c28aaSamw 			return (B_FALSE);
575da6c28aaSamw 		}
576da6c28aaSamw 	}
577da6c28aaSamw 
578da6c28aaSamw 	return (B_TRUE);
579da6c28aaSamw }
580da6c28aaSamw 
581*06799660SGordon Ross /*
582*06799660SGordon Ross  * We want this iterator to be usable by multiple threads in parallel.
583*06799660SGordon Ross  * Caller now passes iterator state as 1st arg.
584*06799660SGordon Ross  */
585da6c28aaSamw static void *
zfs_acl_next_ace(zfs_acl_iter_t * zaip,void * start,uint64_t * who,uint32_t * access_mask,uint16_t * iflags,uint16_t * type)586*06799660SGordon Ross zfs_acl_next_ace(zfs_acl_iter_t *zaip, void *start, uint64_t *who,
587da6c28aaSamw     uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
588da6c28aaSamw {
589*06799660SGordon Ross 	zfs_acl_t *aclp = zaip->zai_aclp;
590da6c28aaSamw 	zfs_acl_node_t *aclnode;
591da6c28aaSamw 
5920a586ceaSMark Shellenbaum 	ASSERT(aclp);
5930a586ceaSMark Shellenbaum 
594da6c28aaSamw 	if (start == NULL) {
595da6c28aaSamw 		aclnode = list_head(&aclp->z_acl);
596da6c28aaSamw 		if (aclnode == NULL)
597da6c28aaSamw 			return (NULL);
598da6c28aaSamw 
599*06799660SGordon Ross 		zaip->zai_curr_node = aclnode;
600*06799660SGordon Ross 		zaip->zai_next_ace = aclnode->z_acldata;
601*06799660SGordon Ross 		zaip->zai_ace_idx = 0;
602da6c28aaSamw 	}
603da6c28aaSamw 
604*06799660SGordon Ross 	aclnode = zaip->zai_curr_node;
605da6c28aaSamw 
606da6c28aaSamw 	if (aclnode == NULL)
607da6c28aaSamw 		return (NULL);
608da6c28aaSamw 
609*06799660SGordon Ross 	if (zaip->zai_ace_idx >= aclnode->z_ace_count) {
610*06799660SGordon Ross 	next_node:
611da6c28aaSamw 		aclnode = list_next(&aclp->z_acl, aclnode);
612da6c28aaSamw 		if (aclnode == NULL)
613da6c28aaSamw 			return (NULL);
614*06799660SGordon Ross 		zaip->zai_curr_node = aclnode;
615*06799660SGordon Ross 		zaip->zai_ace_idx = 0;
616*06799660SGordon Ross 		zaip->zai_next_ace = aclnode->z_acldata;
617da6c28aaSamw 	}
618da6c28aaSamw 
619*06799660SGordon Ross 	if (zaip->zai_ace_idx < aclnode->z_ace_count) {
620*06799660SGordon Ross 		void *acep = zaip->zai_next_ace;
621003c2582SMark Shellenbaum 		size_t ace_size;
622003c2582SMark Shellenbaum 
623003c2582SMark Shellenbaum 		/*
624003c2582SMark Shellenbaum 		 * Make sure we don't overstep our bounds
625003c2582SMark Shellenbaum 		 */
626003c2582SMark Shellenbaum 		ace_size = aclp->z_ops.ace_size(acep);
627003c2582SMark Shellenbaum 
628003c2582SMark Shellenbaum 		if (((caddr_t)acep + ace_size) >
629003c2582SMark Shellenbaum 		    ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
630*06799660SGordon Ross 			DTRACE_PROBE3(acl__size__error, zfs_acl_t *, aclp,
631*06799660SGordon Ross 			    zfs_acl_node_t *, aclnode, zfs_ace_hdr_t *, acep);
632*06799660SGordon Ross 			goto next_node;
633003c2582SMark Shellenbaum 		}
634003c2582SMark Shellenbaum 
635da6c28aaSamw 		*iflags = aclp->z_ops.ace_flags_get(acep);
636da6c28aaSamw 		*type = aclp->z_ops.ace_type_get(acep);
637da6c28aaSamw 		*access_mask = aclp->z_ops.ace_mask_get(acep);
638da6c28aaSamw 		*who = aclp->z_ops.ace_who_get(acep);
639*06799660SGordon Ross 
640*06799660SGordon Ross 		zaip->zai_next_ace = (caddr_t)acep + ace_size;
641*06799660SGordon Ross 		zaip->zai_ace_idx++;
6420a586ceaSMark Shellenbaum 
643da6c28aaSamw 		return ((void *)acep);
644da6c28aaSamw 	}
645da6c28aaSamw 	return (NULL);
646da6c28aaSamw }
647da6c28aaSamw 
648da6c28aaSamw /*ARGSUSED*/
649da6c28aaSamw static uint64_t
zfs_ace_walk(void * datap,uint64_t cookie,int aclcnt,uint16_t * flags,uint16_t * type,uint32_t * mask)650da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
651da6c28aaSamw     uint16_t *flags, uint16_t *type, uint32_t *mask)
652da6c28aaSamw {
653*06799660SGordon Ross 	zfs_acl_iter_t *zaip = datap;
654da6c28aaSamw 	zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
655da6c28aaSamw 	uint64_t who;
656da6c28aaSamw 
657*06799660SGordon Ross 	acep = zfs_acl_next_ace(zaip, acep, &who, mask,
658da6c28aaSamw 	    flags, type);
659da6c28aaSamw 	return ((uint64_t)(uintptr_t)acep);
660da6c28aaSamw }
661da6c28aaSamw 
662da6c28aaSamw /*
663da6c28aaSamw  * Copy ACE to internal ZFS format.
664da6c28aaSamw  * While processing the ACL each ACE will be validated for correctness.
665da6c28aaSamw  * ACE FUIDs will be created later.
666da6c28aaSamw  */
667da6c28aaSamw int
zfs_copy_ace_2_fuid(zfsvfs_t * zfsvfs,vtype_t obj_type,zfs_acl_t * aclp,void * datap,zfs_ace_t * z_acl,uint64_t aclcnt,size_t * size,zfs_fuid_info_t ** fuidp,cred_t * cr)66889459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp,
6690a586ceaSMark Shellenbaum     void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size,
67089459e17SMark Shellenbaum     zfs_fuid_info_t **fuidp, cred_t *cr)
671da6c28aaSamw {
672da6c28aaSamw 	int i;
673da6c28aaSamw 	uint16_t entry_type;
674da6c28aaSamw 	zfs_ace_t *aceptr = z_acl;
675da6c28aaSamw 	ace_t *acep = datap;
676da6c28aaSamw 	zfs_object_ace_t *zobjacep;
677da6c28aaSamw 	ace_object_t *aceobjp;
678da6c28aaSamw 
679da6c28aaSamw 	for (i = 0; i != aclcnt; i++) {
680da6c28aaSamw 		aceptr->z_hdr.z_access_mask = acep->a_access_mask;
681da6c28aaSamw 		aceptr->z_hdr.z_flags = acep->a_flags;
682da6c28aaSamw 		aceptr->z_hdr.z_type = acep->a_type;
683da6c28aaSamw 		entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
684da6c28aaSamw 		if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
6854c841f60Smarks 		    entry_type != ACE_EVERYONE) {
68689459e17SMark Shellenbaum 			aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who,
68789459e17SMark Shellenbaum 			    cr, (entry_type == 0) ?
68889459e17SMark Shellenbaum 			    ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp);
6894c841f60Smarks 		}
6904c841f60Smarks 
691da6c28aaSamw 		/*
692da6c28aaSamw 		 * Make sure ACE is valid
693da6c28aaSamw 		 */
694da6c28aaSamw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
695da6c28aaSamw 		    aceptr->z_hdr.z_flags) != B_TRUE)
696be6fd75aSMatthew Ahrens 			return (SET_ERROR(EINVAL));
697da6c28aaSamw 
698da6c28aaSamw 		switch (acep->a_type) {
699da6c28aaSamw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
700da6c28aaSamw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
701da6c28aaSamw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
702da6c28aaSamw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
703da6c28aaSamw 			zobjacep = (zfs_object_ace_t *)aceptr;
704da6c28aaSamw 			aceobjp = (ace_object_t *)acep;
705da6c28aaSamw 
706da6c28aaSamw 			bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
707da6c28aaSamw 			    sizeof (aceobjp->a_obj_type));
708da6c28aaSamw 			bcopy(aceobjp->a_inherit_obj_type,
709da6c28aaSamw 			    zobjacep->z_inherit_type,
710da6c28aaSamw 			    sizeof (aceobjp->a_inherit_obj_type));
711da6c28aaSamw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
712da6c28aaSamw 			break;
713da6c28aaSamw 		default:
714da6c28aaSamw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
715da6c28aaSamw 		}
716da6c28aaSamw 
717da6c28aaSamw 		aceptr = (zfs_ace_t *)((caddr_t)aceptr +
718da6c28aaSamw 		    aclp->z_ops.ace_size(aceptr));
719da6c28aaSamw 	}
720da6c28aaSamw 
721da6c28aaSamw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
722da6c28aaSamw 
723da6c28aaSamw 	return (0);
724da6c28aaSamw }
725da6c28aaSamw 
726da6c28aaSamw /*
727da6c28aaSamw  * Copy ZFS ACEs to fixed size ace_t layout
728da6c28aaSamw  */
729da6c28aaSamw static void
zfs_copy_fuid_2_ace(zfsvfs_t * zfsvfs,zfs_acl_t * aclp,cred_t * cr,void * datap,int filter)730bda89588Sjp zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
731bda89588Sjp     void *datap, int filter)
732da6c28aaSamw {
733da6c28aaSamw 	uint64_t who;
734da6c28aaSamw 	uint32_t access_mask;
735da6c28aaSamw 	uint16_t iflags, type;
736da6c28aaSamw 	zfs_ace_hdr_t *zacep = NULL;
737da6c28aaSamw 	ace_t *acep = datap;
738da6c28aaSamw 	ace_object_t *objacep;
739da6c28aaSamw 	zfs_object_ace_t *zobjacep;
740da6c28aaSamw 	size_t ace_size;
741da6c28aaSamw 	uint16_t entry_type;
742*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
743da6c28aaSamw 
744*06799660SGordon Ross 	zai.zai_aclp = aclp;
745*06799660SGordon Ross 	while (zacep = zfs_acl_next_ace(&zai, zacep,
746da6c28aaSamw 	    &who, &access_mask, &iflags, &type)) {
747da6c28aaSamw 
748da6c28aaSamw 		switch (type) {
749da6c28aaSamw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
750da6c28aaSamw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
751da6c28aaSamw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
752da6c28aaSamw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
753da6c28aaSamw 			if (filter) {
754da6c28aaSamw 				continue;
755da6c28aaSamw 			}
756da6c28aaSamw 			zobjacep = (zfs_object_ace_t *)zacep;
757da6c28aaSamw 			objacep = (ace_object_t *)acep;
758da6c28aaSamw 			bcopy(zobjacep->z_object_type,
759da6c28aaSamw 			    objacep->a_obj_type,
760da6c28aaSamw 			    sizeof (zobjacep->z_object_type));
761da6c28aaSamw 			bcopy(zobjacep->z_inherit_type,
762da6c28aaSamw 			    objacep->a_inherit_obj_type,
763da6c28aaSamw 			    sizeof (zobjacep->z_inherit_type));
764da6c28aaSamw 			ace_size = sizeof (ace_object_t);
765da6c28aaSamw 			break;
766da6c28aaSamw 		default:
767da6c28aaSamw 			ace_size = sizeof (ace_t);
768da6c28aaSamw 			break;
769da6c28aaSamw 		}
770da6c28aaSamw 
771da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
772da6c28aaSamw 		if ((entry_type != ACE_OWNER &&
7731ab99678SMark Shellenbaum 		    entry_type != OWNING_GROUP &&
774e0d35c44Smarks 		    entry_type != ACE_EVERYONE)) {
775e0d35c44Smarks 			acep->a_who = zfs_fuid_map_id(zfsvfs, who,
776e0d35c44Smarks 			    cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
777e0d35c44Smarks 			    ZFS_ACE_GROUP : ZFS_ACE_USER);
778e0d35c44Smarks 		} else {
779da6c28aaSamw 			acep->a_who = (uid_t)(int64_t)who;
780e0d35c44Smarks 		}
781da6c28aaSamw 		acep->a_access_mask = access_mask;
782da6c28aaSamw 		acep->a_flags = iflags;
783da6c28aaSamw 		acep->a_type = type;
784da6c28aaSamw 		acep = (ace_t *)((caddr_t)acep + ace_size);
785da6c28aaSamw 	}
786da6c28aaSamw }
787da6c28aaSamw 
788da6c28aaSamw static int
zfs_copy_ace_2_oldace(vtype_t obj_type,zfs_acl_t * aclp,ace_t * acep,zfs_oldace_t * z_acl,int aclcnt,size_t * size)789da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
790da6c28aaSamw     zfs_oldace_t *z_acl, int aclcnt, size_t *size)
791da6c28aaSamw {
792da6c28aaSamw 	int i;
793da6c28aaSamw 	zfs_oldace_t *aceptr = z_acl;
794da6c28aaSamw 
795da6c28aaSamw 	for (i = 0; i != aclcnt; i++, aceptr++) {
796da6c28aaSamw 		aceptr->z_access_mask = acep[i].a_access_mask;
797da6c28aaSamw 		aceptr->z_type = acep[i].a_type;
798da6c28aaSamw 		aceptr->z_flags = acep[i].a_flags;
799da6c28aaSamw 		aceptr->z_fuid = acep[i].a_who;
800da6c28aaSamw 		/*
801da6c28aaSamw 		 * Make sure ACE is valid
802da6c28aaSamw 		 */
803da6c28aaSamw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
804da6c28aaSamw 		    aceptr->z_flags) != B_TRUE)
805be6fd75aSMatthew Ahrens 			return (SET_ERROR(EINVAL));
806da6c28aaSamw 	}
807da6c28aaSamw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
808da6c28aaSamw 	return (0);
809da6c28aaSamw }
810da6c28aaSamw 
811da6c28aaSamw /*
812da6c28aaSamw  * convert old ACL format to new
813da6c28aaSamw  */
814da6c28aaSamw void
zfs_acl_xform(znode_t * zp,zfs_acl_t * aclp,cred_t * cr)81589459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
816da6c28aaSamw {
817da6c28aaSamw 	zfs_oldace_t *oldaclp;
818da6c28aaSamw 	int i;
819da6c28aaSamw 	uint16_t type, iflags;
820da6c28aaSamw 	uint32_t access_mask;
821da6c28aaSamw 	uint64_t who;
822da6c28aaSamw 	void *cookie = NULL;
8232459a9eaSmarks 	zfs_acl_node_t *newaclnode;
824*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
825da6c28aaSamw 
826da6c28aaSamw 	ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
827da6c28aaSamw 	/*
828da6c28aaSamw 	 * First create the ACE in a contiguous piece of memory
829da6c28aaSamw 	 * for zfs_copy_ace_2_fuid().
830da6c28aaSamw 	 *
831da6c28aaSamw 	 * We only convert an ACL once, so this won't happen
832da6c28aaSamw 	 * everytime.
833da6c28aaSamw 	 */
834da6c28aaSamw 	oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
835da6c28aaSamw 	    KM_SLEEP);
836da6c28aaSamw 	i = 0;
837*06799660SGordon Ross 
838*06799660SGordon Ross 	zai.zai_aclp = aclp;
839*06799660SGordon Ross 	while (cookie = zfs_acl_next_ace(&zai, cookie, &who,
840da6c28aaSamw 	    &access_mask, &iflags, &type)) {
841da6c28aaSamw 		oldaclp[i].z_flags = iflags;
842da6c28aaSamw 		oldaclp[i].z_type = type;
843da6c28aaSamw 		oldaclp[i].z_fuid = who;
844da6c28aaSamw 		oldaclp[i++].z_access_mask = access_mask;
845da6c28aaSamw 	}
846da6c28aaSamw 
847da6c28aaSamw 	newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
848da6c28aaSamw 	    sizeof (zfs_object_ace_t));
849da6c28aaSamw 	aclp->z_ops = zfs_acl_fuid_ops;
85089459e17SMark Shellenbaum 	VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp,
85189459e17SMark Shellenbaum 	    oldaclp, newaclnode->z_acldata, aclp->z_acl_count,
85289459e17SMark Shellenbaum 	    &newaclnode->z_size, NULL, cr) == 0);
853da6c28aaSamw 	newaclnode->z_ace_count = aclp->z_acl_count;
854da6c28aaSamw 	aclp->z_version = ZFS_ACL_VERSION;
855da6c28aaSamw 	kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
856da6c28aaSamw 
857da6c28aaSamw 	/*
858da6c28aaSamw 	 * Release all previous ACL nodes
859da6c28aaSamw 	 */
860da6c28aaSamw 
8612459a9eaSmarks 	zfs_acl_release_nodes(aclp);
8622459a9eaSmarks 
863da6c28aaSamw 	list_insert_head(&aclp->z_acl, newaclnode);
8642459a9eaSmarks 
8652459a9eaSmarks 	aclp->z_acl_bytes = newaclnode->z_size;
8662459a9eaSmarks 	aclp->z_acl_count = newaclnode->z_ace_count;
8672459a9eaSmarks 
868fa9e4066Sahrens }
869fa9e4066Sahrens 
870fa9e4066Sahrens /*
871fa9e4066Sahrens  * Convert unix access mask to v4 access mask
872fa9e4066Sahrens  */
873fa9e4066Sahrens static uint32_t
zfs_unix_to_v4(uint32_t access_mask)874fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask)
875fa9e4066Sahrens {
876fa9e4066Sahrens 	uint32_t new_mask = 0;
877fa9e4066Sahrens 
878da6c28aaSamw 	if (access_mask & S_IXOTH)
879da6c28aaSamw 		new_mask |= ACE_EXECUTE;
880da6c28aaSamw 	if (access_mask & S_IWOTH)
881da6c28aaSamw 		new_mask |= ACE_WRITE_DATA;
882da6c28aaSamw 	if (access_mask & S_IROTH)
883fa9e4066Sahrens 		new_mask |= ACE_READ_DATA;
884fa9e4066Sahrens 	return (new_mask);
885fa9e4066Sahrens }
886fa9e4066Sahrens 
887fa9e4066Sahrens static void
zfs_set_ace(zfs_acl_t * aclp,void * acep,uint32_t access_mask,uint16_t access_type,uint64_t fuid,uint16_t entry_type)888da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
889da6c28aaSamw     uint16_t access_type, uint64_t fuid, uint16_t entry_type)
890fa9e4066Sahrens {
891da6c28aaSamw 	uint16_t type = entry_type & ACE_TYPE_FLAGS;
892da6c28aaSamw 
893da6c28aaSamw 	aclp->z_ops.ace_mask_set(acep, access_mask);
894da6c28aaSamw 	aclp->z_ops.ace_type_set(acep, access_type);
895da6c28aaSamw 	aclp->z_ops.ace_flags_set(acep, entry_type);
8961ab99678SMark Shellenbaum 	if ((type != ACE_OWNER && type != OWNING_GROUP &&
897da6c28aaSamw 	    type != ACE_EVERYONE))
898da6c28aaSamw 		aclp->z_ops.ace_who_set(acep, fuid);
899fa9e4066Sahrens }
900fa9e4066Sahrens 
901da6c28aaSamw /*
902da6c28aaSamw  * Determine mode of file based on ACL.
903da6c28aaSamw  */
9040a586ceaSMark Shellenbaum uint64_t
zfs_mode_compute(uint64_t fmode,zfs_acl_t * aclp,uint64_t * pflags,uint64_t fuid,uint64_t fgid)90527dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
90627dd1e87SMark Shellenbaum     uint64_t *pflags, uint64_t fuid, uint64_t fgid)
907fa9e4066Sahrens {
908da6c28aaSamw 	int		entry_type;
909da6c28aaSamw 	mode_t		mode;
910da6c28aaSamw 	mode_t		seen = 0;
91154811da5SToomas Soome 	zfs_ace_hdr_t	*acep = NULL;
912da6c28aaSamw 	uint64_t	who;
913da6c28aaSamw 	uint16_t	iflags, type;
914da6c28aaSamw 	uint32_t	access_mask;
915d47621a4STim Haley 	boolean_t	an_exec_denied = B_FALSE;
916*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
917da6c28aaSamw 
9180a586ceaSMark Shellenbaum 	mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
919fa9e4066Sahrens 
920*06799660SGordon Ross 	zai.zai_aclp = aclp;
921*06799660SGordon Ross 	while (acep = zfs_acl_next_ace(&zai, acep, &who,
922da6c28aaSamw 	    &access_mask, &iflags, &type)) {
92329a0b737Smarks 
924003c2582SMark Shellenbaum 		if (!zfs_acl_valid_ace_type(type, iflags))
925003c2582SMark Shellenbaum 			continue;
926003c2582SMark Shellenbaum 
9271ab99678SMark Shellenbaum 		entry_type = (iflags & ACE_TYPE_FLAGS);
9281ab99678SMark Shellenbaum 
92929a0b737Smarks 		/*
930de0f1ddbSAlbert Lee 		 * Skip over any inherit_only ACEs
93129a0b737Smarks 		 */
932de0f1ddbSAlbert Lee 		if (iflags & ACE_INHERIT_ONLY_ACE)
93329a0b737Smarks 			continue;
93429a0b737Smarks 
93527dd1e87SMark Shellenbaum 		if (entry_type == ACE_OWNER || (entry_type == 0 &&
93627dd1e87SMark Shellenbaum 		    who == fuid)) {
937da6c28aaSamw 			if ((access_mask & ACE_READ_DATA) &&
938fa9e4066Sahrens 			    (!(seen & S_IRUSR))) {
939fa9e4066Sahrens 				seen |= S_IRUSR;
940da6c28aaSamw 				if (type == ALLOW) {
941fa9e4066Sahrens 					mode |= S_IRUSR;
942fa9e4066Sahrens 				}
943fa9e4066Sahrens 			}
944da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA) &&
945fa9e4066Sahrens 			    (!(seen & S_IWUSR))) {
946fa9e4066Sahrens 				seen |= S_IWUSR;
947da6c28aaSamw 				if (type == ALLOW) {
948fa9e4066Sahrens 					mode |= S_IWUSR;
949fa9e4066Sahrens 				}
950fa9e4066Sahrens 			}
951da6c28aaSamw 			if ((access_mask & ACE_EXECUTE) &&
952fa9e4066Sahrens 			    (!(seen & S_IXUSR))) {
953fa9e4066Sahrens 				seen |= S_IXUSR;
954da6c28aaSamw 				if (type == ALLOW) {
955fa9e4066Sahrens 					mode |= S_IXUSR;
956fa9e4066Sahrens 				}
957fa9e4066Sahrens 			}
95827dd1e87SMark Shellenbaum 		} else if (entry_type == OWNING_GROUP ||
95927dd1e87SMark Shellenbaum 		    (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) {
960da6c28aaSamw 			if ((access_mask & ACE_READ_DATA) &&
961fa9e4066Sahrens 			    (!(seen & S_IRGRP))) {
962fa9e4066Sahrens 				seen |= S_IRGRP;
963da6c28aaSamw 				if (type == ALLOW) {
964fa9e4066Sahrens 					mode |= S_IRGRP;
965fa9e4066Sahrens 				}
966fa9e4066Sahrens 			}
967da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA) &&
968fa9e4066Sahrens 			    (!(seen & S_IWGRP))) {
969fa9e4066Sahrens 				seen |= S_IWGRP;
970da6c28aaSamw 				if (type == ALLOW) {
971fa9e4066Sahrens 					mode |= S_IWGRP;
972fa9e4066Sahrens 				}
973fa9e4066Sahrens 			}
974da6c28aaSamw 			if ((access_mask & ACE_EXECUTE) &&
975fa9e4066Sahrens 			    (!(seen & S_IXGRP))) {
976fa9e4066Sahrens 				seen |= S_IXGRP;
977da6c28aaSamw 				if (type == ALLOW) {
978fa9e4066Sahrens 					mode |= S_IXGRP;
979fa9e4066Sahrens 				}
980fa9e4066Sahrens 			}
981fa9e4066Sahrens 		} else if (entry_type == ACE_EVERYONE) {
982da6c28aaSamw 			if ((access_mask & ACE_READ_DATA)) {
983fa9e4066Sahrens 				if (!(seen & S_IRUSR)) {
984fa9e4066Sahrens 					seen |= S_IRUSR;
985da6c28aaSamw 					if (type == ALLOW) {
986fa9e4066Sahrens 						mode |= S_IRUSR;
987fa9e4066Sahrens 					}
988fa9e4066Sahrens 				}
989fa9e4066Sahrens 				if (!(seen & S_IRGRP)) {
990fa9e4066Sahrens 					seen |= S_IRGRP;
991da6c28aaSamw 					if (type == ALLOW) {
992fa9e4066Sahrens 						mode |= S_IRGRP;
993fa9e4066Sahrens 					}
994fa9e4066Sahrens 				}
995fa9e4066Sahrens 				if (!(seen & S_IROTH)) {
996fa9e4066Sahrens 					seen |= S_IROTH;
997da6c28aaSamw 					if (type == ALLOW) {
998fa9e4066Sahrens 						mode |= S_IROTH;
999fa9e4066Sahrens 					}
1000fa9e4066Sahrens 				}
1001fa9e4066Sahrens 			}
1002da6c28aaSamw 			if ((access_mask & ACE_WRITE_DATA)) {
1003fa9e4066Sahrens 				if (!(seen & S_IWUSR)) {
1004fa9e4066Sahrens 					seen |= S_IWUSR;
1005da6c28aaSamw 					if (type == ALLOW) {
1006fa9e4066Sahrens 						mode |= S_IWUSR;
1007fa9e4066Sahrens 					}
1008fa9e4066Sahrens 				}
1009fa9e4066Sahrens 				if (!(seen & S_IWGRP)) {
1010fa9e4066Sahrens 					seen |= S_IWGRP;
1011da6c28aaSamw 					if (type == ALLOW) {
1012fa9e4066Sahrens 						mode |= S_IWGRP;
1013fa9e4066Sahrens 					}
1014fa9e4066Sahrens 				}
1015fa9e4066Sahrens 				if (!(seen & S_IWOTH)) {
1016fa9e4066Sahrens 					seen |= S_IWOTH;
1017da6c28aaSamw 					if (type == ALLOW) {
1018fa9e4066Sahrens 						mode |= S_IWOTH;
1019fa9e4066Sahrens 					}
1020fa9e4066Sahrens 				}
1021fa9e4066Sahrens 			}
1022da6c28aaSamw 			if ((access_mask & ACE_EXECUTE)) {
1023fa9e4066Sahrens 				if (!(seen & S_IXUSR)) {
1024fa9e4066Sahrens 					seen |= S_IXUSR;
1025da6c28aaSamw 					if (type == ALLOW) {
1026fa9e4066Sahrens 						mode |= S_IXUSR;
1027fa9e4066Sahrens 					}
1028fa9e4066Sahrens 				}
1029fa9e4066Sahrens 				if (!(seen & S_IXGRP)) {
1030fa9e4066Sahrens 					seen |= S_IXGRP;
1031da6c28aaSamw 					if (type == ALLOW) {
1032fa9e4066Sahrens 						mode |= S_IXGRP;
1033fa9e4066Sahrens 					}
1034fa9e4066Sahrens 				}
1035fa9e4066Sahrens 				if (!(seen & S_IXOTH)) {
1036fa9e4066Sahrens 					seen |= S_IXOTH;
1037da6c28aaSamw 					if (type == ALLOW) {
1038fa9e4066Sahrens 						mode |= S_IXOTH;
1039fa9e4066Sahrens 					}
1040fa9e4066Sahrens 				}
1041fa9e4066Sahrens 			}
1042d47621a4STim Haley 		} else {
1043d47621a4STim Haley 			/*
1044d47621a4STim Haley 			 * Only care if this IDENTIFIER_GROUP or
1045d47621a4STim Haley 			 * USER ACE denies execute access to someone,
1046d47621a4STim Haley 			 * mode is not affected
1047d47621a4STim Haley 			 */
1048d47621a4STim Haley 			if ((access_mask & ACE_EXECUTE) && type == DENY)
1049d47621a4STim Haley 				an_exec_denied = B_TRUE;
1050fa9e4066Sahrens 		}
1051fa9e4066Sahrens 	}
1052d47621a4STim Haley 
10534929fd5eSTim Haley 	/*
10544929fd5eSTim Haley 	 * Failure to allow is effectively a deny, so execute permission
10554929fd5eSTim Haley 	 * is denied if it was never mentioned or if we explicitly
10564929fd5eSTim Haley 	 * weren't allowed it.
10574929fd5eSTim Haley 	 */
10584929fd5eSTim Haley 	if (!an_exec_denied &&
10594929fd5eSTim Haley 	    ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS ||
10604929fd5eSTim Haley 	    (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS))
1061d47621a4STim Haley 		an_exec_denied = B_TRUE;
1062d47621a4STim Haley 
1063d47621a4STim Haley 	if (an_exec_denied)
10640a586ceaSMark Shellenbaum 		*pflags &= ~ZFS_NO_EXECS_DENIED;
1065d47621a4STim Haley 	else
10660a586ceaSMark Shellenbaum 		*pflags |= ZFS_NO_EXECS_DENIED;
1067d47621a4STim Haley 
1068fa9e4066Sahrens 	return (mode);
1069fa9e4066Sahrens }
1070fa9e4066Sahrens 
1071fa9e4066Sahrens /*
10724929fd5eSTim Haley  * Read an external acl object.  If the intent is to modify, always
10734929fd5eSTim Haley  * create a new acl and leave any cached acl in place.
1074fa9e4066Sahrens  */
1075f67950b2SNasf-Fan int
zfs_acl_node_read(struct znode * zp,boolean_t have_lock,zfs_acl_t ** aclpp,boolean_t will_modify)1076f67950b2SNasf-Fan zfs_acl_node_read(struct znode *zp, boolean_t have_lock, zfs_acl_t **aclpp,
10771412a1a2SMark Shellenbaum     boolean_t will_modify)
1078fa9e4066Sahrens {
1079fa9e4066Sahrens 	zfs_acl_t	*aclp;
10800a586ceaSMark Shellenbaum 	int		aclsize;
10810a586ceaSMark Shellenbaum 	int		acl_count;
1082da6c28aaSamw 	zfs_acl_node_t	*aclnode;
10830a586ceaSMark Shellenbaum 	zfs_acl_phys_t	znode_acl;
10840a586ceaSMark Shellenbaum 	int		version;
10850a586ceaSMark Shellenbaum 	int		error;
10861412a1a2SMark Shellenbaum 	boolean_t	drop_lock = B_FALSE;
1087fa9e4066Sahrens 
1088*06799660SGordon Ross 	ASSERT(RW_ISWRITER(&zp->z_acl_lock));
1089fa9e4066Sahrens 
10904929fd5eSTim Haley 	if (zp->z_acl_cached && !will_modify) {
1091d47621a4STim Haley 		*aclpp = zp->z_acl_cached;
1092d47621a4STim Haley 		return (0);
1093d47621a4STim Haley 	}
1094d47621a4STim Haley 
10951412a1a2SMark Shellenbaum 	/*
10961412a1a2SMark Shellenbaum 	 * close race where znode could be upgrade while trying to
10971412a1a2SMark Shellenbaum 	 * read the znode attributes.
10981412a1a2SMark Shellenbaum 	 *
10991412a1a2SMark Shellenbaum 	 * But this could only happen if the file isn't already an SA
11001412a1a2SMark Shellenbaum 	 * znode
11011412a1a2SMark Shellenbaum 	 */
11021412a1a2SMark Shellenbaum 	if (!zp->z_is_sa && !have_lock) {
11031412a1a2SMark Shellenbaum 		mutex_enter(&zp->z_lock);
11041412a1a2SMark Shellenbaum 		drop_lock = B_TRUE;
11051412a1a2SMark Shellenbaum 	}
11061412a1a2SMark Shellenbaum 	version = zfs_znode_acl_version(zp);
1107fa9e4066Sahrens 
11080a586ceaSMark Shellenbaum 	if ((error = zfs_acl_znode_info(zp, &aclsize,
11091412a1a2SMark Shellenbaum 	    &acl_count, &znode_acl)) != 0) {
11101412a1a2SMark Shellenbaum 		goto done;
11111412a1a2SMark Shellenbaum 	}
11120a586ceaSMark Shellenbaum 
11130a586ceaSMark Shellenbaum 	aclp = zfs_acl_alloc(version);
1114fa9e4066Sahrens 
1115da6c28aaSamw 	aclp->z_acl_count = acl_count;
1116da6c28aaSamw 	aclp->z_acl_bytes = aclsize;
1117da6c28aaSamw 
11180a586ceaSMark Shellenbaum 	aclnode = zfs_acl_node_alloc(aclsize);
11190a586ceaSMark Shellenbaum 	aclnode->z_ace_count = aclp->z_acl_count;
11200a586ceaSMark Shellenbaum 	aclnode->z_size = aclsize;
11210a586ceaSMark Shellenbaum 
11220a586ceaSMark Shellenbaum 	if (!zp->z_is_sa) {
11230a586ceaSMark Shellenbaum 		if (znode_acl.z_acl_extern_obj) {
11240a586ceaSMark Shellenbaum 			error = dmu_read(zp->z_zfsvfs->z_os,
11250a586ceaSMark Shellenbaum 			    znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
11260a586ceaSMark Shellenbaum 			    aclnode->z_acldata, DMU_READ_PREFETCH);
11270a586ceaSMark Shellenbaum 		} else {
11280a586ceaSMark Shellenbaum 			bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
11290a586ceaSMark Shellenbaum 			    aclnode->z_size);
11300a586ceaSMark Shellenbaum 		}
11310a586ceaSMark Shellenbaum 	} else {
11320a586ceaSMark Shellenbaum 		error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs),
11330a586ceaSMark Shellenbaum 		    aclnode->z_acldata, aclnode->z_size);
11340a586ceaSMark Shellenbaum 	}
11350a586ceaSMark Shellenbaum 
1136ea8dc4b6Seschrock 	if (error != 0) {
1137ea8dc4b6Seschrock 		zfs_acl_free(aclp);
11380a586ceaSMark Shellenbaum 		zfs_acl_node_free(aclnode);
1139b87f3af3Sperrin 		/* convert checksum errors into IO errors */
1140b87f3af3Sperrin 		if (error == ECKSUM)
1141be6fd75aSMatthew Ahrens 			error = SET_ERROR(EIO);
11421412a1a2SMark Shellenbaum 		goto done;
1143ea8dc4b6Seschrock 	}
1144fa9e4066Sahrens 
11450a586ceaSMark Shellenbaum 	list_insert_head(&aclp->z_acl, aclnode);
11460a586ceaSMark Shellenbaum 
11474929fd5eSTim Haley 	*aclpp = aclp;
11484929fd5eSTim Haley 	if (!will_modify)
11494929fd5eSTim Haley 		zp->z_acl_cached = aclp;
11501412a1a2SMark Shellenbaum done:
11511412a1a2SMark Shellenbaum 	if (drop_lock)
11521412a1a2SMark Shellenbaum 		mutex_exit(&zp->z_lock);
11531412a1a2SMark Shellenbaum 	return (error);
1154fa9e4066Sahrens }
1155fa9e4066Sahrens 
11560a586ceaSMark Shellenbaum /*ARGSUSED*/
11570a586ceaSMark Shellenbaum void
zfs_acl_data_locator(void ** dataptr,uint32_t * length,uint32_t buflen,boolean_t start,void * userdata)11580a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
11590a586ceaSMark Shellenbaum     boolean_t start, void *userdata)
11600a586ceaSMark Shellenbaum {
11610a586ceaSMark Shellenbaum 	zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
11620a586ceaSMark Shellenbaum 
11630a586ceaSMark Shellenbaum 	if (start) {
11640a586ceaSMark Shellenbaum 		cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl);
11650a586ceaSMark Shellenbaum 	} else {
11660a586ceaSMark Shellenbaum 		cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
11670a586ceaSMark Shellenbaum 		    cb->cb_acl_node);
11680a586ceaSMark Shellenbaum 	}
11690a586ceaSMark Shellenbaum 	*dataptr = cb->cb_acl_node->z_acldata;
11700a586ceaSMark Shellenbaum 	*length = cb->cb_acl_node->z_size;
11710a586ceaSMark Shellenbaum }
11720a586ceaSMark Shellenbaum 
117327dd1e87SMark Shellenbaum int
zfs_acl_chown_setattr(znode_t * zp)117427dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp)
117527dd1e87SMark Shellenbaum {
117627dd1e87SMark Shellenbaum 	int error;
117727dd1e87SMark Shellenbaum 	zfs_acl_t *aclp;
117827dd1e87SMark Shellenbaum 
11791412a1a2SMark Shellenbaum 	ASSERT(MUTEX_HELD(&zp->z_lock));
1180*06799660SGordon Ross 	ASSERT(RW_ISWRITER(&zp->z_acl_lock));
118127dd1e87SMark Shellenbaum 
11821412a1a2SMark Shellenbaum 	if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0)
118327dd1e87SMark Shellenbaum 		zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
1184f1696b23SMark Shellenbaum 		    &zp->z_pflags, zp->z_uid, zp->z_gid);
118527dd1e87SMark Shellenbaum 	return (error);
118627dd1e87SMark Shellenbaum }
118727dd1e87SMark Shellenbaum 
1188fa9e4066Sahrens /*
1189da6c28aaSamw  * common code for setting ACLs.
1190fa9e4066Sahrens  *
1191fa9e4066Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
1192fa9e4066Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
1193fa9e4066Sahrens  * already checked the acl and knows whether to inherit.
1194fa9e4066Sahrens  */
1195fa9e4066Sahrens int
zfs_aclset_common(znode_t * zp,zfs_acl_t * aclp,cred_t * cr,dmu_tx_t * tx)119689459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
1197fa9e4066Sahrens {
11980a586ceaSMark Shellenbaum 	int			error;
11990a586ceaSMark Shellenbaum 	zfsvfs_t		*zfsvfs = zp->z_zfsvfs;
12000a586ceaSMark Shellenbaum 	dmu_object_type_t	otype;
12010a586ceaSMark Shellenbaum 	zfs_acl_locator_cb_t	locate = { 0 };
12020a586ceaSMark Shellenbaum 	uint64_t		mode;
12030a586ceaSMark Shellenbaum 	sa_bulk_attr_t		bulk[5];
12040a586ceaSMark Shellenbaum 	uint64_t		ctime[2];
12050a586ceaSMark Shellenbaum 	int			count = 0;
120682693e09SWHR 	zfs_acl_phys_t		acl_phys;
1207*06799660SGordon Ross 	zfs_acl_iter_t		zai = {0};
1208*06799660SGordon Ross 
1209*06799660SGordon Ross 	/*
1210*06799660SGordon Ross 	 * One might be tempted to add here:
1211*06799660SGordon Ross 	 * ASSERT(RW_ISWRITER(&zp->z_acl_lock));
1212*06799660SGordon Ross 	 * and most callers have that lock, but zfs_mknode
1213*06799660SGordon Ross 	 * calls without the lock when making a new node,
1214*06799660SGordon Ross 	 * which is OK because it's not visible yet.
1215*06799660SGordon Ross 	 */
12160a586ceaSMark Shellenbaum 
12170a586ceaSMark Shellenbaum 	mode = zp->z_mode;
121827dd1e87SMark Shellenbaum 
1219f1696b23SMark Shellenbaum 	mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
1220f1696b23SMark Shellenbaum 	    zp->z_uid, zp->z_gid);
12210a586ceaSMark Shellenbaum 
12220a586ceaSMark Shellenbaum 	zp->z_mode = mode;
12230a586ceaSMark Shellenbaum 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
12240a586ceaSMark Shellenbaum 	    &mode, sizeof (mode));
12250a586ceaSMark Shellenbaum 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
12260a586ceaSMark Shellenbaum 	    &zp->z_pflags, sizeof (zp->z_pflags));
12270a586ceaSMark Shellenbaum 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
12280a586ceaSMark Shellenbaum 	    &ctime, sizeof (ctime));
1229fa9e4066Sahrens 
12304929fd5eSTim Haley 	if (zp->z_acl_cached) {
1231d47621a4STim Haley 		zfs_acl_free(zp->z_acl_cached);
1232d47621a4STim Haley 		zp->z_acl_cached = NULL;
1233d47621a4STim Haley 	}
1234d47621a4STim Haley 
1235fa9e4066Sahrens 	/*
12360a586ceaSMark Shellenbaum 	 * Upgrade needed?
1237fa9e4066Sahrens 	 */
1238da6c28aaSamw 	if (!zfsvfs->z_use_fuids) {
1239da6c28aaSamw 		otype = DMU_OT_OLDACL;
1240da6c28aaSamw 	} else {
1241da6c28aaSamw 		if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
1242da6c28aaSamw 		    (zfsvfs->z_version >= ZPL_VERSION_FUID))
124389459e17SMark Shellenbaum 			zfs_acl_xform(zp, aclp, cr);
1244da6c28aaSamw 		ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
1245da6c28aaSamw 		otype = DMU_OT_ACL;
1246da6c28aaSamw 	}
1247da6c28aaSamw 
12480a586ceaSMark Shellenbaum 	/*
12490a586ceaSMark Shellenbaum 	 * Arrgh, we have to handle old on disk format
12500a586ceaSMark Shellenbaum 	 * as well as newer (preferred) SA format.
12510a586ceaSMark Shellenbaum 	 */
12520a586ceaSMark Shellenbaum 
12530a586ceaSMark Shellenbaum 	if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */
12540a586ceaSMark Shellenbaum 		locate.cb_aclp = aclp;
12550a586ceaSMark Shellenbaum 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs),
12560a586ceaSMark Shellenbaum 		    zfs_acl_data_locator, &locate, aclp->z_acl_bytes);
12570a586ceaSMark Shellenbaum 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs),
12580a586ceaSMark Shellenbaum 		    NULL, &aclp->z_acl_count, sizeof (uint64_t));
12590a586ceaSMark Shellenbaum 	} else { /* Painful legacy way */
12600a586ceaSMark Shellenbaum 		zfs_acl_node_t *aclnode;
12610a586ceaSMark Shellenbaum 		uint64_t off = 0;
12620a586ceaSMark Shellenbaum 		uint64_t aoid;
12630a586ceaSMark Shellenbaum 
12640a586ceaSMark Shellenbaum 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
12650a586ceaSMark Shellenbaum 		    &acl_phys, sizeof (acl_phys))) != 0)
12660a586ceaSMark Shellenbaum 			return (error);
12670a586ceaSMark Shellenbaum 
12680a586ceaSMark Shellenbaum 		aoid = acl_phys.z_acl_extern_obj;
12690a586ceaSMark Shellenbaum 
12700a586ceaSMark Shellenbaum 		if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
12710a586ceaSMark Shellenbaum 			/*
12720a586ceaSMark Shellenbaum 			 * If ACL was previously external and we are now
12730a586ceaSMark Shellenbaum 			 * converting to new ACL format then release old
12740a586ceaSMark Shellenbaum 			 * ACL object and create a new one.
12750a586ceaSMark Shellenbaum 			 */
12760a586ceaSMark Shellenbaum 			if (aoid &&
12770a586ceaSMark Shellenbaum 			    aclp->z_version != acl_phys.z_acl_version) {
12780a586ceaSMark Shellenbaum 				error = dmu_object_free(zfsvfs->z_os, aoid, tx);
12790a586ceaSMark Shellenbaum 				if (error)
12800a586ceaSMark Shellenbaum 					return (error);
12810a586ceaSMark Shellenbaum 				aoid = 0;
12820a586ceaSMark Shellenbaum 			}
12830a586ceaSMark Shellenbaum 			if (aoid == 0) {
12840a586ceaSMark Shellenbaum 				aoid = dmu_object_alloc(zfsvfs->z_os,
12850a586ceaSMark Shellenbaum 				    otype, aclp->z_acl_bytes,
12860a586ceaSMark Shellenbaum 				    otype == DMU_OT_ACL ?
12870a586ceaSMark Shellenbaum 				    DMU_OT_SYSACL : DMU_OT_NONE,
12880a586ceaSMark Shellenbaum 				    otype == DMU_OT_ACL ?
128954811da5SToomas Soome 				    DN_OLD_MAX_BONUSLEN : 0, tx);
12900a586ceaSMark Shellenbaum 			} else {
12910a586ceaSMark Shellenbaum 				(void) dmu_object_set_blocksize(zfsvfs->z_os,
12920a586ceaSMark Shellenbaum 				    aoid, aclp->z_acl_bytes, 0, tx);
12930a586ceaSMark Shellenbaum 			}
12940a586ceaSMark Shellenbaum 			acl_phys.z_acl_extern_obj = aoid;
12950a586ceaSMark Shellenbaum 			for (aclnode = list_head(&aclp->z_acl); aclnode;
12960a586ceaSMark Shellenbaum 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
12970a586ceaSMark Shellenbaum 				if (aclnode->z_ace_count == 0)
12980a586ceaSMark Shellenbaum 					continue;
12990a586ceaSMark Shellenbaum 				dmu_write(zfsvfs->z_os, aoid, off,
13000a586ceaSMark Shellenbaum 				    aclnode->z_size, aclnode->z_acldata, tx);
13010a586ceaSMark Shellenbaum 				off += aclnode->z_size;
13020a586ceaSMark Shellenbaum 			}
1303fa9e4066Sahrens 		} else {
13040a586ceaSMark Shellenbaum 			void *start = acl_phys.z_ace_data;
13050a586ceaSMark Shellenbaum 			/*
13060a586ceaSMark Shellenbaum 			 * Migrating back embedded?
13070a586ceaSMark Shellenbaum 			 */
13080a586ceaSMark Shellenbaum 			if (acl_phys.z_acl_extern_obj) {
13090a586ceaSMark Shellenbaum 				error = dmu_object_free(zfsvfs->z_os,
13100a586ceaSMark Shellenbaum 				    acl_phys.z_acl_extern_obj, tx);
13110a586ceaSMark Shellenbaum 				if (error)
13120a586ceaSMark Shellenbaum 					return (error);
13130a586ceaSMark Shellenbaum 				acl_phys.z_acl_extern_obj = 0;
13140a586ceaSMark Shellenbaum 			}
13150a586ceaSMark Shellenbaum 
13160a586ceaSMark Shellenbaum 			for (aclnode = list_head(&aclp->z_acl); aclnode;
13170a586ceaSMark Shellenbaum 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
13180a586ceaSMark Shellenbaum 				if (aclnode->z_ace_count == 0)
13190a586ceaSMark Shellenbaum 					continue;
13200a586ceaSMark Shellenbaum 				bcopy(aclnode->z_acldata, start,
13210a586ceaSMark Shellenbaum 				    aclnode->z_size);
13220a586ceaSMark Shellenbaum 				start = (caddr_t)start + aclnode->z_size;
13230a586ceaSMark Shellenbaum 			}
1324da6c28aaSamw 		}
1325fa9e4066Sahrens 		/*
13260a586ceaSMark Shellenbaum 		 * If Old version then swap count/bytes to match old
13270a586ceaSMark Shellenbaum 		 * layout of znode_acl_phys_t.
1328fa9e4066Sahrens 		 */
13290a586ceaSMark Shellenbaum 		if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
13300a586ceaSMark Shellenbaum 			acl_phys.z_acl_size = aclp->z_acl_count;
13310a586ceaSMark Shellenbaum 			acl_phys.z_acl_count = aclp->z_acl_bytes;
13320a586ceaSMark Shellenbaum 		} else {
13330a586ceaSMark Shellenbaum 			acl_phys.z_acl_size = aclp->z_acl_bytes;
13340a586ceaSMark Shellenbaum 			acl_phys.z_acl_count = aclp->z_acl_count;
1335da6c28aaSamw 		}
13360a586ceaSMark Shellenbaum 		acl_phys.z_acl_version = aclp->z_version;
1337de122929Smarks 
13380a586ceaSMark Shellenbaum 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
13390a586ceaSMark Shellenbaum 		    &acl_phys, sizeof (acl_phys));
1340de122929Smarks 	}
1341fa9e4066Sahrens 
1342da6c28aaSamw 	/*
1343da6c28aaSamw 	 * Replace ACL wide bits, but first clear them.
1344da6c28aaSamw 	 */
13450a586ceaSMark Shellenbaum 	zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS;
1346da6c28aaSamw 
13470a586ceaSMark Shellenbaum 	zp->z_pflags |= aclp->z_hints;
1348fa9e4066Sahrens 
1349*06799660SGordon Ross 	zai.zai_aclp = aclp;
1350*06799660SGordon Ross 	if (ace_trivial_common(&zai, 0, zfs_ace_walk) == 0)
13510a586ceaSMark Shellenbaum 		zp->z_pflags |= ZFS_ACL_TRIVIAL;
1352da6c28aaSamw 
13530a586ceaSMark Shellenbaum 	zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE);
13540a586ceaSMark Shellenbaum 	return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
1355fa9e4066Sahrens }
1356fa9e4066Sahrens 
1357fa9e4066Sahrens static void
zfs_acl_chmod(vtype_t vtype,uint64_t mode,boolean_t split,boolean_t trim,zfs_acl_t * aclp)1358de0f1ddbSAlbert Lee zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t split, boolean_t trim,
1359de0f1ddbSAlbert Lee     zfs_acl_t *aclp)
1360fa9e4066Sahrens {
136127dd1e87SMark Shellenbaum 	void		*acep = NULL;
1362da6c28aaSamw 	uint64_t	who;
136327dd1e87SMark Shellenbaum 	int		new_count, new_bytes;
136427dd1e87SMark Shellenbaum 	int		ace_size;
136554811da5SToomas Soome 	int		entry_type;
1366da6c28aaSamw 	uint16_t	iflags, type;
1367da6c28aaSamw 	uint32_t	access_mask;
136827dd1e87SMark Shellenbaum 	zfs_acl_node_t	*newnode;
136954811da5SToomas Soome 	size_t		abstract_size = aclp->z_ops.ace_abstract_size();
137054811da5SToomas Soome 	void		*zacep;
1371a3c49ce1SAlbert Lee 	boolean_t	isdir;
1372a3c49ce1SAlbert Lee 	trivial_acl_t	masks;
1373*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
137427dd1e87SMark Shellenbaum 
137527dd1e87SMark Shellenbaum 	new_count = new_bytes = 0;
137627dd1e87SMark Shellenbaum 
1377a3c49ce1SAlbert Lee 	isdir = (vtype == VDIR);
1378a3c49ce1SAlbert Lee 
1379a3c49ce1SAlbert Lee 	acl_trivial_access_masks((mode_t)mode, isdir, &masks);
138027dd1e87SMark Shellenbaum 
138127dd1e87SMark Shellenbaum 	newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
138227dd1e87SMark Shellenbaum 
138327dd1e87SMark Shellenbaum 	zacep = newnode->z_acldata;
1384a3c49ce1SAlbert Lee 	if (masks.allow0) {
1385a3c49ce1SAlbert Lee 		zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER);
138627dd1e87SMark Shellenbaum 		zacep = (void *)((uintptr_t)zacep + abstract_size);
138727dd1e87SMark Shellenbaum 		new_count++;
138827dd1e87SMark Shellenbaum 		new_bytes += abstract_size;
1389f7170741SWill Andrews 	}
1390f7170741SWill Andrews 	if (masks.deny1) {
1391a3c49ce1SAlbert Lee 		zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER);
139227dd1e87SMark Shellenbaum 		zacep = (void *)((uintptr_t)zacep + abstract_size);
139327dd1e87SMark Shellenbaum 		new_count++;
139427dd1e87SMark Shellenbaum 		new_bytes += abstract_size;
139527dd1e87SMark Shellenbaum 	}
1396a3c49ce1SAlbert Lee 	if (masks.deny2) {
1397a3c49ce1SAlbert Lee 		zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP);
139827dd1e87SMark Shellenbaum 		zacep = (void *)((uintptr_t)zacep + abstract_size);
139927dd1e87SMark Shellenbaum 		new_count++;
140027dd1e87SMark Shellenbaum 		new_bytes += abstract_size;
140127dd1e87SMark Shellenbaum 	}
14022459a9eaSmarks 
1403*06799660SGordon Ross 	zai.zai_aclp = aclp;
1404*06799660SGordon Ross 	while (acep = zfs_acl_next_ace(&zai, acep, &who, &access_mask,
1405da6c28aaSamw 	    &iflags, &type)) {
1406da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
1407de0f1ddbSAlbert Lee 		/*
1408de0f1ddbSAlbert Lee 		 * ACEs used to represent the file mode may be divided
1409de0f1ddbSAlbert Lee 		 * into an equivalent pair of inherit-only and regular
1410de0f1ddbSAlbert Lee 		 * ACEs, if they are inheritable.
1411de0f1ddbSAlbert Lee 		 * Skip regular ACEs, which are replaced by the new mode.
1412de0f1ddbSAlbert Lee 		 */
1413de0f1ddbSAlbert Lee 		if (split && (entry_type == ACE_OWNER ||
1414de0f1ddbSAlbert Lee 		    entry_type == OWNING_GROUP ||
1415de0f1ddbSAlbert Lee 		    entry_type == ACE_EVERYONE)) {
1416de0f1ddbSAlbert Lee 			if (!isdir || !(iflags &
1417de0f1ddbSAlbert Lee 			    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
1418de0f1ddbSAlbert Lee 				continue;
1419de0f1ddbSAlbert Lee 			/*
1420de0f1ddbSAlbert Lee 			 * We preserve owner@, group@, or @everyone
1421de0f1ddbSAlbert Lee 			 * permissions, if they are inheritable, by
1422de0f1ddbSAlbert Lee 			 * copying them to inherit_only ACEs. This
1423de0f1ddbSAlbert Lee 			 * prevents inheritable permissions from being
1424de0f1ddbSAlbert Lee 			 * altered along with the file mode.
1425de0f1ddbSAlbert Lee 			 */
1426de0f1ddbSAlbert Lee 			iflags |= ACE_INHERIT_ONLY_ACE;
142727dd1e87SMark Shellenbaum 		}
1428da6c28aaSamw 
1429a3c49ce1SAlbert Lee 		/*
1430a3c49ce1SAlbert Lee 		 * If this ACL has any inheritable ACEs, mark that in
1431a3c49ce1SAlbert Lee 		 * the hints (which are later masked into the pflags)
1432a3c49ce1SAlbert Lee 		 * so create knows to do inheritance.
1433a3c49ce1SAlbert Lee 		 */
1434de0f1ddbSAlbert Lee 		if (isdir && (iflags &
1435a3c49ce1SAlbert Lee 		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
1436a3c49ce1SAlbert Lee 			aclp->z_hints |= ZFS_INHERIT_ACE;
1437a3c49ce1SAlbert Lee 
1438da6c28aaSamw 		if ((type != ALLOW && type != DENY) ||
1439de0f1ddbSAlbert Lee 		    (iflags & ACE_INHERIT_ONLY_ACE)) {
1440da6c28aaSamw 			switch (type) {
1441da6c28aaSamw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1442da6c28aaSamw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1443da6c28aaSamw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1444da6c28aaSamw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1445da6c28aaSamw 				aclp->z_hints |= ZFS_ACL_OBJ_ACE;
1446da6c28aaSamw 				break;
1447da6c28aaSamw 			}
1448fa9e4066Sahrens 		} else {
144927dd1e87SMark Shellenbaum 			/*
1450851632d6SAlbert Lee 			 * Limit permissions granted by ACEs to be no greater
1451851632d6SAlbert Lee 			 * than permissions of the requested group mode.
1452851632d6SAlbert Lee 			 * Applies when the "aclmode" property is set to
1453851632d6SAlbert Lee 			 * "groupmask".
145427dd1e87SMark Shellenbaum 			 */
1455a3c49ce1SAlbert Lee 			if ((type == ALLOW) && trim)
1456a3c49ce1SAlbert Lee 				access_mask &= masks.group;
1457fa9e4066Sahrens 		}
145827dd1e87SMark Shellenbaum 		zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
145927dd1e87SMark Shellenbaum 		ace_size = aclp->z_ops.ace_size(acep);
146027dd1e87SMark Shellenbaum 		zacep = (void *)((uintptr_t)zacep + ace_size);
146127dd1e87SMark Shellenbaum 		new_count++;
146227dd1e87SMark Shellenbaum 		new_bytes += ace_size;
1463fa9e4066Sahrens 	}
1464de0f1ddbSAlbert Lee 	zfs_set_ace(aclp, zacep, masks.owner, ALLOW, -1, ACE_OWNER);
146527dd1e87SMark Shellenbaum 	zacep = (void *)((uintptr_t)zacep + abstract_size);
1466de0f1ddbSAlbert Lee 	zfs_set_ace(aclp, zacep, masks.group, ALLOW, -1, OWNING_GROUP);
146727dd1e87SMark Shellenbaum 	zacep = (void *)((uintptr_t)zacep + abstract_size);
1468de0f1ddbSAlbert Lee 	zfs_set_ace(aclp, zacep, masks.everyone, ALLOW, -1, ACE_EVERYONE);
146927dd1e87SMark Shellenbaum 
147027dd1e87SMark Shellenbaum 	new_count += 3;
147127dd1e87SMark Shellenbaum 	new_bytes += abstract_size * 3;
147227dd1e87SMark Shellenbaum 	zfs_acl_release_nodes(aclp);
147327dd1e87SMark Shellenbaum 	aclp->z_acl_count = new_count;
147427dd1e87SMark Shellenbaum 	aclp->z_acl_bytes = new_bytes;
147527dd1e87SMark Shellenbaum 	newnode->z_ace_count = new_count;
147627dd1e87SMark Shellenbaum 	newnode->z_size = new_bytes;
147727dd1e87SMark Shellenbaum 	list_insert_tail(&aclp->z_acl, newnode);
1478fa9e4066Sahrens }
1479fa9e4066Sahrens 
1480a3c49ce1SAlbert Lee int
zfs_acl_chmod_setattr(znode_t * zp,zfs_acl_t ** aclp,uint64_t mode)14814c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
1482fa9e4066Sahrens {
1483a3c49ce1SAlbert Lee 	int error = 0;
1484a3c49ce1SAlbert Lee 
1485*06799660SGordon Ross 	rw_enter(&zp->z_acl_lock, RW_WRITER);
14861412a1a2SMark Shellenbaum 	mutex_enter(&zp->z_lock);
1487a3c49ce1SAlbert Lee 	if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD)
1488a3c49ce1SAlbert Lee 		*aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
1489a3c49ce1SAlbert Lee 	else
1490a3c49ce1SAlbert Lee 		error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE);
1491a3c49ce1SAlbert Lee 
1492a3c49ce1SAlbert Lee 	if (error == 0) {
1493a3c49ce1SAlbert Lee 		(*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
1494de0f1ddbSAlbert Lee 		zfs_acl_chmod(ZTOV(zp)->v_type, mode, B_TRUE,
1495a3c49ce1SAlbert Lee 		    (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp);
1496a3c49ce1SAlbert Lee 	}
14974c841f60Smarks 	mutex_exit(&zp->z_lock);
1498*06799660SGordon Ross 	rw_exit(&zp->z_acl_lock);
1499a3c49ce1SAlbert Lee 
1500a3c49ce1SAlbert Lee 	return (error);
1501fa9e4066Sahrens }
1502fa9e4066Sahrens 
1503da6c28aaSamw /*
1504da6c28aaSamw  * Should ACE be inherited?
1505da6c28aaSamw  */
1506da6c28aaSamw static int
zfs_ace_can_use(vtype_t vtype,uint16_t acep_flags)150789459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags)
1508da6c28aaSamw {
1509da6c28aaSamw 	int	iflags = (acep_flags & 0xf);
1510da6c28aaSamw 
1511da6c28aaSamw 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
1512da6c28aaSamw 		return (1);
1513da6c28aaSamw 	else if (iflags & ACE_FILE_INHERIT_ACE)
1514da6c28aaSamw 		return (!((vtype == VDIR) &&
1515da6c28aaSamw 		    (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
1516da6c28aaSamw 	return (0);
1517fa9e4066Sahrens }
1518fa9e4066Sahrens 
1519fa9e4066Sahrens /*
1520fa9e4066Sahrens  * inherit inheritable ACEs from parent
1521fa9e4066Sahrens  */
1522fa9e4066Sahrens static zfs_acl_t *
zfs_acl_inherit(zfsvfs_t * zfsvfs,vtype_t vtype,zfs_acl_t * paclp,uint64_t mode,boolean_t * need_chmod)152389459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
1524e9bacc6dSDominik Hassler     uint64_t mode, boolean_t *need_chmod)
1525fa9e4066Sahrens {
1526de0f1ddbSAlbert Lee 	void		*pacep = NULL;
152727dd1e87SMark Shellenbaum 	void		*acep;
152827dd1e87SMark Shellenbaum 	zfs_acl_node_t  *aclnode;
1529fa9e4066Sahrens 	zfs_acl_t	*aclp = NULL;
1530da6c28aaSamw 	uint64_t	who;
1531da6c28aaSamw 	uint32_t	access_mask;
1532da6c28aaSamw 	uint16_t	iflags, newflags, type;
1533da6c28aaSamw 	size_t		ace_size;
1534da6c28aaSamw 	void		*data1, *data2;
1535da6c28aaSamw 	size_t		data1sz, data2sz;
1536de0f1ddbSAlbert Lee 	uint_t		aclinherit;
1537de0f1ddbSAlbert Lee 	boolean_t	isdir = (vtype == VDIR);
1538e9bacc6dSDominik Hassler 	boolean_t	isreg = (vtype == VREG);
1539*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
1540e9bacc6dSDominik Hassler 
1541e9bacc6dSDominik Hassler 	*need_chmod = B_TRUE;
1542de0f1ddbSAlbert Lee 
1543003c2582SMark Shellenbaum 	aclp = zfs_acl_alloc(paclp->z_version);
1544de0f1ddbSAlbert Lee 	aclinherit = zfsvfs->z_acl_inherit;
1545de0f1ddbSAlbert Lee 	if (aclinherit == ZFS_ACL_DISCARD || vtype == VLNK)
1546d0f3f37eSMark Shellenbaum 		return (aclp);
1547de0f1ddbSAlbert Lee 
1548*06799660SGordon Ross 	zai.zai_aclp = paclp;
1549*06799660SGordon Ross 	while (pacep = zfs_acl_next_ace(&zai, pacep, &who,
1550d0f3f37eSMark Shellenbaum 	    &access_mask, &iflags, &type)) {
1551fa9e4066Sahrens 
1552d0f3f37eSMark Shellenbaum 		/*
1553d0f3f37eSMark Shellenbaum 		 * don't inherit bogus ACEs
1554d0f3f37eSMark Shellenbaum 		 */
1555d0f3f37eSMark Shellenbaum 		if (!zfs_acl_valid_ace_type(type, iflags))
1556d0f3f37eSMark Shellenbaum 			continue;
1557003c2582SMark Shellenbaum 
1558de0f1ddbSAlbert Lee 		/*
1559de0f1ddbSAlbert Lee 		 * Check if ACE is inheritable by this vnode
1560de0f1ddbSAlbert Lee 		 */
1561de0f1ddbSAlbert Lee 		if ((aclinherit == ZFS_ACL_NOALLOW && type == ALLOW) ||
1562de0f1ddbSAlbert Lee 		    !zfs_ace_can_use(vtype, iflags))
1563d0f3f37eSMark Shellenbaum 			continue;
1564b3d141f8Smarks 
1565e9bacc6dSDominik Hassler 		/*
1566e9bacc6dSDominik Hassler 		 * If owner@, group@, or everyone@ inheritable
1567e9bacc6dSDominik Hassler 		 * then zfs_acl_chmod() isn't needed.
1568e9bacc6dSDominik Hassler 		 */
1569e9bacc6dSDominik Hassler 		if ((aclinherit == ZFS_ACL_PASSTHROUGH ||
1570e9bacc6dSDominik Hassler 		    aclinherit == ZFS_ACL_PASSTHROUGH_X) &&
1571e9bacc6dSDominik Hassler 		    ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
1572e9bacc6dSDominik Hassler 		    ((iflags & OWNING_GROUP) == OWNING_GROUP)) &&
1573e9bacc6dSDominik Hassler 		    (isreg || (isdir && (iflags & ACE_DIRECTORY_INHERIT_ACE))))
1574e9bacc6dSDominik Hassler 			*need_chmod = B_FALSE;
1575e9bacc6dSDominik Hassler 
1576d0f3f37eSMark Shellenbaum 		/*
1577de0f1ddbSAlbert Lee 		 * Strip inherited execute permission from file if
1578de0f1ddbSAlbert Lee 		 * not in mode
1579d0f3f37eSMark Shellenbaum 		 */
1580de0f1ddbSAlbert Lee 		if (aclinherit == ZFS_ACL_PASSTHROUGH_X && type == ALLOW &&
1581de0f1ddbSAlbert Lee 		    !isdir && ((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) {
1582de0f1ddbSAlbert Lee 			access_mask &= ~ACE_EXECUTE;
1583c694df91SMark Shellenbaum 		}
1584d0f3f37eSMark Shellenbaum 
1585de0f1ddbSAlbert Lee 		/*
1586de0f1ddbSAlbert Lee 		 * Strip write_acl and write_owner from permissions
1587de0f1ddbSAlbert Lee 		 * when inheriting an ACE
1588de0f1ddbSAlbert Lee 		 */
1589de0f1ddbSAlbert Lee 		if (aclinherit == ZFS_ACL_RESTRICTED && type == ALLOW) {
1590de0f1ddbSAlbert Lee 			access_mask &= ~RESTRICTED_CLEAR;
1591d0f3f37eSMark Shellenbaum 		}
1592d0f3f37eSMark Shellenbaum 
1593de0f1ddbSAlbert Lee 		ace_size = aclp->z_ops.ace_size(pacep);
1594d0f3f37eSMark Shellenbaum 		aclnode = zfs_acl_node_alloc(ace_size);
1595d0f3f37eSMark Shellenbaum 		list_insert_tail(&aclp->z_acl, aclnode);
1596d0f3f37eSMark Shellenbaum 		acep = aclnode->z_acldata;
1597d0f3f37eSMark Shellenbaum 
1598d0f3f37eSMark Shellenbaum 		zfs_set_ace(aclp, acep, access_mask, type,
1599d0f3f37eSMark Shellenbaum 		    who, iflags|ACE_INHERITED_ACE);
1600d0f3f37eSMark Shellenbaum 
1601d0f3f37eSMark Shellenbaum 		/*
1602d0f3f37eSMark Shellenbaum 		 * Copy special opaque data if any
1603d0f3f37eSMark Shellenbaum 		 */
1604d0f3f37eSMark Shellenbaum 		if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) {
1605d0f3f37eSMark Shellenbaum 			VERIFY((data2sz = aclp->z_ops.ace_data(acep,
1606d0f3f37eSMark Shellenbaum 			    &data2)) == data1sz);
1607d0f3f37eSMark Shellenbaum 			bcopy(data1, data2, data2sz);
1608d0f3f37eSMark Shellenbaum 		}
160927dd1e87SMark Shellenbaum 
1610d0f3f37eSMark Shellenbaum 		aclp->z_acl_count++;
1611d0f3f37eSMark Shellenbaum 		aclnode->z_ace_count++;
1612d0f3f37eSMark Shellenbaum 		aclp->z_acl_bytes += aclnode->z_size;
1613d0f3f37eSMark Shellenbaum 		newflags = aclp->z_ops.ace_flags_get(acep);
1614d0f3f37eSMark Shellenbaum 
1615de0f1ddbSAlbert Lee 		/*
1616de0f1ddbSAlbert Lee 		 * If ACE is not to be inherited further, or if the vnode is
1617de0f1ddbSAlbert Lee 		 * not a directory, remove all inheritance flags
1618de0f1ddbSAlbert Lee 		 */
1619de0f1ddbSAlbert Lee 		if (!isdir || (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
1620d0f3f37eSMark Shellenbaum 			newflags &= ~ALL_INHERIT;
1621d0f3f37eSMark Shellenbaum 			aclp->z_ops.ace_flags_set(acep,
1622d0f3f37eSMark Shellenbaum 			    newflags|ACE_INHERITED_ACE);
1623d0f3f37eSMark Shellenbaum 			continue;
1624d0f3f37eSMark Shellenbaum 		}
1625d0f3f37eSMark Shellenbaum 
1626de0f1ddbSAlbert Lee 		/*
1627de0f1ddbSAlbert Lee 		 * This directory has an inheritable ACE
1628de0f1ddbSAlbert Lee 		 */
1629de0f1ddbSAlbert Lee 		aclp->z_hints |= ZFS_INHERIT_ACE;
1630d0f3f37eSMark Shellenbaum 
163127dd1e87SMark Shellenbaum 		/*
163227dd1e87SMark Shellenbaum 		 * If only FILE_INHERIT is set then turn on
163327dd1e87SMark Shellenbaum 		 * inherit_only
163427dd1e87SMark Shellenbaum 		 */
1635d0f3f37eSMark Shellenbaum 		if ((iflags & (ACE_FILE_INHERIT_ACE |
1636485adf61SMark Shellenbaum 		    ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) {
1637d0f3f37eSMark Shellenbaum 			newflags |= ACE_INHERIT_ONLY_ACE;
1638d0f3f37eSMark Shellenbaum 			aclp->z_ops.ace_flags_set(acep,
1639d0f3f37eSMark Shellenbaum 			    newflags|ACE_INHERITED_ACE);
1640485adf61SMark Shellenbaum 		} else {
1641485adf61SMark Shellenbaum 			newflags &= ~ACE_INHERIT_ONLY_ACE;
1642485adf61SMark Shellenbaum 			aclp->z_ops.ace_flags_set(acep,
1643485adf61SMark Shellenbaum 			    newflags|ACE_INHERITED_ACE);
1644fa9e4066Sahrens 		}
1645fa9e4066Sahrens 	}
1646de0f1ddbSAlbert Lee 
1647fa9e4066Sahrens 	return (aclp);
1648fa9e4066Sahrens }
1649fa9e4066Sahrens 
1650fa9e4066Sahrens /*
1651fa9e4066Sahrens  * Create file system object initial permissions
1652fa9e4066Sahrens  * including inheritable ACEs.
1653de0f1ddbSAlbert Lee  * Also, create FUIDs for owner and group.
1654fa9e4066Sahrens  */
165589459e17SMark Shellenbaum int
zfs_acl_ids_create(znode_t * dzp,int flag,vattr_t * vap,cred_t * cr,vsecattr_t * vsecp,zfs_acl_ids_t * acl_ids)165689459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
165789459e17SMark Shellenbaum     vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
1658fa9e4066Sahrens {
1659fa9e4066Sahrens 	int		error;
166089459e17SMark Shellenbaum 	zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
1661da6c28aaSamw 	zfs_acl_t	*paclp;
1662e0d35c44Smarks 	gid_t		gid;
1663e9bacc6dSDominik Hassler 	boolean_t	need_chmod = B_TRUE;
1664de0f1ddbSAlbert Lee 	boolean_t	trim = B_FALSE;
16650a586ceaSMark Shellenbaum 	boolean_t	inherited = B_FALSE;
1666da6c28aaSamw 
166789459e17SMark Shellenbaum 	bzero(acl_ids, sizeof (zfs_acl_ids_t));
166889459e17SMark Shellenbaum 	acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1669fa9e4066Sahrens 
167089459e17SMark Shellenbaum 	if (vsecp)
167189459e17SMark Shellenbaum 		if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr,
167289459e17SMark Shellenbaum 		    &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
167389459e17SMark Shellenbaum 			return (error);
1674fa9e4066Sahrens 	/*
1675fa9e4066Sahrens 	 * Determine uid and gid.
1676fa9e4066Sahrens 	 */
16774a1f0cc9SMark Shellenbaum 	if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
1678fa9e4066Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
167989459e17SMark Shellenbaum 		acl_ids->z_fuid = zfs_fuid_create(zfsvfs,
168089459e17SMark Shellenbaum 		    (uint64_t)vap->va_uid, cr,
168189459e17SMark Shellenbaum 		    ZFS_OWNER, &acl_ids->z_fuidp);
168289459e17SMark Shellenbaum 		acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
168389459e17SMark Shellenbaum 		    (uint64_t)vap->va_gid, cr,
168489459e17SMark Shellenbaum 		    ZFS_GROUP, &acl_ids->z_fuidp);
1685e0d35c44Smarks 		gid = vap->va_gid;
1686fa9e4066Sahrens 	} else {
168789459e17SMark Shellenbaum 		acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
168889459e17SMark Shellenbaum 		    cr, &acl_ids->z_fuidp);
168989459e17SMark Shellenbaum 		acl_ids->z_fgid = 0;
1690e0d35c44Smarks 		if (vap->va_mask & AT_GID)  {
169189459e17SMark Shellenbaum 			acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
169289459e17SMark Shellenbaum 			    (uint64_t)vap->va_gid,
169389459e17SMark Shellenbaum 			    cr, ZFS_GROUP, &acl_ids->z_fuidp);
1694e0d35c44Smarks 			gid = vap->va_gid;
1695f1696b23SMark Shellenbaum 			if (acl_ids->z_fgid != dzp->z_gid &&
1696e0d35c44Smarks 			    !groupmember(vap->va_gid, cr) &&
1697e0d35c44Smarks 			    secpolicy_vnode_create_gid(cr) != 0)
169889459e17SMark Shellenbaum 				acl_ids->z_fgid = 0;
1699e0d35c44Smarks 		}
170089459e17SMark Shellenbaum 		if (acl_ids->z_fgid == 0) {
17010a586ceaSMark Shellenbaum 			if (dzp->z_mode & S_ISGID) {
1702b3874165SJohn Harres 				char		*domain;
1703b3874165SJohn Harres 				uint32_t	rid;
1704b3874165SJohn Harres 
1705f1696b23SMark Shellenbaum 				acl_ids->z_fgid = dzp->z_gid;
170689459e17SMark Shellenbaum 				gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
1707e0d35c44Smarks 				    cr, ZFS_GROUP);
1708b3874165SJohn Harres 
1709b3874165SJohn Harres 				if (zfsvfs->z_use_fuids &&
1710b3874165SJohn Harres 				    IS_EPHEMERAL(acl_ids->z_fgid)) {
1711b3874165SJohn Harres 					domain = zfs_fuid_idx_domain(
1712b3874165SJohn Harres 					    &zfsvfs->z_fuid_idx,
1713b3874165SJohn Harres 					    FUID_INDEX(acl_ids->z_fgid));
1714b3874165SJohn Harres 					rid = FUID_RID(acl_ids->z_fgid);
1715b3874165SJohn Harres 					zfs_fuid_node_add(&acl_ids->z_fuidp,
1716b3874165SJohn Harres 					    domain, rid,
1717b3874165SJohn Harres 					    FUID_INDEX(acl_ids->z_fgid),
1718b3874165SJohn Harres 					    acl_ids->z_fgid, ZFS_GROUP);
1719b3874165SJohn Harres 				}
1720e0d35c44Smarks 			} else {
172189459e17SMark Shellenbaum 				acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs,
172289459e17SMark Shellenbaum 				    ZFS_GROUP, cr, &acl_ids->z_fuidp);
1723e0d35c44Smarks 				gid = crgetgid(cr);
1724e0d35c44Smarks 			}
1725da6c28aaSamw 		}
1726fa9e4066Sahrens 	}
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	/*
1729fa9e4066Sahrens 	 * If we're creating a directory, and the parent directory has the
1730fa9e4066Sahrens 	 * set-GID bit set, set in on the new directory.
1731fa9e4066Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1732fa9e4066Sahrens 	 * file's new group, clear the file's set-GID bit.
1733fa9e4066Sahrens 	 */
1734fa9e4066Sahrens 
17350a586ceaSMark Shellenbaum 	if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
173689459e17SMark Shellenbaum 	    (vap->va_type == VDIR)) {
173789459e17SMark Shellenbaum 		acl_ids->z_mode |= S_ISGID;
1738e0d35c44Smarks 	} else {
173989459e17SMark Shellenbaum 		if ((acl_ids->z_mode & S_ISGID) &&
1740fa9e4066Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
174189459e17SMark Shellenbaum 			acl_ids->z_mode &= ~S_ISGID;
1742fa9e4066Sahrens 	}
1743fa9e4066Sahrens 
174489459e17SMark Shellenbaum 	if (acl_ids->z_aclp == NULL) {
1745*06799660SGordon Ross 		rw_enter(&dzp->z_acl_lock, RW_WRITER);
174689459e17SMark Shellenbaum 		mutex_enter(&dzp->z_lock);
1747a3c49ce1SAlbert Lee 		if (!(flag & IS_ROOT_NODE) &&
1748a3c49ce1SAlbert Lee 		    (dzp->z_pflags & ZFS_INHERIT_ACE) &&
17490a586ceaSMark Shellenbaum 		    !(dzp->z_pflags & ZFS_XATTR)) {
17501412a1a2SMark Shellenbaum 			VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE,
17511412a1a2SMark Shellenbaum 			    &paclp, B_FALSE));
175289459e17SMark Shellenbaum 			acl_ids->z_aclp = zfs_acl_inherit(zfsvfs,
1753e9bacc6dSDominik Hassler 			    vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
17540a586ceaSMark Shellenbaum 			inherited = B_TRUE;
1755da6c28aaSamw 		} else {
175689459e17SMark Shellenbaum 			acl_ids->z_aclp =
175789459e17SMark Shellenbaum 			    zfs_acl_alloc(zfs_acl_version_zp(dzp));
17580a586ceaSMark Shellenbaum 			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
175989459e17SMark Shellenbaum 		}
176089459e17SMark Shellenbaum 		mutex_exit(&dzp->z_lock);
1761*06799660SGordon Ross 		rw_exit(&dzp->z_acl_lock);
1762de0f1ddbSAlbert Lee 
1763e9bacc6dSDominik Hassler 		if (need_chmod) {
1764e9bacc6dSDominik Hassler 			if (vap->va_type == VDIR)
1765e9bacc6dSDominik Hassler 				acl_ids->z_aclp->z_hints |=
1766e9bacc6dSDominik Hassler 				    ZFS_ACL_AUTO_INHERIT;
1767e9bacc6dSDominik Hassler 
1768e9bacc6dSDominik Hassler 			if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK &&
1769e9bacc6dSDominik Hassler 			    zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH &&
1770e9bacc6dSDominik Hassler 			    zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH_X)
1771e9bacc6dSDominik Hassler 				trim = B_TRUE;
1772e9bacc6dSDominik Hassler 			zfs_acl_chmod(vap->va_type, acl_ids->z_mode, B_FALSE,
1773e9bacc6dSDominik Hassler 			    trim, acl_ids->z_aclp);
1774e9bacc6dSDominik Hassler 		}
1775fa9e4066Sahrens 	}
1776da6c28aaSamw 
17770a586ceaSMark Shellenbaum 	if (inherited || vsecp) {
1778*06799660SGordon Ross 		zfs_acl_iter_t	zai = {0};
1779*06799660SGordon Ross 
17800a586ceaSMark Shellenbaum 		acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
178127dd1e87SMark Shellenbaum 		    acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
178227dd1e87SMark Shellenbaum 		    acl_ids->z_fuid, acl_ids->z_fgid);
1783*06799660SGordon Ross 
1784*06799660SGordon Ross 		zai.zai_aclp = acl_ids->z_aclp;
1785*06799660SGordon Ross 		if (ace_trivial_common(&zai, 0, zfs_ace_walk) == 0)
17860a586ceaSMark Shellenbaum 			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
17870a586ceaSMark Shellenbaum 	}
17880a586ceaSMark Shellenbaum 
178989459e17SMark Shellenbaum 	return (0);
179089459e17SMark Shellenbaum }
1791fa9e4066Sahrens 
179289459e17SMark Shellenbaum /*
179389459e17SMark Shellenbaum  * Free ACL and fuid_infop, but not the acl_ids structure
179489459e17SMark Shellenbaum  */
179589459e17SMark Shellenbaum void
zfs_acl_ids_free(zfs_acl_ids_t * acl_ids)179689459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids)
179789459e17SMark Shellenbaum {
179889459e17SMark Shellenbaum 	if (acl_ids->z_aclp)
179989459e17SMark Shellenbaum 		zfs_acl_free(acl_ids->z_aclp);
180089459e17SMark Shellenbaum 	if (acl_ids->z_fuidp)
180189459e17SMark Shellenbaum 		zfs_fuid_info_free(acl_ids->z_fuidp);
180289459e17SMark Shellenbaum 	acl_ids->z_aclp = NULL;
180389459e17SMark Shellenbaum 	acl_ids->z_fuidp = NULL;
1804fa9e4066Sahrens }
1805fa9e4066Sahrens 
180614843421SMatthew Ahrens boolean_t
zfs_acl_ids_overquota(zfsvfs_t * zv,zfs_acl_ids_t * acl_ids,uint64_t projid)1807f67950b2SNasf-Fan zfs_acl_ids_overquota(zfsvfs_t *zv, zfs_acl_ids_t *acl_ids, uint64_t projid)
180814843421SMatthew Ahrens {
1809f67950b2SNasf-Fan 	return (zfs_id_overquota(zv, DMU_USERUSED_OBJECT, acl_ids->z_fuid) ||
1810f67950b2SNasf-Fan 	    zfs_id_overquota(zv, DMU_GROUPUSED_OBJECT, acl_ids->z_fgid) ||
1811f67950b2SNasf-Fan 	    (projid != ZFS_DEFAULT_PROJID && projid != ZFS_INVALID_PROJID &&
1812f67950b2SNasf-Fan 	    zfs_id_overquota(zv, DMU_PROJECTUSED_OBJECT, projid)));
181314843421SMatthew Ahrens }
181489459e17SMark Shellenbaum 
1815fa9e4066Sahrens /*
1816f7170741SWill Andrews  * Retrieve a file's ACL
1817fa9e4066Sahrens  */
1818fa9e4066Sahrens int
zfs_getacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)1819da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1820fa9e4066Sahrens {
1821fa9e4066Sahrens 	zfs_acl_t	*aclp;
1822da6c28aaSamw 	ulong_t		mask;
1823fa9e4066Sahrens 	int		error;
182454811da5SToomas Soome 	int		count = 0;
1825da6c28aaSamw 	int		largeace = 0;
1826fa9e4066Sahrens 
1827da6c28aaSamw 	mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
1828da6c28aaSamw 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
1829da6c28aaSamw 
1830fa9e4066Sahrens 	if (mask == 0)
1831be6fd75aSMatthew Ahrens 		return (SET_ERROR(ENOSYS));
1832fa9e4066Sahrens 
18330a586ceaSMark Shellenbaum 	if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
18340a586ceaSMark Shellenbaum 		return (error);
18350a586ceaSMark Shellenbaum 
1836*06799660SGordon Ross 	/*
1837*06799660SGordon Ross 	 * This may be frequently called, so when possible
1838*06799660SGordon Ross 	 * try to avoid entering z_acl_lock as writer.
1839*06799660SGordon Ross 	 */
1840*06799660SGordon Ross 	rw_enter(&zp->z_acl_lock, RW_READER);
1841*06799660SGordon Ross 	aclp = zp->z_acl_cached;
1842*06799660SGordon Ross 	if (aclp == NULL) {
1843*06799660SGordon Ross 		/*
1844*06799660SGordon Ross 		 * OK, need WRITER to load the ACL.  Note:
1845*06799660SGordon Ross 		 * zfs_acl_node_read() re-checks zp->z_acl_cached
1846*06799660SGordon Ross 		 * and just returns if it's set.
1847*06799660SGordon Ross 		 */
1848*06799660SGordon Ross 		rw_exit(&zp->z_acl_lock);
1849*06799660SGordon Ross 		rw_enter(&zp->z_acl_lock, RW_WRITER);
1850fa9e4066Sahrens 
1851*06799660SGordon Ross 		error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
1852*06799660SGordon Ross 		if (error != 0) {
1853*06799660SGordon Ross 			rw_exit(&zp->z_acl_lock);
1854*06799660SGordon Ross 			return (error);
1855*06799660SGordon Ross 		}
1856*06799660SGordon Ross 		rw_downgrade(&zp->z_acl_lock);	/* now RW_READER */
1857*06799660SGordon Ross 		ASSERT(zp->z_acl_cached);
1858ea8dc4b6Seschrock 	}
1859ea8dc4b6Seschrock 
1860da6c28aaSamw 	/*
1861da6c28aaSamw 	 * Scan ACL to determine number of ACEs
1862da6c28aaSamw 	 */
18630a586ceaSMark Shellenbaum 	if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) {
1864da6c28aaSamw 		void *zacep = NULL;
1865da6c28aaSamw 		uint64_t who;
1866da6c28aaSamw 		uint32_t access_mask;
1867da6c28aaSamw 		uint16_t type, iflags;
1868*06799660SGordon Ross 		zfs_acl_iter_t	zai = {0};
1869da6c28aaSamw 
1870*06799660SGordon Ross 		zai.zai_aclp = aclp;
1871*06799660SGordon Ross 		while (zacep = zfs_acl_next_ace(&zai, zacep,
1872da6c28aaSamw 		    &who, &access_mask, &iflags, &type)) {
1873da6c28aaSamw 			switch (type) {
1874da6c28aaSamw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
1875da6c28aaSamw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
1876da6c28aaSamw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
1877da6c28aaSamw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
1878da6c28aaSamw 				largeace++;
1879da6c28aaSamw 				continue;
1880da6c28aaSamw 			default:
1881da6c28aaSamw 				count++;
1882da6c28aaSamw 			}
1883da6c28aaSamw 		}
1884da6c28aaSamw 		vsecp->vsa_aclcnt = count;
1885da6c28aaSamw 	} else
18860a586ceaSMark Shellenbaum 		count = (int)aclp->z_acl_count;
1887fa9e4066Sahrens 
1888fa9e4066Sahrens 	if (mask & VSA_ACECNT) {
1889da6c28aaSamw 		vsecp->vsa_aclcnt = count;
1890fa9e4066Sahrens 	}
1891fa9e4066Sahrens 
1892fa9e4066Sahrens 	if (mask & VSA_ACE) {
1893da6c28aaSamw 		size_t aclsz;
1894da6c28aaSamw 
1895da6c28aaSamw 		aclsz = count * sizeof (ace_t) +
1896da6c28aaSamw 		    sizeof (ace_object_t) * largeace;
1897da6c28aaSamw 
1898da6c28aaSamw 		vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
1899da6c28aaSamw 		vsecp->vsa_aclentsz = aclsz;
1900da6c28aaSamw 
1901da6c28aaSamw 		if (aclp->z_version == ZFS_ACL_VERSION_FUID)
1902bda89588Sjp 			zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr,
1903da6c28aaSamw 			    vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
1904da6c28aaSamw 		else {
19052e7d9b42SMark Shellenbaum 			zfs_acl_node_t *aclnode;
19062e7d9b42SMark Shellenbaum 			void *start = vsecp->vsa_aclentp;
19072e7d9b42SMark Shellenbaum 
19082e7d9b42SMark Shellenbaum 			for (aclnode = list_head(&aclp->z_acl); aclnode;
19092e7d9b42SMark Shellenbaum 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
19102e7d9b42SMark Shellenbaum 				bcopy(aclnode->z_acldata, start,
19112e7d9b42SMark Shellenbaum 				    aclnode->z_size);
19122e7d9b42SMark Shellenbaum 				start = (caddr_t)start + aclnode->z_size;
19132e7d9b42SMark Shellenbaum 			}
19142e7d9b42SMark Shellenbaum 			ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp ==
19152e7d9b42SMark Shellenbaum 			    aclp->z_acl_bytes);
1916da6c28aaSamw 		}
1917da6c28aaSamw 	}
1918da6c28aaSamw 	if (mask & VSA_ACE_ACLFLAGS) {
1919da6c28aaSamw 		vsecp->vsa_aclflags = 0;
19200a586ceaSMark Shellenbaum 		if (zp->z_pflags & ZFS_ACL_DEFAULTED)
1921da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_DEFAULTED;
19220a586ceaSMark Shellenbaum 		if (zp->z_pflags & ZFS_ACL_PROTECTED)
1923da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_PROTECTED;
19240a586ceaSMark Shellenbaum 		if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT)
1925da6c28aaSamw 			vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
1926fa9e4066Sahrens 	}
1927fa9e4066Sahrens 
1928*06799660SGordon Ross 	rw_exit(&zp->z_acl_lock);
1929fa9e4066Sahrens 
1930fa9e4066Sahrens 	return (0);
1931fa9e4066Sahrens }
1932fa9e4066Sahrens 
1933da6c28aaSamw int
zfs_vsec_2_aclp(zfsvfs_t * zfsvfs,vtype_t obj_type,vsecattr_t * vsecp,cred_t * cr,zfs_fuid_info_t ** fuidp,zfs_acl_t ** zaclp)1934da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
193589459e17SMark Shellenbaum     vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp)
1936da6c28aaSamw {
1937da6c28aaSamw 	zfs_acl_t *aclp;
1938da6c28aaSamw 	zfs_acl_node_t *aclnode;
1939da6c28aaSamw 	int aclcnt = vsecp->vsa_aclcnt;
1940da6c28aaSamw 	int error;
1941da6c28aaSamw 
1942da6c28aaSamw 	if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
1943be6fd75aSMatthew Ahrens 		return (SET_ERROR(EINVAL));
1944da6c28aaSamw 
1945da6c28aaSamw 	aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
1946da6c28aaSamw 
1947da6c28aaSamw 	aclp->z_hints = 0;
1948da6c28aaSamw 	aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
1949da6c28aaSamw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
1950da6c28aaSamw 		if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
1951da6c28aaSamw 		    (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
1952da6c28aaSamw 		    aclcnt, &aclnode->z_size)) != 0) {
1953da6c28aaSamw 			zfs_acl_free(aclp);
1954da6c28aaSamw 			zfs_acl_node_free(aclnode);
1955da6c28aaSamw 			return (error);
1956da6c28aaSamw 		}
1957da6c28aaSamw 	} else {
195889459e17SMark Shellenbaum 		if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp,
1959da6c28aaSamw 		    vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
196089459e17SMark Shellenbaum 		    &aclnode->z_size, fuidp, cr)) != 0) {
1961da6c28aaSamw 			zfs_acl_free(aclp);
1962da6c28aaSamw 			zfs_acl_node_free(aclnode);
1963da6c28aaSamw 			return (error);
1964da6c28aaSamw 		}
1965da6c28aaSamw 	}
1966da6c28aaSamw 	aclp->z_acl_bytes = aclnode->z_size;
1967da6c28aaSamw 	aclnode->z_ace_count = aclcnt;
1968da6c28aaSamw 	aclp->z_acl_count = aclcnt;
1969da6c28aaSamw 	list_insert_head(&aclp->z_acl, aclnode);
1970da6c28aaSamw 
1971da6c28aaSamw 	/*
1972da6c28aaSamw 	 * If flags are being set then add them to z_hints
1973da6c28aaSamw 	 */
1974da6c28aaSamw 	if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
1975da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_PROTECTED)
1976da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_PROTECTED;
1977da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_DEFAULTED)
1978da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_DEFAULTED;
1979da6c28aaSamw 		if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
1980da6c28aaSamw 			aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
1981da6c28aaSamw 	}
1982da6c28aaSamw 
1983da6c28aaSamw 	*zaclp = aclp;
1984da6c28aaSamw 
1985da6c28aaSamw 	return (0);
1986da6c28aaSamw }
1987da6c28aaSamw 
1988fa9e4066Sahrens /*
1989f7170741SWill Andrews  * Set a file's ACL
1990fa9e4066Sahrens  */
1991fa9e4066Sahrens int
zfs_setacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)1992da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1993fa9e4066Sahrens {
1994fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1995fa9e4066Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
1996fa9e4066Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1997fa9e4066Sahrens 	dmu_tx_t	*tx;
1998fa9e4066Sahrens 	int		error;
1999fa9e4066Sahrens 	zfs_acl_t	*aclp;
2000da6c28aaSamw 	zfs_fuid_info_t	*fuidp = NULL;
200189459e17SMark Shellenbaum 	boolean_t	fuid_dirtied;
20021412a1a2SMark Shellenbaum 	uint64_t	acl_obj;
2003fa9e4066Sahrens 
2004fa9e4066Sahrens 	if (mask == 0)
2005be6fd75aSMatthew Ahrens 		return (SET_ERROR(ENOSYS));
2006fa9e4066Sahrens 
20070a586ceaSMark Shellenbaum 	if (zp->z_pflags & ZFS_IMMUTABLE)
2008be6fd75aSMatthew Ahrens 		return (SET_ERROR(EPERM));
2009da6c28aaSamw 
2010da6c28aaSamw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
2011da6c28aaSamw 		return (error);
2012da6c28aaSamw 
201389459e17SMark Shellenbaum 	error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
201489459e17SMark Shellenbaum 	    &aclp);
2015da6c28aaSamw 	if (error)
2016da6c28aaSamw 		return (error);
2017da6c28aaSamw 
2018da6c28aaSamw 	/*
2019da6c28aaSamw 	 * If ACL wide flags aren't being set then preserve any
2020da6c28aaSamw 	 * existing flags.
2021da6c28aaSamw 	 */
2022da6c28aaSamw 	if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
20230a586ceaSMark Shellenbaum 		aclp->z_hints |=
20240a586ceaSMark Shellenbaum 		    (zp->z_pflags & V4_ACL_WIDE_FLAGS);
2025da6c28aaSamw 	}
2026fa9e4066Sahrens top:
2027*06799660SGordon Ross 	rw_enter(&zp->z_acl_lock, RW_WRITER);
20281412a1a2SMark Shellenbaum 	mutex_enter(&zp->z_lock);
2029fa9e4066Sahrens 
2030fa9e4066Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
20310a586ceaSMark Shellenbaum 
20320a586ceaSMark Shellenbaum 	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
20330a586ceaSMark Shellenbaum 
20340a586ceaSMark Shellenbaum 	fuid_dirtied = zfsvfs->z_fuid_dirty;
20350a586ceaSMark Shellenbaum 	if (fuid_dirtied)
20360a586ceaSMark Shellenbaum 		zfs_fuid_txhold(zfsvfs, tx);
20370a586ceaSMark Shellenbaum 
20380a586ceaSMark Shellenbaum 	/*
20390a586ceaSMark Shellenbaum 	 * If old version and ACL won't fit in bonus and we aren't
20400a586ceaSMark Shellenbaum 	 * upgrading then take out necessary DMU holds
20410a586ceaSMark Shellenbaum 	 */
20420a586ceaSMark Shellenbaum 
20431412a1a2SMark Shellenbaum 	if ((acl_obj = zfs_external_acl(zp)) != 0) {
20442bd6c4deSMark Shellenbaum 		if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
20451412a1a2SMark Shellenbaum 		    zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
20461412a1a2SMark Shellenbaum 			dmu_tx_hold_free(tx, acl_obj, 0,
20470a586ceaSMark Shellenbaum 			    DMU_OBJECT_END);
20482bd6c4deSMark Shellenbaum 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
20492bd6c4deSMark Shellenbaum 			    aclp->z_acl_bytes);
2050da6c28aaSamw 		} else {
20511412a1a2SMark Shellenbaum 			dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
2052da6c28aaSamw 		}
20530a586ceaSMark Shellenbaum 	} else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
2054da6c28aaSamw 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
2055da6c28aaSamw 	}
2056fa9e4066Sahrens 
20570a586ceaSMark Shellenbaum 	zfs_sa_upgrade_txholds(tx, zp);
20581209a471SNeil Perrin 	error = dmu_tx_assign(tx, TXG_NOWAIT);
2059fa9e4066Sahrens 	if (error) {
2060*06799660SGordon Ross 		rw_exit(&zp->z_acl_lock);
2061fa9e4066Sahrens 		mutex_exit(&zp->z_lock);
2062fa9e4066Sahrens 
20631209a471SNeil Perrin 		if (error == ERESTART) {
20648a2f1b91Sahrens 			dmu_tx_wait(tx);
20658a2f1b91Sahrens 			dmu_tx_abort(tx);
2066fa9e4066Sahrens 			goto top;
2067fa9e4066Sahrens 		}
20688a2f1b91Sahrens 		dmu_tx_abort(tx);
2069da6c28aaSamw 		zfs_acl_free(aclp);
2070fa9e4066Sahrens 		return (error);
2071fa9e4066Sahrens 	}
2072fa9e4066Sahrens 
207389459e17SMark Shellenbaum 	error = zfs_aclset_common(zp, aclp, cr, tx);
2074fa9e4066Sahrens 	ASSERT(error == 0);
20750b2a8171SMark Shellenbaum 	ASSERT(zp->z_acl_cached == NULL);
20764929fd5eSTim Haley 	zp->z_acl_cached = aclp;
2077fa9e4066Sahrens 
207889459e17SMark Shellenbaum 	if (fuid_dirtied)
207989459e17SMark Shellenbaum 		zfs_fuid_sync(zfsvfs, tx);
208089459e17SMark Shellenbaum 
2081da6c28aaSamw 	zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
2082da6c28aaSamw 
2083da6c28aaSamw 	if (fuidp)
2084da6c28aaSamw 		zfs_fuid_info_free(fuidp);
2085fa9e4066Sahrens 	dmu_tx_commit(tx);
2086fa9e4066Sahrens done:
2087fa9e4066Sahrens 	mutex_exit(&zp->z_lock);
2088*06799660SGordon Ross 	rw_exit(&zp->z_acl_lock);
2089fa9e4066Sahrens 
2090fa9e4066Sahrens 	return (error);
2091fa9e4066Sahrens }
2092fa9e4066Sahrens 
2093da6c28aaSamw /*
2094e802abbdSTim Haley  * Check accesses of interest (AoI) against attributes of the dataset
2095e802abbdSTim Haley  * such as read-only.  Returns zero if no AoI conflict with dataset
2096e802abbdSTim Haley  * attributes, otherwise an appropriate errno is returned.
2097da6c28aaSamw  */
2098fa9e4066Sahrens static int
zfs_zaccess_dataset_check(znode_t * zp,uint32_t v4_mode)2099e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
2100fa9e4066Sahrens {
2101fa9e4066Sahrens 	if ((v4_mode & WRITE_MASK) &&
2102fa9e4066Sahrens 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
2103f52e0e2bSMark Shellenbaum 	    (!IS_DEVVP(ZTOV(zp)) ||
2104f52e0e2bSMark Shellenbaum 	    (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
2105be6fd75aSMatthew Ahrens 		return (SET_ERROR(EROFS));
2106fa9e4066Sahrens 	}
2107fa9e4066Sahrens 
2108da6c28aaSamw 	/*
21092889ec41SGordon Ross 	 * Intentionally allow ZFS_READONLY through here.
21102889ec41SGordon Ross 	 * See zfs_zaccess_common().
2111da6c28aaSamw 	 */
2112da6c28aaSamw 	if ((v4_mode & WRITE_MASK_DATA) &&
21132889ec41SGordon Ross 	    (zp->z_pflags & ZFS_IMMUTABLE)) {
2114be6fd75aSMatthew Ahrens 		return (SET_ERROR(EPERM));
2115da6c28aaSamw 	}
2116da6c28aaSamw 
2117da6c28aaSamw 	if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
21180a586ceaSMark Shellenbaum 	    (zp->z_pflags & ZFS_NOUNLINK)) {
2119be6fd75aSMatthew Ahrens 		return (SET_ERROR(EPERM));
2120da6c28aaSamw 	}
2121da6c28aaSamw 
2122da6c28aaSamw 	if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
21230a586ceaSMark Shellenbaum 	    (zp->z_pflags & ZFS_AV_QUARANTINED))) {
2124be6fd75aSMatthew Ahrens 		return (SET_ERROR(EACCES));
2125da6c28aaSamw 	}
2126da6c28aaSamw 
2127e802abbdSTim Haley 	return (0);
2128e802abbdSTim Haley }
2129e802abbdSTim Haley 
2130e802abbdSTim Haley /*
2131e802abbdSTim Haley  * The primary usage of this function is to loop through all of the
2132e802abbdSTim Haley  * ACEs in the znode, determining what accesses of interest (AoI) to
2133e802abbdSTim Haley  * the caller are allowed or denied.  The AoI are expressed as bits in
2134e802abbdSTim Haley  * the working_mode parameter.  As each ACE is processed, bits covered
2135e802abbdSTim Haley  * by that ACE are removed from the working_mode.  This removal
2136e802abbdSTim Haley  * facilitates two things.  The first is that when the working mode is
2137e802abbdSTim Haley  * empty (= 0), we know we've looked at all the AoI. The second is
2138e802abbdSTim Haley  * that the ACE interpretation rules don't allow a later ACE to undo
2139e802abbdSTim Haley  * something granted or denied by an earlier ACE.  Removing the
2140e802abbdSTim Haley  * discovered access or denial enforces this rule.  At the end of
2141e802abbdSTim Haley  * processing the ACEs, all AoI that were found to be denied are
2142e802abbdSTim Haley  * placed into the working_mode, giving the caller a mask of denied
2143e802abbdSTim Haley  * accesses.  Returns:
2144e802abbdSTim Haley  *	0		if all AoI granted
21451eb4e906SKevin Crowe  *	EACCES		if the denied mask is non-zero
2146e802abbdSTim Haley  *	other error	if abnormal failure (e.g., IO error)
2147e802abbdSTim Haley  *
2148e802abbdSTim Haley  * A secondary usage of the function is to determine if any of the
2149e802abbdSTim Haley  * AoI are granted.  If an ACE grants any access in
2150e802abbdSTim Haley  * the working_mode, we immediately short circuit out of the function.
2151e802abbdSTim Haley  * This mode is chosen by setting anyaccess to B_TRUE.  The
2152e802abbdSTim Haley  * working_mode is not a denied access mask upon exit if the function
2153e802abbdSTim Haley  * is used in this manner.
2154e802abbdSTim Haley  */
2155e802abbdSTim Haley static int
zfs_zaccess_aces_check(znode_t * zp,uint32_t * working_mode,boolean_t anyaccess,cred_t * cr)2156e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
2157e802abbdSTim Haley     boolean_t anyaccess, cred_t *cr)
2158e802abbdSTim Haley {
2159e802abbdSTim Haley 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2160e802abbdSTim Haley 	zfs_acl_t	*aclp;
2161e802abbdSTim Haley 	int		error;
21624fbfc69bSGordon Ross 	uint64_t	who;		/* FUID from the ACE */
2163e802abbdSTim Haley 	uint16_t	type, iflags;
2164e802abbdSTim Haley 	uint16_t	entry_type;
2165e802abbdSTim Haley 	uint32_t	access_mask;
2166e802abbdSTim Haley 	uint32_t	deny_mask = 0;
2167e802abbdSTim Haley 	zfs_ace_hdr_t	*acep = NULL;
21684fbfc69bSGordon Ross 	boolean_t	checkit;	/* ACE ID matches */
2169*06799660SGordon Ross 	zfs_acl_iter_t	zai = {0};
2170da6c28aaSamw 
2171*06799660SGordon Ross 	/*
2172*06799660SGordon Ross 	 * This can be a HOT code path, so when possible
2173*06799660SGordon Ross 	 * try to avoid entering z_acl_lock as writer.
2174*06799660SGordon Ross 	 */
2175*06799660SGordon Ross 	rw_enter(&zp->z_acl_lock, RW_READER);
2176*06799660SGordon Ross 	aclp = zp->z_acl_cached;
2177*06799660SGordon Ross 	if (aclp == NULL) {
2178*06799660SGordon Ross 		/*
2179*06799660SGordon Ross 		 * OK, need WRITER to load the ACL.  Note:
2180*06799660SGordon Ross 		 * zfs_acl_node_read() re-checks zp->z_acl_cached
2181*06799660SGordon Ross 		 * and just returns if it's set.
2182*06799660SGordon Ross 		 */
2183*06799660SGordon Ross 		rw_exit(&zp->z_acl_lock);
2184*06799660SGordon Ross 		rw_enter(&zp->z_acl_lock, RW_WRITER);
2185fa9e4066Sahrens 
2186*06799660SGordon Ross 		error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
2187*06799660SGordon Ross 		if (error != 0) {
2188*06799660SGordon Ross 			rw_exit(&zp->z_acl_lock);
2189*06799660SGordon Ross 			return (error);
2190*06799660SGordon Ross 		}
2191*06799660SGordon Ross 		rw_downgrade(&zp->z_acl_lock);	/* now RW_READER */
2192*06799660SGordon Ross 		ASSERT(zp->z_acl_cached);
2193ea8dc4b6Seschrock 	}
2194ea8dc4b6Seschrock 
2195*06799660SGordon Ross 	zai.zai_aclp = aclp;
2196*06799660SGordon Ross 	while (acep = zfs_acl_next_ace(&zai, acep, &who, &access_mask,
2197da6c28aaSamw 	    &iflags, &type)) {
2198e802abbdSTim Haley 		uint32_t mask_matched;
2199fa9e4066Sahrens 
2200003c2582SMark Shellenbaum 		if (!zfs_acl_valid_ace_type(type, iflags))
2201003c2582SMark Shellenbaum 			continue;
2202003c2582SMark Shellenbaum 
2203b249c65cSmarks 		if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
2204da6c28aaSamw 			continue;
2205fa9e4066Sahrens 
2206e802abbdSTim Haley 		/* Skip ACE if it does not affect any AoI */
2207e802abbdSTim Haley 		mask_matched = (access_mask & *working_mode);
2208e802abbdSTim Haley 		if (!mask_matched)
2209e802abbdSTim Haley 			continue;
2210e802abbdSTim Haley 
2211da6c28aaSamw 		entry_type = (iflags & ACE_TYPE_FLAGS);
2212169cdae2Smarks 
2213da6c28aaSamw 		checkit = B_FALSE;
2214fa9e4066Sahrens 
2215fa9e4066Sahrens 		switch (entry_type) {
2216fa9e4066Sahrens 		case ACE_OWNER:
22174fbfc69bSGordon Ross 			who = zp->z_uid;
22184fbfc69bSGordon Ross 			/*FALLTHROUGH*/
22194fbfc69bSGordon Ross 		case 0:	/* USER Entry */
22204fbfc69bSGordon Ross 			checkit = zfs_user_in_cred(zfsvfs, who, cr);
2221fa9e4066Sahrens 			break;
2222da6c28aaSamw 		case OWNING_GROUP:
22234fbfc69bSGordon Ross 			who = zp->z_gid;
2224da6c28aaSamw 			/*FALLTHROUGH*/
2225fa9e4066Sahrens 		case ACE_IDENTIFIER_GROUP:
2226da6c28aaSamw 			checkit = zfs_groupmember(zfsvfs, who, cr);
2227fa9e4066Sahrens 			break;
2228fa9e4066Sahrens 		case ACE_EVERYONE:
2229da6c28aaSamw 			checkit = B_TRUE;
2230fa9e4066Sahrens 			break;
2231fa9e4066Sahrens 
2232fa9e4066Sahrens 		default:
22334fbfc69bSGordon Ross 			/*
22344fbfc69bSGordon Ross 			 * The zfs_acl_valid_ace_type check above
22354fbfc69bSGordon Ross 			 * should make this case impossible.
22364fbfc69bSGordon Ross 			 */
2237*06799660SGordon Ross 			rw_exit(&zp->z_acl_lock);
22384fbfc69bSGordon Ross 			return (SET_ERROR(EIO));
2239da6c28aaSamw 		}
2240da6c28aaSamw 
2241da6c28aaSamw 		if (checkit) {
2242e802abbdSTim Haley 			if (type == DENY) {
2243e802abbdSTim Haley 				DTRACE_PROBE3(zfs__ace__denies,
2244e802abbdSTim Haley 				    znode_t *, zp,
2245e802abbdSTim Haley 				    zfs_ace_hdr_t *, acep,
2246e802abbdSTim Haley 				    uint32_t, mask_matched);
2247e802abbdSTim Haley 				deny_mask |= mask_matched;
2248e802abbdSTim Haley 			} else {
2249e802abbdSTim Haley 				DTRACE_PROBE3(zfs__ace__allows,
2250e802abbdSTim Haley 				    znode_t *, zp,
2251e802abbdSTim Haley 				    zfs_ace_hdr_t *, acep,
2252e802abbdSTim Haley 				    uint32_t, mask_matched);
2253e802abbdSTim Haley 				if (anyaccess) {
2254*06799660SGordon Ross 					rw_exit(&zp->z_acl_lock);
2255e802abbdSTim Haley 					return (0);
2256e802abbdSTim Haley 				}
2257fa9e4066Sahrens 			}
2258e802abbdSTim Haley 			*working_mode &= ~mask_matched;
2259fa9e4066Sahrens 		}
2260fa9e4066Sahrens 
226190fafcf0Smarks 		/* Are we done? */
226290fafcf0Smarks 		if (*working_mode == 0)
2263fa9e4066Sahrens 			break;
2264fa9e4066Sahrens 	}
2265fa9e4066Sahrens 
2266*06799660SGordon Ross 	rw_exit(&zp->z_acl_lock);
226790fafcf0Smarks 
226890fafcf0Smarks 	/* Put the found 'denies' back on the working mode */
22697ed7e920Smarks 	if (deny_mask) {
22707ed7e920Smarks 		*working_mode |= deny_mask;
2271be6fd75aSMatthew Ahrens 		return (SET_ERROR(EACCES));
22727ed7e920Smarks 	} else if (*working_mode) {
22737ed7e920Smarks 		return (-1);
22747ed7e920Smarks 	}
227590fafcf0Smarks 
227690fafcf0Smarks 	return (0);
2277fa9e4066Sahrens }
2278fa9e4066Sahrens 
2279e802abbdSTim Haley /*
2280e802abbdSTim Haley  * Return true if any access whatsoever granted, we don't actually
2281e802abbdSTim Haley  * care what access is granted.
2282e802abbdSTim Haley  */
2283e802abbdSTim Haley boolean_t
zfs_has_access(znode_t * zp,cred_t * cr)2284e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr)
2285e802abbdSTim Haley {
2286e802abbdSTim Haley 	uint32_t have = ACE_ALL_PERMS;
2287e802abbdSTim Haley 
2288e802abbdSTim Haley 	if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
2289f1696b23SMark Shellenbaum 		uid_t owner;
2290f1696b23SMark Shellenbaum 
2291f1696b23SMark Shellenbaum 		owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
2292f1696b23SMark Shellenbaum 		return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0);
2293e802abbdSTim Haley 	}
2294e802abbdSTim Haley 	return (B_TRUE);
2295e802abbdSTim Haley }
2296e802abbdSTim Haley 
2297e802abbdSTim Haley static int
zfs_zaccess_common(znode_t * zp,uint32_t v4_mode,uint32_t * working_mode,boolean_t * check_privs,boolean_t skipaclchk,cred_t * cr)2298e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
2299e802abbdSTim Haley     boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
2300e802abbdSTim Haley {
2301e802abbdSTim Haley 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
2302e802abbdSTim Haley 	int err;
2303e802abbdSTim Haley 
2304e802abbdSTim Haley 	*working_mode = v4_mode;
2305e802abbdSTim Haley 	*check_privs = B_TRUE;
2306e802abbdSTim Haley 
2307e802abbdSTim Haley 	/*
2308e802abbdSTim Haley 	 * Short circuit empty requests
2309e802abbdSTim Haley 	 */
2310e802abbdSTim Haley 	if (v4_mode == 0 || zfsvfs->z_replay) {
2311e802abbdSTim Haley 		*working_mode = 0;
2312e802abbdSTim Haley 		return (0);
2313e802abbdSTim Haley 	}
2314e802abbdSTim Haley 
2315e802abbdSTim Haley 	if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) {
2316e802abbdSTim Haley 		*check_privs = B_FALSE;
2317e802abbdSTim Haley 		return (err);
2318e802abbdSTim Haley 	}
2319e802abbdSTim Haley 
2320e802abbdSTim Haley 	/*
2321e802abbdSTim Haley 	 * The caller requested that the ACL check be skipped.  This
2322e802abbdSTim Haley 	 * would only happen if the caller checked VOP_ACCESS() with a
2323e802abbdSTim Haley 	 * 32 bit ACE mask and already had the appropriate permissions.
2324e802abbdSTim Haley 	 */
2325e802abbdSTim Haley 	if (skipaclchk) {
2326e802abbdSTim Haley 		*working_mode = 0;
2327e802abbdSTim Haley 		return (0);
2328e802abbdSTim Haley 	}
2329e802abbdSTim Haley 
23302889ec41SGordon Ross 	/*
23312889ec41SGordon Ross 	 * Note: ZFS_READONLY represents the "DOS R/O" attribute.
23322889ec41SGordon Ross 	 * When that flag is set, we should behave as if write access
23332889ec41SGordon Ross 	 * were not granted by anything in the ACL.  In particular:
23342889ec41SGordon Ross 	 * We _must_ allow writes after opening the file r/w, then
23352889ec41SGordon Ross 	 * setting the DOS R/O attribute, and writing some more.
23362889ec41SGordon Ross 	 * (Similar to how you can write after fchmod(fd, 0444).)
23372889ec41SGordon Ross 	 *
23382889ec41SGordon Ross 	 * Therefore ZFS_READONLY is ignored in the dataset check
23392889ec41SGordon Ross 	 * above, and checked here as if part of the ACL check.
23402889ec41SGordon Ross 	 * Also note: DOS R/O is ignored for directories.
23412889ec41SGordon Ross 	 */
23422889ec41SGordon Ross 	if ((v4_mode & WRITE_MASK_DATA) &&
23432889ec41SGordon Ross 	    (ZTOV(zp)->v_type != VDIR) &&
23442889ec41SGordon Ross 	    (zp->z_pflags & ZFS_READONLY)) {
23452889ec41SGordon Ross 		return (SET_ERROR(EPERM));
23462889ec41SGordon Ross 	}
23472889ec41SGordon Ross 
2348e802abbdSTim Haley 	return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
2349e802abbdSTim Haley }
2350e802abbdSTim Haley 
2351da6c28aaSamw static int
zfs_zaccess_append(znode_t * zp,uint32_t * working_mode,boolean_t * check_privs,cred_t * cr)2352da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
2353da6c28aaSamw     cred_t *cr)
2354da6c28aaSamw {
2355da6c28aaSamw 	if (*working_mode != ACE_WRITE_DATA)
2356be6fd75aSMatthew Ahrens 		return (SET_ERROR(EACCES));
2357da6c28aaSamw 
2358da6c28aaSamw 	return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
2359da6c28aaSamw 	    check_privs, B_FALSE, cr));
2360da6c28aaSamw }
2361fa9e4066Sahrens 
2362d47621a4STim Haley int
zfs_fastaccesschk_execute(znode_t * zdp,cred_t * cr,boolean_t skipaclchk)2363f37b3cbbSMatt Barden zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr, boolean_t skipaclchk)
2364d47621a4STim Haley {
2365d47621a4STim Haley 	boolean_t owner = B_FALSE;
2366d47621a4STim Haley 	boolean_t groupmbr = B_FALSE;
2367d47621a4STim Haley 	boolean_t is_attr;
2368d47621a4STim Haley 	uid_t uid = crgetuid(cr);
2369d47621a4STim Haley 	int error;
2370d47621a4STim Haley 
23710a586ceaSMark Shellenbaum 	if (zdp->z_pflags & ZFS_AV_QUARANTINED)
2372be6fd75aSMatthew Ahrens 		return (SET_ERROR(EACCES));
2373d47621a4STim Haley 
23740a586ceaSMark Shellenbaum 	is_attr = ((zdp->z_pflags & ZFS_XATTR) &&
2375d47621a4STim Haley 	    (ZTOV(zdp)->v_type == VDIR));
2376d47621a4STim Haley 	if (is_attr)
2377d47621a4STim Haley 		goto slow;
2378d47621a4STim Haley 
23790a586ceaSMark Shellenbaum 
2380*06799660SGordon Ross 	rw_enter(&zdp->z_acl_lock, RW_READER);
2381d47621a4STim Haley 
23820a586ceaSMark Shellenbaum 	if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) {
2383*06799660SGordon Ross 		rw_exit(&zdp->z_acl_lock);
2384d47621a4STim Haley 		return (0);
2385d47621a4STim Haley 	}
2386d47621a4STim Haley 
2387f1696b23SMark Shellenbaum 	if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
2388*06799660SGordon Ross 		rw_exit(&zdp->z_acl_lock);
2389d47621a4STim Haley 		goto slow;
2390d47621a4STim Haley 	}
2391d47621a4STim Haley 
23920a586ceaSMark Shellenbaum 	if (uid == zdp->z_uid) {
2393d47621a4STim Haley 		owner = B_TRUE;
23940a586ceaSMark Shellenbaum 		if (zdp->z_mode & S_IXUSR) {
2395*06799660SGordon Ross 			rw_exit(&zdp->z_acl_lock);
2396d47621a4STim Haley 			return (0);
2397e4f96946STim Haley 		} else {
2398*06799660SGordon Ross 			rw_exit(&zdp->z_acl_lock);
2399e4f96946STim Haley 			goto slow;
2400d47621a4STim Haley 		}
2401d47621a4STim Haley 	}
24020a586ceaSMark Shellenbaum 	if (groupmember(zdp->z_gid, cr)) {
2403d47621a4STim Haley 		groupmbr = B_TRUE;
24040a586ceaSMark Shellenbaum 		if (zdp->z_mode & S_IXGRP) {
2405*06799660SGordon Ross 			rw_exit(&zdp->z_acl_lock);
2406d47621a4STim Haley 			return (0);
2407e4f96946STim Haley 		} else {
2408*06799660SGordon Ross 			rw_exit(&zdp->z_acl_lock);
2409e4f96946STim Haley 			goto slow;
2410d47621a4STim Haley 		}
2411d47621a4STim Haley 	}
2412d47621a4STim Haley 	if (!owner && !groupmbr) {
24130a586ceaSMark Shellenbaum 		if (zdp->z_mode & S_IXOTH) {
2414*06799660SGordon Ross 			rw_exit(&zdp->z_acl_lock);
2415d47621a4STim Haley 			return (0);
2416d47621a4STim Haley 		}
2417d47621a4STim Haley 	}
2418d47621a4STim Haley 
2419*06799660SGordon Ross 	rw_exit(&zdp->z_acl_lock);
2420d47621a4STim Haley 
2421d47621a4STim Haley slow:
2422d47621a4STim Haley 	DTRACE_PROBE(zfs__fastpath__execute__access__miss);
2423d47621a4STim Haley 	ZFS_ENTER(zdp->z_zfsvfs);
2424f37b3cbbSMatt Barden 	error = zfs_zaccess(zdp, ACE_EXECUTE, 0, skipaclchk, cr);
2425d47621a4STim Haley 	ZFS_EXIT(zdp->z_zfsvfs);
2426d47621a4STim Haley 	return (error);
2427d47621a4STim Haley }
2428d47621a4STim Haley 
2429fa9e4066Sahrens /*
2430134a1f4eSCasper H.S. Dik  * Determine whether Access should be granted/denied.
2431f7170741SWill Andrews  *
2432edc8ef7dSToomas Soome  * The least priv subsystem is always consulted as a basic privilege
2433134a1f4eSCasper H.S. Dik  * can define any form of access.
2434fa9e4066Sahrens  */
2435fa9e4066Sahrens int
zfs_zaccess(znode_t * zp,int mode,int flags,boolean_t skipaclchk,cred_t * cr)2436da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
2437fa9e4066Sahrens {
2438da6c28aaSamw 	uint32_t	working_mode;
2439da6c28aaSamw 	int		error;
2440da6c28aaSamw 	int		is_attr;
244154811da5SToomas Soome 	boolean_t	check_privs;
2442da6c28aaSamw 	znode_t		*xzp;
244354811da5SToomas Soome 	znode_t		*check_zp = zp;
2444134a1f4eSCasper H.S. Dik 	mode_t		needed_bits;
2445f1696b23SMark Shellenbaum 	uid_t		owner;
2446fa9e4066Sahrens 
24470a586ceaSMark Shellenbaum 	is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
2448fa9e4066Sahrens 
2449fa9e4066Sahrens 	/*
2450fa9e4066Sahrens 	 * If attribute then validate against base file
2451fa9e4066Sahrens 	 */
2452fa9e4066Sahrens 	if (is_attr) {
24530a586ceaSMark Shellenbaum 		uint64_t	parent;
24540a586ceaSMark Shellenbaum 
24550a586ceaSMark Shellenbaum 		if ((error = sa_lookup(zp->z_sa_hdl,
24560a586ceaSMark Shellenbaum 		    SA_ZPL_PARENT(zp->z_zfsvfs), &parent,
24570a586ceaSMark Shellenbaum 		    sizeof (parent))) != 0)
24580a586ceaSMark Shellenbaum 			return (error);
24590a586ceaSMark Shellenbaum 
2460fa9e4066Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
24610a586ceaSMark Shellenbaum 		    parent, &xzp)) != 0)	{
2462fa9e4066Sahrens 			return (error);
2463fa9e4066Sahrens 		}
2464da6c28aaSamw 
2465fa9e4066Sahrens 		check_zp = xzp;
2466da6c28aaSamw 
2467fa9e4066Sahrens 		/*
2468fa9e4066Sahrens 		 * fixup mode to map to xattr perms
2469fa9e4066Sahrens 		 */
2470fa9e4066Sahrens 
2471fa9e4066Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
2472fa9e4066Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
2473fa9e4066Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
2474fa9e4066Sahrens 		}
2475fa9e4066Sahrens 
2476fa9e4066Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
2477fa9e4066Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
2478fa9e4066Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
2479fa9e4066Sahrens 		}
2480fa9e4066Sahrens 	}
2481fa9e4066Sahrens 
2482f1696b23SMark Shellenbaum 	owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
2483134a1f4eSCasper H.S. Dik 	/*
2484134a1f4eSCasper H.S. Dik 	 * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
2485134a1f4eSCasper H.S. Dik 	 * in needed_bits.  Map the bits mapped by working_mode (currently
2486134a1f4eSCasper H.S. Dik 	 * missing) in missing_bits.
2487134a1f4eSCasper H.S. Dik 	 * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
2488134a1f4eSCasper H.S. Dik 	 * needed_bits.
2489134a1f4eSCasper H.S. Dik 	 */
2490134a1f4eSCasper H.S. Dik 	needed_bits = 0;
2491134a1f4eSCasper H.S. Dik 
2492134a1f4eSCasper H.S. Dik 	working_mode = mode;
249370561057SGordon Ross 
2494134a1f4eSCasper H.S. Dik 	if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
2495f1696b23SMark Shellenbaum 	    owner == crgetuid(cr))
2496134a1f4eSCasper H.S. Dik 		working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
2497134a1f4eSCasper H.S. Dik 
2498134a1f4eSCasper H.S. Dik 	if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
2499134a1f4eSCasper H.S. Dik 	    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
2500134a1f4eSCasper H.S. Dik 		needed_bits |= VREAD;
2501134a1f4eSCasper H.S. Dik 	if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
2502134a1f4eSCasper H.S. Dik 	    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
2503134a1f4eSCasper H.S. Dik 		needed_bits |= VWRITE;
2504134a1f4eSCasper H.S. Dik 	if (working_mode & ACE_EXECUTE)
2505134a1f4eSCasper H.S. Dik 		needed_bits |= VEXEC;
2506134a1f4eSCasper H.S. Dik 
2507da6c28aaSamw 	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
2508da6c28aaSamw 	    &check_privs, skipaclchk, cr)) == 0) {
2509da6c28aaSamw 		if (is_attr)
2510da6c28aaSamw 			VN_RELE(ZTOV(xzp));
2511f1696b23SMark Shellenbaum 		return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
2512134a1f4eSCasper H.S. Dik 		    needed_bits, needed_bits));
2513da6c28aaSamw 	}
2514fa9e4066Sahrens 
2515e0d35c44Smarks 	if (error && !check_privs) {
2516fa9e4066Sahrens 		if (is_attr)
2517fa9e4066Sahrens 			VN_RELE(ZTOV(xzp));
2518fa9e4066Sahrens 		return (error);
2519fa9e4066Sahrens 	}
2520fa9e4066Sahrens 
2521da6c28aaSamw 	if (error && (flags & V_APPEND)) {
2522da6c28aaSamw 		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
2523da6c28aaSamw 	}
2524da6c28aaSamw 
2525da6c28aaSamw 	if (error && check_privs) {
2526da6c28aaSamw 		mode_t		checkmode = 0;
2527da6c28aaSamw 
2528da6c28aaSamw 		/*
2529da6c28aaSamw 		 * First check for implicit owner permission on
2530da6c28aaSamw 		 * read_acl/read_attributes
2531da6c28aaSamw 		 */
2532da6c28aaSamw 
2533da6c28aaSamw 		error = 0;
2534da6c28aaSamw 		ASSERT(working_mode != 0);
2535da6c28aaSamw 
2536da6c28aaSamw 		if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
2537f1696b23SMark Shellenbaum 		    owner == crgetuid(cr)))
2538da6c28aaSamw 			working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
2539da6c28aaSamw 
2540da6c28aaSamw 		if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
254147def0dcSMark Shellenbaum 		    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
2542da6c28aaSamw 			checkmode |= VREAD;
2543da6c28aaSamw 		if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
254447def0dcSMark Shellenbaum 		    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
2545da6c28aaSamw 			checkmode |= VWRITE;
2546da6c28aaSamw 		if (working_mode & ACE_EXECUTE)
2547da6c28aaSamw 			checkmode |= VEXEC;
2548da6c28aaSamw 
2549f1696b23SMark Shellenbaum 		error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
2550134a1f4eSCasper H.S. Dik 		    needed_bits & ~checkmode, needed_bits);
2551da6c28aaSamw 
2552da6c28aaSamw 		if (error == 0 && (working_mode & ACE_WRITE_OWNER))
2553f1696b23SMark Shellenbaum 			error = secpolicy_vnode_chown(cr, owner);
2554da6c28aaSamw 		if (error == 0 && (working_mode & ACE_WRITE_ACL))
255570561057SGordon Ross 			error = secpolicy_vnode_setdac3(cr, owner,
255670561057SGordon Ross 			    zp->z_zfsvfs->z_acl_implicit);
2557da6c28aaSamw 
2558da6c28aaSamw 		if (error == 0 && (working_mode &
2559da6c28aaSamw 		    (ACE_DELETE|ACE_DELETE_CHILD)))
2560da6c28aaSamw 			error = secpolicy_vnode_remove(cr);
2561da6c28aaSamw 
256247def0dcSMark Shellenbaum 		if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
2563f1696b23SMark Shellenbaum 			error = secpolicy_vnode_chown(cr, owner);
256447def0dcSMark Shellenbaum 		}
2565da6c28aaSamw 		if (error == 0) {
2566da6c28aaSamw 			/*
2567da6c28aaSamw 			 * See if any bits other than those already checked
2568da6c28aaSamw 			 * for are still present.  If so then return EACCES
2569da6c28aaSamw 			 */
2570da6c28aaSamw 			if (working_mode & ~(ZFS_CHECKED_MASKS)) {
2571be6fd75aSMatthew Ahrens 				error = SET_ERROR(EACCES);
2572da6c28aaSamw 			}
2573da6c28aaSamw 		}
2574134a1f4eSCasper H.S. Dik 	} else if (error == 0) {
2575f1696b23SMark Shellenbaum 		error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
2576134a1f4eSCasper H.S. Dik 		    needed_bits, needed_bits);
2577fa9e4066Sahrens 	}
2578fa9e4066Sahrens 
2579134a1f4eSCasper H.S. Dik 
2580fa9e4066Sahrens 	if (is_attr)
2581fa9e4066Sahrens 		VN_RELE(ZTOV(xzp));
2582fa9e4066Sahrens 
2583fa9e4066Sahrens 	return (error);
2584fa9e4066Sahrens }
2585fa9e4066Sahrens 
2586fa9e4066Sahrens /*
2587da6c28aaSamw  * Translate traditional unix VREAD/VWRITE/VEXEC mode into
2588da6c28aaSamw  * native ACL format and call zfs_zaccess()
2589fa9e4066Sahrens  */
2590fa9e4066Sahrens int
zfs_zaccess_rwx(znode_t * zp,mode_t mode,int flags,cred_t * cr)2591da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
2592fa9e4066Sahrens {
2593da6c28aaSamw 	return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
2594fa9e4066Sahrens }
2595fa9e4066Sahrens 
2596fa9e4066Sahrens /*
2597da6c28aaSamw  * Access function for secpolicy_vnode_setattr
2598fa9e4066Sahrens  */
2599fa9e4066Sahrens int
zfs_zaccess_unix(znode_t * zp,mode_t mode,cred_t * cr)2600da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
2601fa9e4066Sahrens {
2602fa9e4066Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
2603fa9e4066Sahrens 
2604da6c28aaSamw 	return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
2605fa9e4066Sahrens }
2606fa9e4066Sahrens 
26071eb4e906SKevin Crowe /* See zfs_zaccess_delete() */
26081eb4e906SKevin Crowe int zfs_write_implies_delete_child = 1;
260947db7e74Smarks 
2610fa9e4066Sahrens /*
26111eb4e906SKevin Crowe  * Determine whether delete access should be granted.
2612fa9e4066Sahrens  *
2613da412744SKevin Crowe  * The following chart outlines how we handle delete permissions which is
2614da412744SKevin Crowe  * how recent versions of windows (Windows 2008) handles it.  The efficiency
2615da412744SKevin Crowe  * comes from not having to check the parent ACL where the object itself grants
2616da412744SKevin Crowe  * delete:
2617fa9e4066Sahrens  *
2618fa9e4066Sahrens  *      -------------------------------------------------------
26191eb4e906SKevin Crowe  *      |   Parent Dir  |      Target Object Permissions      |
2620fa9e4066Sahrens  *      |  permissions  |                                     |
2621fa9e4066Sahrens  *      -------------------------------------------------------
2622fa9e4066Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
2623fa9e4066Sahrens  *      |               |  Delete    |  Delete   | unspecified|
2624fa9e4066Sahrens  *      -------------------------------------------------------
2625da412744SKevin Crowe  *      | ACL Allows    | Permit     | Deny *    | Permit     |
2626da412744SKevin Crowe  *      | DELETE_CHILD  |            |           |            |
2627fa9e4066Sahrens  *      -------------------------------------------------------
2628da412744SKevin Crowe  *      | ACL Denies    | Permit     | Deny      | Deny       |
2629da412744SKevin Crowe  *      | DELETE_CHILD  |            |           |            |
2630fa9e4066Sahrens  *      -------------------------------------------------------
2631fa9e4066Sahrens  *      | ACL specifies |            |           |            |
2632da412744SKevin Crowe  *      | only allow    | Permit     | Deny *    | Permit     |
2633fa9e4066Sahrens  *      | write and     |            |           |            |
2634fa9e4066Sahrens  *      | execute       |            |           |            |
2635fa9e4066Sahrens  *      -------------------------------------------------------
2636fa9e4066Sahrens  *      | ACL denies    |            |           |            |
2637fa9e4066Sahrens  *      | write and     | Permit     | Deny      | Deny       |
2638fa9e4066Sahrens  *      | execute       |            |           |            |
2639fa9e4066Sahrens  *      -------------------------------------------------------
2640fa9e4066Sahrens  *         ^
2641fa9e4066Sahrens  *         |
26421eb4e906SKevin Crowe  *         Re. execute permission on the directory:  if that's missing,
26431eb4e906SKevin Crowe  *	   the vnode lookup of the target will fail before we get here.
26441eb4e906SKevin Crowe  *
2645da412744SKevin Crowe  * Re [*] in the table above:  NFSv4 would normally Permit delete for
2646da412744SKevin Crowe  * these two cells of the matrix.
2647da412744SKevin Crowe  * See acl.h for notes on which ACE_... flags should be checked for which
2648da412744SKevin Crowe  * operations.  Specifically, the NFSv4 committee recommendation is in
2649da412744SKevin Crowe  * conflict with the Windows interpretation of DENY ACEs, where DENY ACEs
26501eb4e906SKevin Crowe  * should take precedence ahead of ALLOW ACEs.
26511eb4e906SKevin Crowe  *
2652da412744SKevin Crowe  * This implementation always consults the target object's ACL first.
2653da412744SKevin Crowe  * If a DENY ACE is present on the target object that specifies ACE_DELETE,
2654da412744SKevin Crowe  * delete access is denied.  If an ALLOW ACE with ACE_DELETE is present on
2655da412744SKevin Crowe  * the target object, access is allowed.  If and only if no entries with
2656da412744SKevin Crowe  * ACE_DELETE are present in the object's ACL, check the container's ACL
2657da412744SKevin Crowe  * for entries with ACE_DELETE_CHILD.
26581eb4e906SKevin Crowe  *
2659da412744SKevin Crowe  * A summary of the logic implemented from the table above is as follows:
2660fa9e4066Sahrens  *
26611eb4e906SKevin Crowe  * First check for DENY ACEs that apply.
26621eb4e906SKevin Crowe  * If either target or container has a deny, EACCES.
26631eb4e906SKevin Crowe  *
26641eb4e906SKevin Crowe  * Delete access can then be summarized as follows:
26651eb4e906SKevin Crowe  * 1: The object to be deleted grants ACE_DELETE, or
26661eb4e906SKevin Crowe  * 2: The containing directory grants ACE_DELETE_CHILD.
26671eb4e906SKevin Crowe  * In a Windows system, that would be the end of the story.
26681eb4e906SKevin Crowe  * In this system, (2) has some complications...
26691eb4e906SKevin Crowe  * 2a: "sticky" bit on a directory adds restrictions, and
26701eb4e906SKevin Crowe  * 2b: existing ACEs from previous versions of ZFS may
26711eb4e906SKevin Crowe  * not carry ACE_DELETE_CHILD where they should, so we
26721eb4e906SKevin Crowe  * also allow delete when ACE_WRITE_DATA is granted.
26731eb4e906SKevin Crowe  *
26741eb4e906SKevin Crowe  * Note: 2b is technically a work-around for a prior bug,
26751eb4e906SKevin Crowe  * which hopefully can go away some day.  For those who
26761eb4e906SKevin Crowe  * no longer need the work around, and for testing, this
26771eb4e906SKevin Crowe  * work-around is made conditional via the tunable:
26781eb4e906SKevin Crowe  * zfs_write_implies_delete_child
2679fa9e4066Sahrens  */
2680fa9e4066Sahrens int
zfs_zaccess_delete(znode_t * dzp,znode_t * zp,cred_t * cr)2681fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
2682fa9e4066Sahrens {
26831eb4e906SKevin Crowe 	uint32_t wanted_dirperms;
2684da6c28aaSamw 	uint32_t dzp_working_mode = 0;
2685da6c28aaSamw 	uint32_t zp_working_mode = 0;
2686fa9e4066Sahrens 	int dzp_error, zp_error;
26871eb4e906SKevin Crowe 	boolean_t dzpcheck_privs;
26881eb4e906SKevin Crowe 	boolean_t zpcheck_privs;
2689fa9e4066Sahrens 
26900a586ceaSMark Shellenbaum 	if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
2691be6fd75aSMatthew Ahrens 		return (SET_ERROR(EPERM));
2692da6c28aaSamw 
269323d5bb1fSmarks 	/*
26941eb4e906SKevin Crowe 	 * Case 1:
26951eb4e906SKevin Crowe 	 * If target object grants ACE_DELETE then we are done.  This is
26961eb4e906SKevin Crowe 	 * indicated by a return value of 0.  For this case we don't worry
26971eb4e906SKevin Crowe 	 * about the sticky bit because sticky only applies to the parent
26981eb4e906SKevin Crowe 	 * directory and this is the child access result.
26991eb4e906SKevin Crowe 	 *
27001eb4e906SKevin Crowe 	 * If we encounter a DENY ACE here, we're also done (EACCES).
27011eb4e906SKevin Crowe 	 * Note that if we hit a DENY ACE here (on the target) it should
27021eb4e906SKevin Crowe 	 * take precedence over a DENY ACE on the container, so that when
27031eb4e906SKevin Crowe 	 * we have more complete auditing support we will be able to
27041eb4e906SKevin Crowe 	 * report an access failure against the specific target.
27051eb4e906SKevin Crowe 	 * (This is part of why we're checking the target first.)
270623d5bb1fSmarks 	 */
27071eb4e906SKevin Crowe 	zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
27081eb4e906SKevin Crowe 	    &zpcheck_privs, B_FALSE, cr);
27091eb4e906SKevin Crowe 	if (zp_error == EACCES) {
27101eb4e906SKevin Crowe 		/* We hit a DENY ACE. */
27111eb4e906SKevin Crowe 		if (!zpcheck_privs)
27121eb4e906SKevin Crowe 			return (SET_ERROR(zp_error));
27131eb4e906SKevin Crowe 		return (secpolicy_vnode_remove(cr));
27141eb4e906SKevin Crowe 
27151eb4e906SKevin Crowe 	}
27161eb4e906SKevin Crowe 	if (zp_error == 0)
271723d5bb1fSmarks 		return (0);
2718fa9e4066Sahrens 
271923d5bb1fSmarks 	/*
27201eb4e906SKevin Crowe 	 * Case 2:
27211eb4e906SKevin Crowe 	 * If the containing directory grants ACE_DELETE_CHILD,
27221eb4e906SKevin Crowe 	 * or we're in backward compatibility mode and the
27231eb4e906SKevin Crowe 	 * containing directory has ACE_WRITE_DATA, allow.
27241eb4e906SKevin Crowe 	 * Case 2b is handled with wanted_dirperms.
272523d5bb1fSmarks 	 */
27261eb4e906SKevin Crowe 	wanted_dirperms = ACE_DELETE_CHILD;
27271eb4e906SKevin Crowe 	if (zfs_write_implies_delete_child)
27281eb4e906SKevin Crowe 		wanted_dirperms |= ACE_WRITE_DATA;
27291eb4e906SKevin Crowe 	dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
27301eb4e906SKevin Crowe 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
27311eb4e906SKevin Crowe 	if (dzp_error == EACCES) {
27321eb4e906SKevin Crowe 		/* We hit a DENY ACE. */
27331eb4e906SKevin Crowe 		if (!dzpcheck_privs)
27341eb4e906SKevin Crowe 			return (SET_ERROR(dzp_error));
27351eb4e906SKevin Crowe 		return (secpolicy_vnode_remove(cr));
27361eb4e906SKevin Crowe 	}
2737fa9e4066Sahrens 
2738fa9e4066Sahrens 	/*
27391eb4e906SKevin Crowe 	 * Cases 2a, 2b (continued)
27407ed7e920Smarks 	 *
27411eb4e906SKevin Crowe 	 * Note: dzp_working_mode now contains any permissions
27421eb4e906SKevin Crowe 	 * that were NOT granted.  Therefore, if any of the
27431eb4e906SKevin Crowe 	 * wanted_dirperms WERE granted, we will have:
27441eb4e906SKevin Crowe 	 *   dzp_working_mode != wanted_dirperms
27451eb4e906SKevin Crowe 	 * We're really asking if ANY of those permissions
27461eb4e906SKevin Crowe 	 * were granted, and if so, grant delete access.
274747db7e74Smarks 	 */
27481eb4e906SKevin Crowe 	if (dzp_working_mode != wanted_dirperms)
27491eb4e906SKevin Crowe 		dzp_error = 0;
275047db7e74Smarks 
2751fa9e4066Sahrens 	/*
27521eb4e906SKevin Crowe 	 * dzp_error is 0 if the container granted us permissions to "modify".
27531eb4e906SKevin Crowe 	 * If we do not have permission via one or more ACEs, our current
27541eb4e906SKevin Crowe 	 * privileges may still permit us to modify the container.
27551eb4e906SKevin Crowe 	 *
27561eb4e906SKevin Crowe 	 * dzpcheck_privs is false when i.e. the FS is read-only.
27571eb4e906SKevin Crowe 	 * Otherwise, do privilege checks for the container.
2758fa9e4066Sahrens 	 */
27591eb4e906SKevin Crowe 	if (dzp_error != 0 && dzpcheck_privs) {
27601eb4e906SKevin Crowe 		uid_t owner;
2761fa9e4066Sahrens 
27621eb4e906SKevin Crowe 		/*
27631eb4e906SKevin Crowe 		 * The secpolicy call needs the requested access and
27641eb4e906SKevin Crowe 		 * the current access mode of the container, but it
27651eb4e906SKevin Crowe 		 * only knows about Unix-style modes (VEXEC, VWRITE),
27661eb4e906SKevin Crowe 		 * so this must condense the fine-grained ACE bits into
27671eb4e906SKevin Crowe 		 * Unix modes.
27681eb4e906SKevin Crowe 		 *
27691eb4e906SKevin Crowe 		 * The VEXEC flag is easy, because we know that has
27701eb4e906SKevin Crowe 		 * always been checked before we get here (during the
27711eb4e906SKevin Crowe 		 * lookup of the target vnode).  The container has not
27721eb4e906SKevin Crowe 		 * granted us permissions to "modify", so we do not set
27731eb4e906SKevin Crowe 		 * the VWRITE flag in the current access mode.
27741eb4e906SKevin Crowe 		 */
27751eb4e906SKevin Crowe 		owner = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr,
27761eb4e906SKevin Crowe 		    ZFS_OWNER);
27771eb4e906SKevin Crowe 		dzp_error = secpolicy_vnode_access2(cr, ZTOV(dzp),
27781eb4e906SKevin Crowe 		    owner, VEXEC, VWRITE|VEXEC);
27791eb4e906SKevin Crowe 	}
27801eb4e906SKevin Crowe 	if (dzp_error != 0) {
27811eb4e906SKevin Crowe 		/*
27821eb4e906SKevin Crowe 		 * Note: We may have dzp_error = -1 here (from
27831eb4e906SKevin Crowe 		 * zfs_zacess_common).  Don't return that.
27841eb4e906SKevin Crowe 		 */
27851eb4e906SKevin Crowe 		return (SET_ERROR(EACCES));
27861eb4e906SKevin Crowe 	}
27877ed7e920Smarks 
2788fa9e4066Sahrens 	/*
27891eb4e906SKevin Crowe 	 * At this point, we know that the directory permissions allow
27901eb4e906SKevin Crowe 	 * us to modify, but we still need to check for the additional
27911eb4e906SKevin Crowe 	 * restrictions that apply when the "sticky bit" is set.
27921eb4e906SKevin Crowe 	 *
27931eb4e906SKevin Crowe 	 * Yes, zfs_sticky_remove_access() also checks this bit, but
27941eb4e906SKevin Crowe 	 * checking it here and skipping the call below is nice when
27951eb4e906SKevin Crowe 	 * you're watching all of this with dtrace.
2796fa9e4066Sahrens 	 */
27971eb4e906SKevin Crowe 	if ((dzp->z_mode & S_ISVTX) == 0)
27981eb4e906SKevin Crowe 		return (0);
2799fa9e4066Sahrens 
28001eb4e906SKevin Crowe 	/*
28011eb4e906SKevin Crowe 	 * zfs_sticky_remove_access will succeed if:
28021eb4e906SKevin Crowe 	 * 1. The sticky bit is absent.
28031eb4e906SKevin Crowe 	 * 2. We pass the sticky bit restrictions.
28041eb4e906SKevin Crowe 	 * 3. We have privileges that always allow file removal.
28051eb4e906SKevin Crowe 	 */
28061eb4e906SKevin Crowe 	return (zfs_sticky_remove_access(dzp, zp, cr));
2807fa9e4066Sahrens }
2808fa9e4066Sahrens 
2809fa9e4066Sahrens int
zfs_zaccess_rename(znode_t * sdzp,znode_t * szp,znode_t * tdzp,znode_t * tzp,cred_t * cr)2810fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
2811fa9e4066Sahrens     znode_t *tzp, cred_t *cr)
2812fa9e4066Sahrens {
2813fa9e4066Sahrens 	int add_perm;
2814fa9e4066Sahrens 	int error;
2815fa9e4066Sahrens 
28160a586ceaSMark Shellenbaum 	if (szp->z_pflags & ZFS_AV_QUARANTINED)
2817be6fd75aSMatthew Ahrens 		return (SET_ERROR(EACCES));
2818da6c28aaSamw 
2819fa9e4066Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
2820fa9e4066Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
2821fa9e4066Sahrens 
2822fa9e4066Sahrens 	/*
2823fa9e4066Sahrens 	 * Rename permissions are combination of delete permission +
2824fa9e4066Sahrens 	 * add file/subdir permission.
2825fa9e4066Sahrens 	 */
2826fa9e4066Sahrens 
2827fa9e4066Sahrens 	/*
2828fa9e4066Sahrens 	 * first make sure we do the delete portion.
2829fa9e4066Sahrens 	 *
2830fa9e4066Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
2831fa9e4066Sahrens 	 */
2832fa9e4066Sahrens 
2833fa9e4066Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
2834fa9e4066Sahrens 		return (error);
2835fa9e4066Sahrens 
2836fa9e4066Sahrens 	/*
2837fa9e4066Sahrens 	 * If we have a tzp, see if we can delete it?
2838fa9e4066Sahrens 	 */
2839fa9e4066Sahrens 	if (tzp) {
2840fa9e4066Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
2841fa9e4066Sahrens 			return (error);
2842fa9e4066Sahrens 	}
2843fa9e4066Sahrens 
2844fa9e4066Sahrens 	/*
2845fa9e4066Sahrens 	 * Now check for add permissions
2846fa9e4066Sahrens 	 */
2847da6c28aaSamw 	error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
2848fa9e4066Sahrens 
2849fa9e4066Sahrens 	return (error);
2850fa9e4066Sahrens }
2851