xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5*ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6*ea8dc4b6Seschrock  * 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 /*
2284c5a155Smarks  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/types.h>
29fa9e4066Sahrens #include <sys/param.h>
30fa9e4066Sahrens #include <sys/time.h>
31fa9e4066Sahrens #include <sys/systm.h>
32fa9e4066Sahrens #include <sys/sysmacros.h>
33fa9e4066Sahrens #include <sys/resource.h>
34fa9e4066Sahrens #include <sys/vfs.h>
35fa9e4066Sahrens #include <sys/vnode.h>
36fa9e4066Sahrens #include <sys/file.h>
37fa9e4066Sahrens #include <sys/stat.h>
38fa9e4066Sahrens #include <sys/kmem.h>
39fa9e4066Sahrens #include <sys/cmn_err.h>
40fa9e4066Sahrens #include <sys/errno.h>
41fa9e4066Sahrens #include <sys/unistd.h>
42fa9e4066Sahrens #include <sys/fs/zfs.h>
43fa9e4066Sahrens #include <sys/mode.h>
44fa9e4066Sahrens #include <sys/policy.h>
45fa9e4066Sahrens #include <sys/zfs_znode.h>
46fa9e4066Sahrens #include <sys/zfs_acl.h>
47fa9e4066Sahrens #include <sys/zfs_dir.h>
48fa9e4066Sahrens #include <sys/zfs_vfsops.h>
49fa9e4066Sahrens #include <sys/dmu.h>
50fa9e4066Sahrens #include <sys/zap.h>
51fa9e4066Sahrens #include <util/qsort.h>
52fa9e4066Sahrens #include "fs/fs_subr.h"
53fa9e4066Sahrens #include <acl/acl_common.h>
54fa9e4066Sahrens 
55fa9e4066Sahrens #define	ALLOW	ACE_ACCESS_ALLOWED_ACE_TYPE
56fa9e4066Sahrens #define	DENY	ACE_ACCESS_DENIED_ACE_TYPE
57fa9e4066Sahrens 
58fa9e4066Sahrens #define	OWNING_GROUP		(ACE_GROUP|ACE_IDENTIFIER_GROUP)
59fa9e4066Sahrens #define	EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
60fa9e4066Sahrens     ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
61fa9e4066Sahrens #define	EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
62fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
63fa9e4066Sahrens #define	OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
64fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
65fa9e4066Sahrens #define	WRITE_MASK (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS| \
66fa9e4066Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|ACE_WRITE_OWNER)
67fa9e4066Sahrens 
68fa9e4066Sahrens #define	OGE_CLEAR	(ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
69fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
70fa9e4066Sahrens 
71fa9e4066Sahrens #define	OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
72fa9e4066Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
73fa9e4066Sahrens 
74fa9e4066Sahrens #define	ALL_INHERIT	(ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
75fa9e4066Sahrens     ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
76fa9e4066Sahrens 
77fa9e4066Sahrens #define	SECURE_NO_INHERIT	(ACE_WRITE_ACL|ACE_WRITE_OWNER)
78fa9e4066Sahrens 
79fa9e4066Sahrens #define	OGE_PAD	6		/* traditional owner/group/everyone ACES */
80fa9e4066Sahrens 
81fa9e4066Sahrens static int zfs_ace_can_use(znode_t *zp, ace_t *);
82fa9e4066Sahrens 
83fa9e4066Sahrens static zfs_acl_t *
84fa9e4066Sahrens zfs_acl_alloc(int slots)
85fa9e4066Sahrens {
86fa9e4066Sahrens 	zfs_acl_t *aclp;
87fa9e4066Sahrens 
88fa9e4066Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
89fa9e4066Sahrens 	if (slots != 0) {
90fa9e4066Sahrens 		aclp->z_acl = kmem_alloc(ZFS_ACL_SIZE(slots), KM_SLEEP);
91fa9e4066Sahrens 		aclp->z_acl_count = 0;
92fa9e4066Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
93fa9e4066Sahrens 	} else {
94fa9e4066Sahrens 		aclp->z_state = 0;
95fa9e4066Sahrens 	}
96fa9e4066Sahrens 	aclp->z_slots = slots;
97fa9e4066Sahrens 	return (aclp);
98fa9e4066Sahrens }
99fa9e4066Sahrens 
100fa9e4066Sahrens void
101fa9e4066Sahrens zfs_acl_free(zfs_acl_t *aclp)
102fa9e4066Sahrens {
103fa9e4066Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED) {
104fa9e4066Sahrens 		kmem_free(aclp->z_acl, ZFS_ACL_SIZE(aclp->z_slots));
105fa9e4066Sahrens 	}
106fa9e4066Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
107fa9e4066Sahrens }
108fa9e4066Sahrens 
109fa9e4066Sahrens static uint32_t
110fa9e4066Sahrens zfs_v4_to_unix(uint32_t access_mask)
111fa9e4066Sahrens {
112fa9e4066Sahrens 	uint32_t new_mask = 0;
113fa9e4066Sahrens 
114fa9e4066Sahrens 	if (access_mask & (ACE_READ_DATA | ACE_LIST_DIRECTORY))
115fa9e4066Sahrens 		new_mask |= S_IROTH;
116fa9e4066Sahrens 	if (access_mask & (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_ADD_FILE))
117fa9e4066Sahrens 		new_mask |= S_IWOTH;
118fa9e4066Sahrens 	if (access_mask & (ACE_EXECUTE|ACE_READ_NAMED_ATTRS))
119fa9e4066Sahrens 		new_mask |= S_IXOTH;
120fa9e4066Sahrens 
121fa9e4066Sahrens 	return (new_mask);
122fa9e4066Sahrens }
123fa9e4066Sahrens 
124fa9e4066Sahrens /*
125fa9e4066Sahrens  * Convert unix access mask to v4 access mask
126fa9e4066Sahrens  */
127fa9e4066Sahrens static uint32_t
128fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask)
129fa9e4066Sahrens {
130fa9e4066Sahrens 	uint32_t new_mask = 0;
131fa9e4066Sahrens 
132fa9e4066Sahrens 	if (access_mask & 01)
133fa9e4066Sahrens 		new_mask |= (ACE_EXECUTE);
134fa9e4066Sahrens 	if (access_mask & 02) {
135fa9e4066Sahrens 		new_mask |= (ACE_WRITE_DATA);
136fa9e4066Sahrens 	} if (access_mask & 04) {
137fa9e4066Sahrens 		new_mask |= ACE_READ_DATA;
138fa9e4066Sahrens 	}
139fa9e4066Sahrens 	return (new_mask);
140fa9e4066Sahrens }
141fa9e4066Sahrens 
142fa9e4066Sahrens static void
143fa9e4066Sahrens zfs_set_ace(ace_t *zacep, uint32_t access_mask, int access_type,
144fa9e4066Sahrens     uid_t uid, int entry_type)
145fa9e4066Sahrens {
146fa9e4066Sahrens 	zacep->a_access_mask = access_mask;
147fa9e4066Sahrens 	zacep->a_type = access_type;
148fa9e4066Sahrens 	zacep->a_who = uid;
149fa9e4066Sahrens 	zacep->a_flags = entry_type;
150fa9e4066Sahrens }
151fa9e4066Sahrens 
152fa9e4066Sahrens static uint64_t
153fa9e4066Sahrens zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp)
154fa9e4066Sahrens {
155fa9e4066Sahrens 	int 	i;
156fa9e4066Sahrens 	int	entry_type;
157fa9e4066Sahrens 	mode_t	mode = (zp->z_phys->zp_mode &
158fa9e4066Sahrens 	    (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
159fa9e4066Sahrens 	mode_t	 seen = 0;
160fa9e4066Sahrens 	ace_t 	*acep;
161fa9e4066Sahrens 
162fa9e4066Sahrens 	for (i = 0, acep = aclp->z_acl;
163fa9e4066Sahrens 	    i != aclp->z_acl_count; i++, acep++) {
164fa9e4066Sahrens 		entry_type = (acep->a_flags & 0xf040);
165fa9e4066Sahrens 		if (entry_type == ACE_OWNER) {
166fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA) &&
167fa9e4066Sahrens 			    (!(seen & S_IRUSR))) {
168fa9e4066Sahrens 				seen |= S_IRUSR;
169fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
170fa9e4066Sahrens 					mode |= S_IRUSR;
171fa9e4066Sahrens 				}
172fa9e4066Sahrens 			}
173fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA) &&
174fa9e4066Sahrens 			    (!(seen & S_IWUSR))) {
175fa9e4066Sahrens 				seen |= S_IWUSR;
176fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
177fa9e4066Sahrens 					mode |= S_IWUSR;
178fa9e4066Sahrens 				}
179fa9e4066Sahrens 			}
180fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE) &&
181fa9e4066Sahrens 			    (!(seen & S_IXUSR))) {
182fa9e4066Sahrens 				seen |= S_IXUSR;
183fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
184fa9e4066Sahrens 					mode |= S_IXUSR;
185fa9e4066Sahrens 				}
186fa9e4066Sahrens 			}
187fa9e4066Sahrens 		} else if (entry_type == OWNING_GROUP) {
188fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA) &&
189fa9e4066Sahrens 			    (!(seen & S_IRGRP))) {
190fa9e4066Sahrens 				seen |= S_IRGRP;
191fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
192fa9e4066Sahrens 					mode |= S_IRGRP;
193fa9e4066Sahrens 				}
194fa9e4066Sahrens 			}
195fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA) &&
196fa9e4066Sahrens 			    (!(seen & S_IWGRP))) {
197fa9e4066Sahrens 				seen |= S_IWGRP;
198fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
199fa9e4066Sahrens 					mode |= S_IWGRP;
200fa9e4066Sahrens 				}
201fa9e4066Sahrens 			}
202fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE) &&
203fa9e4066Sahrens 			    (!(seen & S_IXGRP))) {
204fa9e4066Sahrens 				seen |= S_IXGRP;
205fa9e4066Sahrens 				if (acep->a_type == ALLOW) {
206fa9e4066Sahrens 					mode |= S_IXGRP;
207fa9e4066Sahrens 				}
208fa9e4066Sahrens 			}
209fa9e4066Sahrens 		} else if (entry_type == ACE_EVERYONE) {
210fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA)) {
211fa9e4066Sahrens 				if (!(seen & S_IRUSR)) {
212fa9e4066Sahrens 					seen |= S_IRUSR;
213fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
214fa9e4066Sahrens 						mode |= S_IRUSR;
215fa9e4066Sahrens 					}
216fa9e4066Sahrens 				}
217fa9e4066Sahrens 				if (!(seen & S_IRGRP)) {
218fa9e4066Sahrens 					seen |= S_IRGRP;
219fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
220fa9e4066Sahrens 						mode |= S_IRGRP;
221fa9e4066Sahrens 					}
222fa9e4066Sahrens 				}
223fa9e4066Sahrens 				if (!(seen & S_IROTH)) {
224fa9e4066Sahrens 					seen |= S_IROTH;
225fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
226fa9e4066Sahrens 						mode |= S_IROTH;
227fa9e4066Sahrens 					}
228fa9e4066Sahrens 				}
229fa9e4066Sahrens 			}
230fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA)) {
231fa9e4066Sahrens 				if (!(seen & S_IWUSR)) {
232fa9e4066Sahrens 					seen |= S_IWUSR;
233fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
234fa9e4066Sahrens 						mode |= S_IWUSR;
235fa9e4066Sahrens 					}
236fa9e4066Sahrens 				}
237fa9e4066Sahrens 				if (!(seen & S_IWGRP)) {
238fa9e4066Sahrens 					seen |= S_IWGRP;
239fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
240fa9e4066Sahrens 						mode |= S_IWGRP;
241fa9e4066Sahrens 					}
242fa9e4066Sahrens 				}
243fa9e4066Sahrens 				if (!(seen & S_IWOTH)) {
244fa9e4066Sahrens 					seen |= S_IWOTH;
245fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
246fa9e4066Sahrens 						mode |= S_IWOTH;
247fa9e4066Sahrens 					}
248fa9e4066Sahrens 				}
249fa9e4066Sahrens 			}
250fa9e4066Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE)) {
251fa9e4066Sahrens 				if (!(seen & S_IXUSR)) {
252fa9e4066Sahrens 					seen |= S_IXUSR;
253fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
254fa9e4066Sahrens 						mode |= S_IXUSR;
255fa9e4066Sahrens 					}
256fa9e4066Sahrens 				}
257fa9e4066Sahrens 				if (!(seen & S_IXGRP)) {
258fa9e4066Sahrens 					seen |= S_IXGRP;
259fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
260fa9e4066Sahrens 						mode |= S_IXGRP;
261fa9e4066Sahrens 					}
262fa9e4066Sahrens 				}
263fa9e4066Sahrens 				if (!(seen & S_IXOTH)) {
264fa9e4066Sahrens 					seen |= S_IXOTH;
265fa9e4066Sahrens 					if (acep->a_type == ALLOW) {
266fa9e4066Sahrens 						mode |= S_IXOTH;
267fa9e4066Sahrens 					}
268fa9e4066Sahrens 				}
269fa9e4066Sahrens 			}
270fa9e4066Sahrens 		}
271fa9e4066Sahrens 	}
272fa9e4066Sahrens 	return (mode);
273fa9e4066Sahrens }
274fa9e4066Sahrens 
275fa9e4066Sahrens static zfs_acl_t *
276fa9e4066Sahrens zfs_acl_node_read_internal(znode_t *zp)
277fa9e4066Sahrens {
278fa9e4066Sahrens 	zfs_acl_t	*aclp;
279fa9e4066Sahrens 
280fa9e4066Sahrens 	aclp = zfs_acl_alloc(0);
281fa9e4066Sahrens 	aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
282fa9e4066Sahrens 	aclp->z_acl = &zp->z_phys->zp_acl.z_ace_data[0];
283fa9e4066Sahrens 
284fa9e4066Sahrens 	return (aclp);
285fa9e4066Sahrens }
286fa9e4066Sahrens 
287fa9e4066Sahrens /*
288fa9e4066Sahrens  * Read an external acl object.
289fa9e4066Sahrens  */
290*ea8dc4b6Seschrock static int
291*ea8dc4b6Seschrock zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp)
292fa9e4066Sahrens {
293fa9e4066Sahrens 	uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
294fa9e4066Sahrens 	zfs_acl_t	*aclp;
295*ea8dc4b6Seschrock 	int error;
296fa9e4066Sahrens 
297fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
298fa9e4066Sahrens 
299*ea8dc4b6Seschrock 	if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) {
300*ea8dc4b6Seschrock 		*aclpp = zfs_acl_node_read_internal(zp);
301*ea8dc4b6Seschrock 		return (0);
302*ea8dc4b6Seschrock 	}
303fa9e4066Sahrens 
304fa9e4066Sahrens 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_count);
305fa9e4066Sahrens 
306*ea8dc4b6Seschrock 	error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
307fa9e4066Sahrens 	    ZFS_ACL_SIZE(zp->z_phys->zp_acl.z_acl_count), aclp->z_acl);
308*ea8dc4b6Seschrock 	if (error != 0) {
309*ea8dc4b6Seschrock 		zfs_acl_free(aclp);
310*ea8dc4b6Seschrock 		return (error);
311*ea8dc4b6Seschrock 	}
312fa9e4066Sahrens 
313fa9e4066Sahrens 	aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
314fa9e4066Sahrens 
315*ea8dc4b6Seschrock 	*aclpp = aclp;
316*ea8dc4b6Seschrock 	return (0);
317fa9e4066Sahrens }
318fa9e4066Sahrens 
319fa9e4066Sahrens static boolean_t
320fa9e4066Sahrens zfs_acl_valid(znode_t *zp, ace_t *uace, int aclcnt, int *inherit)
321fa9e4066Sahrens {
322fa9e4066Sahrens 	ace_t 	*acep;
323fa9e4066Sahrens 	int i;
324fa9e4066Sahrens 
325fa9e4066Sahrens 	*inherit = 0;
326fa9e4066Sahrens 
327fa9e4066Sahrens 	if (aclcnt > MAX_ACL_ENTRIES || aclcnt <= 0) {
328fa9e4066Sahrens 		return (B_FALSE);
329fa9e4066Sahrens 	}
330fa9e4066Sahrens 
331fa9e4066Sahrens 	for (i = 0, acep = uace; i != aclcnt; i++, acep++) {
332fa9e4066Sahrens 
333fa9e4066Sahrens 		/*
334fa9e4066Sahrens 		 * first check type of entry
335fa9e4066Sahrens 		 */
336fa9e4066Sahrens 
337fa9e4066Sahrens 		switch (acep->a_flags & 0xf040) {
338fa9e4066Sahrens 		case ACE_OWNER:
339fa9e4066Sahrens 			acep->a_who = -1;
340fa9e4066Sahrens 			break;
341fa9e4066Sahrens 		case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
342fa9e4066Sahrens 		case ACE_IDENTIFIER_GROUP:
343fa9e4066Sahrens 			if (acep->a_flags & ACE_GROUP) {
344fa9e4066Sahrens 				acep->a_who = -1;
345fa9e4066Sahrens 			}
346fa9e4066Sahrens 			break;
347fa9e4066Sahrens 		case ACE_EVERYONE:
348fa9e4066Sahrens 			acep->a_who = -1;
349fa9e4066Sahrens 			break;
350fa9e4066Sahrens 		}
351fa9e4066Sahrens 
352fa9e4066Sahrens 		/*
353fa9e4066Sahrens 		 * next check inheritance level flags
354fa9e4066Sahrens 		 */
355fa9e4066Sahrens 
356fa9e4066Sahrens 		if (acep->a_type != ALLOW && acep->a_type != DENY)
357fa9e4066Sahrens 			return (B_FALSE);
358fa9e4066Sahrens 
359fa9e4066Sahrens 		/*
360fa9e4066Sahrens 		 * Only directories should have inheritance flags.
361fa9e4066Sahrens 		 */
362fa9e4066Sahrens 		if (ZTOV(zp)->v_type != VDIR && (acep->a_flags &
363fa9e4066Sahrens 		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
364fa9e4066Sahrens 		    ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
365fa9e4066Sahrens 			return (B_FALSE);
366fa9e4066Sahrens 		}
367fa9e4066Sahrens 
368fa9e4066Sahrens 		if (acep->a_flags &
369fa9e4066Sahrens 		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
370fa9e4066Sahrens 			*inherit = 1;
371fa9e4066Sahrens 
372fa9e4066Sahrens 		if (acep->a_flags &
373fa9e4066Sahrens 		    (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
374fa9e4066Sahrens 			if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
375fa9e4066Sahrens 			    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
376fa9e4066Sahrens 				return (B_FALSE);
377fa9e4066Sahrens 			}
378fa9e4066Sahrens 		}
379fa9e4066Sahrens 	}
380fa9e4066Sahrens 
381fa9e4066Sahrens 	return (B_TRUE);
382fa9e4066Sahrens }
383fa9e4066Sahrens /*
384fa9e4066Sahrens  * common code for setting acl's.
385fa9e4066Sahrens  *
386fa9e4066Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
387fa9e4066Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
388fa9e4066Sahrens  * already checked the acl and knows whether to inherit.
389fa9e4066Sahrens  */
390fa9e4066Sahrens int
391fa9e4066Sahrens zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
392fa9e4066Sahrens {
393fa9e4066Sahrens 	int 		inherit = 0;
394fa9e4066Sahrens 	int		error;
395fa9e4066Sahrens 	znode_phys_t	*zphys = zp->z_phys;
396fa9e4066Sahrens 	zfs_znode_acl_t	*zacl = &zphys->zp_acl;
397fa9e4066Sahrens 	uint32_t	acl_phys_size = ZFS_ACL_SIZE(aclp->z_acl_count);
398fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
399fa9e4066Sahrens 	uint64_t	aoid = zphys->zp_acl.z_acl_extern_obj;
400fa9e4066Sahrens 
401fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
402fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
403fa9e4066Sahrens 
404fa9e4066Sahrens 	if (ihp)
405fa9e4066Sahrens 		inherit = *ihp;		/* already determined by caller */
406fa9e4066Sahrens 	else if (!zfs_acl_valid(zp, aclp->z_acl,
407fa9e4066Sahrens 	    aclp->z_acl_count, &inherit)) {
408fa9e4066Sahrens 		return (EINVAL);
409fa9e4066Sahrens 	}
410fa9e4066Sahrens 
411fa9e4066Sahrens 	dmu_buf_will_dirty(zp->z_dbuf, tx);
412fa9e4066Sahrens 
413fa9e4066Sahrens 	/*
414fa9e4066Sahrens 	 * Will ACL fit internally?
415fa9e4066Sahrens 	 */
416fa9e4066Sahrens 	if (aclp->z_acl_count > ACE_SLOT_CNT) {
417fa9e4066Sahrens 		if (aoid == 0) {
418fa9e4066Sahrens 			aoid = dmu_object_alloc(zfsvfs->z_os,
419fa9e4066Sahrens 			    DMU_OT_ACL, acl_phys_size, DMU_OT_NONE, 0, tx);
420fa9e4066Sahrens 		} else {
421fa9e4066Sahrens 			(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
422fa9e4066Sahrens 			    acl_phys_size, 0, tx);
423fa9e4066Sahrens 		}
424fa9e4066Sahrens 		zphys->zp_acl.z_acl_extern_obj = aoid;
425fa9e4066Sahrens 		zphys->zp_acl.z_acl_count = aclp->z_acl_count;
426fa9e4066Sahrens 		dmu_write(zfsvfs->z_os, aoid, 0,
427fa9e4066Sahrens 		    acl_phys_size, aclp->z_acl, tx);
428fa9e4066Sahrens 	} else {
429fa9e4066Sahrens 		/*
430fa9e4066Sahrens 		 * Migrating back embedded?
431fa9e4066Sahrens 		 */
432fa9e4066Sahrens 		if (zphys->zp_acl.z_acl_extern_obj) {
433fa9e4066Sahrens 			error = dmu_object_free(zfsvfs->z_os,
434fa9e4066Sahrens 				zp->z_phys->zp_acl.z_acl_extern_obj, tx);
435fa9e4066Sahrens 			if (error)
436fa9e4066Sahrens 				return (error);
437fa9e4066Sahrens 			zphys->zp_acl.z_acl_extern_obj = 0;
438fa9e4066Sahrens 		}
439fa9e4066Sahrens 		bcopy(aclp->z_acl, zacl->z_ace_data,
440fa9e4066Sahrens 		    aclp->z_acl_count * sizeof (ace_t));
441fa9e4066Sahrens 		zacl->z_acl_count = aclp->z_acl_count;
442fa9e4066Sahrens 	}
443de122929Smarks 
444de122929Smarks 	zp->z_phys->zp_flags &= ~(ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE);
445de122929Smarks 	if (inherit) {
446fa9e4066Sahrens 		zp->z_phys->zp_flags |= ZFS_INHERIT_ACE;
447de122929Smarks 	} else if (ace_trivial(zacl->z_ace_data, zacl->z_acl_count) == 0) {
448de122929Smarks 		zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
449de122929Smarks 	}
450fa9e4066Sahrens 
451fa9e4066Sahrens 	zphys->zp_mode = zfs_mode_compute(zp, aclp);
452fa9e4066Sahrens 	zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
453fa9e4066Sahrens 
454fa9e4066Sahrens 	return (0);
455fa9e4066Sahrens }
456fa9e4066Sahrens 
457fa9e4066Sahrens /*
458fa9e4066Sahrens  * Create space for slots_needed ACEs to be append
459fa9e4066Sahrens  * to aclp.
460fa9e4066Sahrens  */
461fa9e4066Sahrens static void
462fa9e4066Sahrens zfs_acl_append(zfs_acl_t *aclp, int slots_needed)
463fa9e4066Sahrens {
464fa9e4066Sahrens 	ace_t	*newacep;
465fa9e4066Sahrens 	ace_t	*oldaclp;
466fa9e4066Sahrens 	int	slot_cnt;
467fa9e4066Sahrens 	int 	slots_left = aclp->z_slots - aclp->z_acl_count;
468fa9e4066Sahrens 
469fa9e4066Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED)
470fa9e4066Sahrens 		ASSERT(aclp->z_slots >= aclp->z_acl_count);
471fa9e4066Sahrens 	if (slots_left < slots_needed || aclp->z_state != ACL_DATA_ALLOCED) {
472fa9e4066Sahrens 		slot_cnt = aclp->z_slots +  1 + (slots_needed - slots_left);
473fa9e4066Sahrens 		newacep = kmem_alloc(ZFS_ACL_SIZE(slot_cnt), KM_SLEEP);
474fa9e4066Sahrens 		bcopy(aclp->z_acl, newacep,
475fa9e4066Sahrens 		    ZFS_ACL_SIZE(aclp->z_acl_count));
476fa9e4066Sahrens 		oldaclp = aclp->z_acl;
477fa9e4066Sahrens 		if (aclp->z_state == ACL_DATA_ALLOCED)
478fa9e4066Sahrens 			kmem_free(oldaclp, ZFS_ACL_SIZE(aclp->z_slots));
479fa9e4066Sahrens 		aclp->z_acl = newacep;
480fa9e4066Sahrens 		aclp->z_slots = slot_cnt;
481fa9e4066Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
482fa9e4066Sahrens 	}
483fa9e4066Sahrens }
484fa9e4066Sahrens 
485fa9e4066Sahrens /*
486fa9e4066Sahrens  * Remove "slot" ACE from aclp
487fa9e4066Sahrens  */
488fa9e4066Sahrens static void
489fa9e4066Sahrens zfs_ace_remove(zfs_acl_t *aclp, int slot)
490fa9e4066Sahrens {
491fa9e4066Sahrens 	if (aclp->z_acl_count > 1) {
492fa9e4066Sahrens 		(void) memmove(&aclp->z_acl[slot],
493fa9e4066Sahrens 		    &aclp->z_acl[slot +1], sizeof (ace_t) *
494fa9e4066Sahrens 		    (--aclp->z_acl_count - slot));
495fa9e4066Sahrens 	} else
496fa9e4066Sahrens 		aclp->z_acl_count--;
497fa9e4066Sahrens }
498fa9e4066Sahrens 
499fa9e4066Sahrens /*
500fa9e4066Sahrens  * Update access mask for prepended ACE
501fa9e4066Sahrens  *
502fa9e4066Sahrens  * This applies the "groupmask" value for aclmode property.
503fa9e4066Sahrens  */
504fa9e4066Sahrens static void
505fa9e4066Sahrens zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
506fa9e4066Sahrens {
507fa9e4066Sahrens 
508fa9e4066Sahrens 	int	rmask, wmask, xmask;
509fa9e4066Sahrens 	int	user_ace;
510fa9e4066Sahrens 
511fa9e4066Sahrens 	user_ace = (!(acep->a_flags &
512fa9e4066Sahrens 	    (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
513fa9e4066Sahrens 
514fa9e4066Sahrens 	if (user_ace && (acep->a_who == owner)) {
515fa9e4066Sahrens 		rmask = S_IRUSR;
516fa9e4066Sahrens 		wmask = S_IWUSR;
517fa9e4066Sahrens 		xmask = S_IXUSR;
518fa9e4066Sahrens 	} else {
519fa9e4066Sahrens 		rmask = S_IRGRP;
520fa9e4066Sahrens 		wmask = S_IWGRP;
521fa9e4066Sahrens 		xmask = S_IXGRP;
522fa9e4066Sahrens 	}
523fa9e4066Sahrens 
524fa9e4066Sahrens 	if (origacep->a_access_mask & ACE_READ_DATA) {
525fa9e4066Sahrens 		if (mode & rmask)
526fa9e4066Sahrens 			acep->a_access_mask &= ~ACE_READ_DATA;
527fa9e4066Sahrens 		else
528fa9e4066Sahrens 			acep->a_access_mask |= ACE_READ_DATA;
529fa9e4066Sahrens 	}
530fa9e4066Sahrens 
531fa9e4066Sahrens 	if (origacep->a_access_mask & ACE_WRITE_DATA) {
532fa9e4066Sahrens 		if (mode & wmask)
533fa9e4066Sahrens 			acep->a_access_mask &= ~ACE_WRITE_DATA;
534fa9e4066Sahrens 		else
535fa9e4066Sahrens 			acep->a_access_mask |= ACE_WRITE_DATA;
536fa9e4066Sahrens 	}
537fa9e4066Sahrens 
538fa9e4066Sahrens 	if (origacep->a_access_mask & ACE_APPEND_DATA) {
539fa9e4066Sahrens 		if (mode & wmask)
540fa9e4066Sahrens 			acep->a_access_mask &= ~ACE_APPEND_DATA;
541fa9e4066Sahrens 		else
542fa9e4066Sahrens 			acep->a_access_mask |= ACE_APPEND_DATA;
543fa9e4066Sahrens 	}
544fa9e4066Sahrens 
545fa9e4066Sahrens 	if (origacep->a_access_mask & ACE_EXECUTE) {
546fa9e4066Sahrens 		if (mode & xmask)
547fa9e4066Sahrens 			acep->a_access_mask &= ~ACE_EXECUTE;
548fa9e4066Sahrens 		else
549fa9e4066Sahrens 			acep->a_access_mask |= ACE_EXECUTE;
550fa9e4066Sahrens 	}
551fa9e4066Sahrens }
552fa9e4066Sahrens 
553fa9e4066Sahrens /*
554fa9e4066Sahrens  * Apply mode to canonical six ACEs.
555fa9e4066Sahrens  */
556fa9e4066Sahrens static void
557fa9e4066Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
558fa9e4066Sahrens {
559fa9e4066Sahrens 	int	cnt;
560fa9e4066Sahrens 	ace_t	*acep;
561fa9e4066Sahrens 
562fa9e4066Sahrens 	cnt = aclp->z_acl_count -1;
563fa9e4066Sahrens 	acep = aclp->z_acl;
564fa9e4066Sahrens 
565fa9e4066Sahrens 	/*
566fa9e4066Sahrens 	 * Fixup final ACEs to match the mode
567fa9e4066Sahrens 	 */
568fa9e4066Sahrens 
569fa9e4066Sahrens 	ASSERT(cnt >= 5);
570fa9e4066Sahrens 	adjust_ace_pair(&acep[cnt - 1], mode);	/* everyone@ */
571fa9e4066Sahrens 	adjust_ace_pair(&acep[cnt - 3], (mode & 0070) >> 3);	/* group@ */
572fa9e4066Sahrens 	adjust_ace_pair(&acep[cnt - 5], (mode & 0700) >> 6);	/* owner@ */
573fa9e4066Sahrens }
574fa9e4066Sahrens 
575fa9e4066Sahrens 
576fa9e4066Sahrens static int
577fa9e4066Sahrens zfs_acl_ace_match(ace_t *acep, int allow_deny, int type, int mask)
578fa9e4066Sahrens {
579fa9e4066Sahrens 	return (acep->a_access_mask == mask && acep->a_type == allow_deny &&
580fa9e4066Sahrens 	    ((acep->a_flags & 0xf040) == type));
581fa9e4066Sahrens }
582fa9e4066Sahrens 
583fa9e4066Sahrens /*
584fa9e4066Sahrens  * Can prepended ACE be reused?
585fa9e4066Sahrens  */
586fa9e4066Sahrens static int
587fa9e4066Sahrens zfs_reuse_deny(ace_t *acep, int i)
588fa9e4066Sahrens {
589fa9e4066Sahrens 	int okay_masks;
590fa9e4066Sahrens 
591fa9e4066Sahrens 	if (i < 1)
592fa9e4066Sahrens 		return (B_FALSE);
593fa9e4066Sahrens 
594fa9e4066Sahrens 	if (acep[i-1].a_type != DENY)
595fa9e4066Sahrens 		return (B_FALSE);
596fa9e4066Sahrens 
597fa9e4066Sahrens 	if (acep[i-1].a_flags != (acep[i].a_flags & ACE_IDENTIFIER_GROUP))
598fa9e4066Sahrens 		return (B_FALSE);
599fa9e4066Sahrens 
600fa9e4066Sahrens 	okay_masks = (acep[i].a_access_mask & OKAY_MASK_BITS);
601fa9e4066Sahrens 
602fa9e4066Sahrens 	if (acep[i-1].a_access_mask & ~okay_masks)
603fa9e4066Sahrens 		return (B_FALSE);
604fa9e4066Sahrens 
605fa9e4066Sahrens 	return (B_TRUE);
606fa9e4066Sahrens }
607fa9e4066Sahrens 
608fa9e4066Sahrens /*
609fa9e4066Sahrens  * Create space to prepend an ACE
610fa9e4066Sahrens  */
611fa9e4066Sahrens static void
612fa9e4066Sahrens zfs_acl_prepend(zfs_acl_t *aclp, int i)
613fa9e4066Sahrens {
614fa9e4066Sahrens 	ace_t	*oldaclp = NULL;
615fa9e4066Sahrens 	ace_t	*to, *from;
616fa9e4066Sahrens 	int	slots_left = aclp->z_slots - aclp->z_acl_count;
617fa9e4066Sahrens 	int	oldslots;
618fa9e4066Sahrens 	int	need_free = 0;
619fa9e4066Sahrens 
620fa9e4066Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED)
621fa9e4066Sahrens 		ASSERT(aclp->z_slots >= aclp->z_acl_count);
622fa9e4066Sahrens 
623fa9e4066Sahrens 	if (slots_left == 0 || aclp->z_state != ACL_DATA_ALLOCED) {
624fa9e4066Sahrens 
625fa9e4066Sahrens 		to = kmem_alloc(ZFS_ACL_SIZE(aclp->z_acl_count +
626fa9e4066Sahrens 		    OGE_PAD), KM_SLEEP);
627fa9e4066Sahrens 		if (aclp->z_state == ACL_DATA_ALLOCED)
628fa9e4066Sahrens 			need_free++;
629fa9e4066Sahrens 		from = aclp->z_acl;
630fa9e4066Sahrens 		oldaclp = aclp->z_acl;
631fa9e4066Sahrens 		(void) memmove(to, from,
632fa9e4066Sahrens 		    sizeof (ace_t) * aclp->z_acl_count);
633fa9e4066Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
634fa9e4066Sahrens 	} else {
635fa9e4066Sahrens 		from = aclp->z_acl;
636fa9e4066Sahrens 		to = aclp->z_acl;
637fa9e4066Sahrens 	}
638fa9e4066Sahrens 
639fa9e4066Sahrens 
640fa9e4066Sahrens 	(void) memmove(&to[i + 1], &from[i],
641fa9e4066Sahrens 	    sizeof (ace_t) * (aclp->z_acl_count - i));
642fa9e4066Sahrens 
643fa9e4066Sahrens 	if (oldaclp) {
644fa9e4066Sahrens 		aclp->z_acl = to;
645fa9e4066Sahrens 		oldslots = aclp->z_slots;
646fa9e4066Sahrens 		aclp->z_slots = aclp->z_acl_count + OGE_PAD;
647fa9e4066Sahrens 		if (need_free)
648fa9e4066Sahrens 			kmem_free(oldaclp, ZFS_ACL_SIZE(oldslots));
649fa9e4066Sahrens 	}
650fa9e4066Sahrens 
651fa9e4066Sahrens }
652fa9e4066Sahrens 
653fa9e4066Sahrens /*
654fa9e4066Sahrens  * Prepend deny ACE
655fa9e4066Sahrens  */
656fa9e4066Sahrens static void
657fa9e4066Sahrens zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
658fa9e4066Sahrens     mode_t mode)
659fa9e4066Sahrens {
660fa9e4066Sahrens 	ace_t	*acep;
661fa9e4066Sahrens 
662fa9e4066Sahrens 	zfs_acl_prepend(aclp, i);
663fa9e4066Sahrens 
664fa9e4066Sahrens 	acep = aclp->z_acl;
665fa9e4066Sahrens 	zfs_set_ace(&acep[i], 0, DENY, acep[i + 1].a_who,
666fa9e4066Sahrens 	    (acep[i + 1].a_flags & 0xf040));
667fa9e4066Sahrens 	zfs_acl_prepend_fixup(&acep[i], &acep[i+1], mode, zp->z_phys->zp_uid);
668fa9e4066Sahrens 	aclp->z_acl_count++;
669fa9e4066Sahrens }
670fa9e4066Sahrens 
671fa9e4066Sahrens /*
672fa9e4066Sahrens  * Split an inherited ACE into inherit_only ACE
673fa9e4066Sahrens  * and original ACE with inheritance flags stripped off.
674fa9e4066Sahrens  */
675fa9e4066Sahrens static void
676fa9e4066Sahrens zfs_acl_split_ace(zfs_acl_t *aclp, int i)
677fa9e4066Sahrens {
678fa9e4066Sahrens 	ace_t *acep = aclp->z_acl;
679fa9e4066Sahrens 
680fa9e4066Sahrens 	zfs_acl_prepend(aclp, i);
681fa9e4066Sahrens 	acep = aclp->z_acl;
682fa9e4066Sahrens 	acep[i] = acep[i + 1];
683fa9e4066Sahrens 	acep[i].a_flags |= ACE_INHERIT_ONLY_ACE;
684fa9e4066Sahrens 	acep[i + 1].a_flags &= ~ALL_INHERIT;
685fa9e4066Sahrens 	aclp->z_acl_count++;
686fa9e4066Sahrens }
687fa9e4066Sahrens 
688fa9e4066Sahrens /*
689fa9e4066Sahrens  * Are ACES started at index i, the canonical six ACES?
690fa9e4066Sahrens  */
691fa9e4066Sahrens static int
692fa9e4066Sahrens zfs_have_canonical_six(zfs_acl_t *aclp, int i)
693fa9e4066Sahrens {
694fa9e4066Sahrens 	ace_t *acep = aclp->z_acl;
695fa9e4066Sahrens 
696fa9e4066Sahrens 	if ((zfs_acl_ace_match(&acep[i],
697fa9e4066Sahrens 	    DENY, ACE_OWNER, 0) &&
698fa9e4066Sahrens 	    zfs_acl_ace_match(&acep[i + 1], ALLOW, ACE_OWNER,
699fa9e4066Sahrens 	    OWNER_ALLOW_MASK) && zfs_acl_ace_match(&acep[i + 2],
700fa9e4066Sahrens 	    DENY, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 3],
701fa9e4066Sahrens 	    ALLOW, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 4],
702fa9e4066Sahrens 	    DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
703fa9e4066Sahrens 	    zfs_acl_ace_match(&acep[i + 5], ALLOW, ACE_EVERYONE,
704fa9e4066Sahrens 	    EVERYONE_ALLOW_MASK))) {
705fa9e4066Sahrens 		return (1);
706fa9e4066Sahrens 	} else {
707fa9e4066Sahrens 		return (0);
708fa9e4066Sahrens 	}
709fa9e4066Sahrens }
710fa9e4066Sahrens 
711fa9e4066Sahrens /*
712fa9e4066Sahrens  * Apply step 1g, to group entries
713fa9e4066Sahrens  *
714fa9e4066Sahrens  * Need to deal with corner case where group may have
715fa9e4066Sahrens  * greater permissions than owner.  If so then limit
716fa9e4066Sahrens  * group permissions, based on what extra permissions
717fa9e4066Sahrens  * group has.
718fa9e4066Sahrens  */
719fa9e4066Sahrens static void
720fa9e4066Sahrens zfs_fixup_group_entries(ace_t *acep, mode_t mode)
721fa9e4066Sahrens {
722fa9e4066Sahrens 	mode_t extramode = (mode >> 3) & 07;
723fa9e4066Sahrens 	mode_t ownermode = (mode >> 6);
724fa9e4066Sahrens 
725fa9e4066Sahrens 	if (acep[0].a_flags & ACE_IDENTIFIER_GROUP) {
726fa9e4066Sahrens 
727fa9e4066Sahrens 		extramode &= ~ownermode;
728fa9e4066Sahrens 
729fa9e4066Sahrens 		if (extramode) {
730fa9e4066Sahrens 			if (extramode & 04) {
731fa9e4066Sahrens 				acep[0].a_access_mask &= ~ACE_READ_DATA;
732fa9e4066Sahrens 				acep[1].a_access_mask &= ~ACE_READ_DATA;
733fa9e4066Sahrens 			}
734fa9e4066Sahrens 			if (extramode & 02) {
735fa9e4066Sahrens 				acep[0].a_access_mask &=
736fa9e4066Sahrens 				    ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
737fa9e4066Sahrens 				acep[1].a_access_mask &=
738fa9e4066Sahrens 				    ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
739fa9e4066Sahrens 			}
740fa9e4066Sahrens 			if (extramode & 01) {
741fa9e4066Sahrens 				acep[0].a_access_mask &= ~ACE_EXECUTE;
742fa9e4066Sahrens 				acep[1].a_access_mask &= ~ACE_EXECUTE;
743fa9e4066Sahrens 			}
744fa9e4066Sahrens 		}
745fa9e4066Sahrens 	}
746fa9e4066Sahrens }
747fa9e4066Sahrens 
748fa9e4066Sahrens /*
749fa9e4066Sahrens  * Apply the chmod algorithm as described
750fa9e4066Sahrens  * in PSARC/2002/240
751fa9e4066Sahrens  */
752fa9e4066Sahrens static int
753fa9e4066Sahrens zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
754fa9e4066Sahrens     dmu_tx_t *tx)
755fa9e4066Sahrens {
756fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
757fa9e4066Sahrens 	ace_t 		*acep;
758fa9e4066Sahrens 	int 		i;
759fa9e4066Sahrens 	int		error;
760fa9e4066Sahrens 	int 		entry_type;
761fa9e4066Sahrens 	int 		reuse_deny;
762fa9e4066Sahrens 	int 		need_canonical_six = 1;
763de122929Smarks 	int		inherit = 0;
764de122929Smarks 	int		iflags;
765fa9e4066Sahrens 
766fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
767fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
768fa9e4066Sahrens 
769fa9e4066Sahrens 	i = 0;
770fa9e4066Sahrens 	while (i < aclp->z_acl_count) {
771fa9e4066Sahrens 		acep = aclp->z_acl;
772fa9e4066Sahrens 		entry_type = (acep[i].a_flags & 0xf040);
773de122929Smarks 		iflags = (acep[i].a_flags & ALL_INHERIT);
774fa9e4066Sahrens 
775fa9e4066Sahrens 		if ((acep[i].a_type != ALLOW && acep[i].a_type != DENY) ||
776de122929Smarks 		    (iflags & ACE_INHERIT_ONLY_ACE)) {
777fa9e4066Sahrens 			i++;
778de122929Smarks 			if (iflags)
779de122929Smarks 				inherit = 1;
780fa9e4066Sahrens 			continue;
781fa9e4066Sahrens 		}
782fa9e4066Sahrens 
783fa9e4066Sahrens 
784fa9e4066Sahrens 		if (zfsvfs->z_acl_mode == DISCARD) {
785fa9e4066Sahrens 			zfs_ace_remove(aclp, i);
786fa9e4066Sahrens 			continue;
787fa9e4066Sahrens 		}
788fa9e4066Sahrens 
789fa9e4066Sahrens 		/*
790fa9e4066Sahrens 		 * Need to split ace into two?
791fa9e4066Sahrens 		 */
792de122929Smarks 		if ((iflags & (ACE_FILE_INHERIT_ACE|
793fa9e4066Sahrens 		    ACE_DIRECTORY_INHERIT_ACE)) &&
794de122929Smarks 		    (!(iflags & ACE_INHERIT_ONLY_ACE))) {
795fa9e4066Sahrens 			zfs_acl_split_ace(aclp, i);
796fa9e4066Sahrens 			i++;
797de122929Smarks 			inherit = 1;
798fa9e4066Sahrens 			continue;
799fa9e4066Sahrens 		}
800fa9e4066Sahrens 
801fa9e4066Sahrens 		if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
802fa9e4066Sahrens 		    (entry_type == OWNING_GROUP)) {
803fa9e4066Sahrens 			acep[i].a_access_mask &= ~OGE_CLEAR;
804fa9e4066Sahrens 			i++;
805fa9e4066Sahrens 			continue;
806fa9e4066Sahrens 
807fa9e4066Sahrens 		} else {
808fa9e4066Sahrens 			if (acep[i].a_type == ALLOW) {
809fa9e4066Sahrens 
810fa9e4066Sahrens 				/*
811fa9e4066Sahrens 				 * Check preceding ACE if any, to see
812fa9e4066Sahrens 				 * if we need to prepend a DENY ACE.
813fa9e4066Sahrens 				 * This is only applicable when the acl_mode
814fa9e4066Sahrens 				 * property == groupmask.
815fa9e4066Sahrens 				 */
816fa9e4066Sahrens 				if (zfsvfs->z_acl_mode == GROUPMASK) {
817fa9e4066Sahrens 
818fa9e4066Sahrens 					reuse_deny = zfs_reuse_deny(acep, i);
819fa9e4066Sahrens 
820fa9e4066Sahrens 					if (reuse_deny == B_FALSE) {
821fa9e4066Sahrens 						zfs_acl_prepend_deny(zp, aclp,
822fa9e4066Sahrens 						    i, mode);
823fa9e4066Sahrens 						i++;
824fa9e4066Sahrens 						acep = aclp->z_acl;
825fa9e4066Sahrens 					} else {
826fa9e4066Sahrens 						zfs_acl_prepend_fixup(
827fa9e4066Sahrens 						    &acep[i - 1],
828fa9e4066Sahrens 						    &acep[i], mode,
829fa9e4066Sahrens 						    zp->z_phys->zp_uid);
830fa9e4066Sahrens 					}
831fa9e4066Sahrens 					zfs_fixup_group_entries(&acep[i - 1],
832fa9e4066Sahrens 					    mode);
833fa9e4066Sahrens 				}
834fa9e4066Sahrens 			}
835fa9e4066Sahrens 			i++;
836fa9e4066Sahrens 		}
837fa9e4066Sahrens 	}
838fa9e4066Sahrens 
839fa9e4066Sahrens 	/*
840fa9e4066Sahrens 	 * Check out last six aces, if we have six.
841fa9e4066Sahrens 	 */
842fa9e4066Sahrens 
843fa9e4066Sahrens 	if (aclp->z_acl_count >= 6) {
844fa9e4066Sahrens 		i = aclp->z_acl_count - 6;
845fa9e4066Sahrens 
846fa9e4066Sahrens 		if (zfs_have_canonical_six(aclp, i)) {
847fa9e4066Sahrens 			need_canonical_six = 0;
848fa9e4066Sahrens 		}
849fa9e4066Sahrens 	}
850fa9e4066Sahrens 
851fa9e4066Sahrens 	if (need_canonical_six) {
852fa9e4066Sahrens 
853fa9e4066Sahrens 		zfs_acl_append(aclp, 6);
854fa9e4066Sahrens 		i = aclp->z_acl_count;
855fa9e4066Sahrens 		acep = aclp->z_acl;
856fa9e4066Sahrens 		zfs_set_ace(&acep[i++], 0, DENY, -1, ACE_OWNER);
857fa9e4066Sahrens 		zfs_set_ace(&acep[i++], OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
858fa9e4066Sahrens 		zfs_set_ace(&acep[i++], 0, DENY, -1, OWNING_GROUP);
859fa9e4066Sahrens 		zfs_set_ace(&acep[i++], 0, ALLOW, -1, OWNING_GROUP);
860fa9e4066Sahrens 		zfs_set_ace(&acep[i++], EVERYONE_DENY_MASK,
861fa9e4066Sahrens 		    DENY, -1, ACE_EVERYONE);
862fa9e4066Sahrens 		zfs_set_ace(&acep[i++], EVERYONE_ALLOW_MASK,
863fa9e4066Sahrens 		    ALLOW, -1, ACE_EVERYONE);
864fa9e4066Sahrens 		aclp->z_acl_count += 6;
865fa9e4066Sahrens 	}
866fa9e4066Sahrens 
867fa9e4066Sahrens 	zfs_acl_fixup_canonical_six(aclp, mode);
868fa9e4066Sahrens 
869fa9e4066Sahrens 	zp->z_phys->zp_mode = mode;
870de122929Smarks 	error = zfs_aclset_common(zp, aclp, tx, &inherit);
871fa9e4066Sahrens 	return (error);
872fa9e4066Sahrens }
873fa9e4066Sahrens 
874fa9e4066Sahrens 
875fa9e4066Sahrens int
876fa9e4066Sahrens zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
877fa9e4066Sahrens {
878*ea8dc4b6Seschrock 	zfs_acl_t *aclp = NULL;
879fa9e4066Sahrens 	int error;
880fa9e4066Sahrens 
881fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
882fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
883*ea8dc4b6Seschrock 	error = zfs_acl_node_read(zp, &aclp);
884*ea8dc4b6Seschrock 	if (error == 0)
885*ea8dc4b6Seschrock 		error = zfs_acl_chmod(zp, mode, aclp, tx);
886fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
887*ea8dc4b6Seschrock 	if (aclp)
888*ea8dc4b6Seschrock 		zfs_acl_free(aclp);
889fa9e4066Sahrens 	return (error);
890fa9e4066Sahrens }
891fa9e4066Sahrens 
892fa9e4066Sahrens /*
893fa9e4066Sahrens  * strip off write_owner and write_acl
894fa9e4066Sahrens  */
895fa9e4066Sahrens static void
896fa9e4066Sahrens zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep)
897fa9e4066Sahrens {
898fa9e4066Sahrens 	if ((zfsvfs->z_acl_inherit == SECURE) &&
899fa9e4066Sahrens 	    acep->a_type == ALLOW)
900fa9e4066Sahrens 		acep->a_access_mask &= ~SECURE_NO_INHERIT;
901fa9e4066Sahrens }
902fa9e4066Sahrens 
903fa9e4066Sahrens /*
904fa9e4066Sahrens  * inherit inheritable ACEs from parent
905fa9e4066Sahrens  */
906fa9e4066Sahrens static zfs_acl_t *
907fa9e4066Sahrens zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
908fa9e4066Sahrens {
909fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
910fa9e4066Sahrens 	ace_t 		*pacep;
911fa9e4066Sahrens 	ace_t		*acep;
912fa9e4066Sahrens 	int 		ace_cnt = 0;
913fa9e4066Sahrens 	int		pace_cnt;
914fa9e4066Sahrens 	int 		i, j;
915fa9e4066Sahrens 	zfs_acl_t	*aclp = NULL;
916fa9e4066Sahrens 
917fa9e4066Sahrens 	i = j = 0;
918fa9e4066Sahrens 	pace_cnt = paclp->z_acl_count;
919fa9e4066Sahrens 	pacep = paclp->z_acl;
920fa9e4066Sahrens 	if (zfsvfs->z_acl_inherit != DISCARD) {
921fa9e4066Sahrens 		for (i = 0; i != pace_cnt; i++) {
922fa9e4066Sahrens 
923fa9e4066Sahrens 			if (zfsvfs->z_acl_inherit == NOALLOW &&
924fa9e4066Sahrens 			    pacep[i].a_type == ALLOW)
925fa9e4066Sahrens 				continue;
926fa9e4066Sahrens 
927fa9e4066Sahrens 			if (zfs_ace_can_use(zp, &pacep[i])) {
928fa9e4066Sahrens 				ace_cnt++;
929fa9e4066Sahrens 				if (!(pacep[i].a_flags &
930fa9e4066Sahrens 				    ACE_NO_PROPAGATE_INHERIT_ACE))
931fa9e4066Sahrens 					ace_cnt++;
932fa9e4066Sahrens 			}
933fa9e4066Sahrens 		}
934fa9e4066Sahrens 	}
935fa9e4066Sahrens 
936fa9e4066Sahrens 	aclp = zfs_acl_alloc(ace_cnt + OGE_PAD);
937fa9e4066Sahrens 	if (ace_cnt && zfsvfs->z_acl_inherit != DISCARD) {
938fa9e4066Sahrens 		acep = aclp->z_acl;
939fa9e4066Sahrens 		pacep = paclp->z_acl;
940fa9e4066Sahrens 		for (i = 0; i != pace_cnt; i++) {
941fa9e4066Sahrens 
942fa9e4066Sahrens 			if (zfsvfs->z_acl_inherit == NOALLOW &&
943fa9e4066Sahrens 			    pacep[i].a_type == ALLOW)
944fa9e4066Sahrens 				continue;
945fa9e4066Sahrens 
946fa9e4066Sahrens 			if (zfs_ace_can_use(zp, &pacep[i])) {
947fa9e4066Sahrens 				/*
948fa9e4066Sahrens 				 * Now create entry for inherited ace
949fa9e4066Sahrens 				 */
950fa9e4066Sahrens 				acep[j] = pacep[i];
951fa9e4066Sahrens 
952fa9e4066Sahrens 				if (pacep[i].a_flags &
953fa9e4066Sahrens 				    ACE_NO_PROPAGATE_INHERIT_ACE) {
954fa9e4066Sahrens 					acep[j].a_flags &= ~ALL_INHERIT;
955fa9e4066Sahrens 					j++;
956fa9e4066Sahrens 					continue;
957fa9e4066Sahrens 				}
958fa9e4066Sahrens 
959fa9e4066Sahrens 				if (pacep[i].a_type != ALLOW &&
960fa9e4066Sahrens 				    pacep[i].a_type != DENY) {
961fa9e4066Sahrens 					zfs_securemode_update(zfsvfs, &acep[j]);
962fa9e4066Sahrens 					j++;
963fa9e4066Sahrens 					continue;
964fa9e4066Sahrens 				}
965fa9e4066Sahrens 
966fa9e4066Sahrens 				if (ZTOV(zp)->v_type != VDIR) {
967fa9e4066Sahrens 					acep[j].a_flags &= ~ALL_INHERIT;
968fa9e4066Sahrens 					zfs_securemode_update(zfsvfs, &acep[j]);
969fa9e4066Sahrens 					j++;
970fa9e4066Sahrens 					continue;
971fa9e4066Sahrens 				}
972fa9e4066Sahrens 
973fa9e4066Sahrens 				ASSERT(ZTOV(zp)->v_type == VDIR);
974fa9e4066Sahrens 
975fa9e4066Sahrens 				/*
976fa9e4066Sahrens 				 * If we are inheriting an ACE targeted for
97755601ddbSmarks 				 * only files, then make sure inherit_only
97855601ddbSmarks 				 * is on for future propagation.
979fa9e4066Sahrens 				 */
980fa9e4066Sahrens 				if ((acep[j].a_flags & (ACE_FILE_INHERIT_ACE |
98155601ddbSmarks 				    ACE_DIRECTORY_INHERIT_ACE)) ==
98255601ddbSmarks 				    ACE_FILE_INHERIT_ACE) {
98355601ddbSmarks 					acep[j].a_flags |= ACE_INHERIT_ONLY_ACE;
98455601ddbSmarks 				} else {
985fa9e4066Sahrens 					acep[j].a_flags &=
986fa9e4066Sahrens 					    ~ACE_INHERIT_ONLY_ACE;
98755601ddbSmarks 				}
988fa9e4066Sahrens 
989fa9e4066Sahrens 				zfs_securemode_update(zfsvfs, &acep[j]);
990fa9e4066Sahrens 				j++;
991fa9e4066Sahrens 			}
992fa9e4066Sahrens 		}
993fa9e4066Sahrens 	}
994fa9e4066Sahrens 	aclp->z_acl_count = j;
995fa9e4066Sahrens 	ASSERT(aclp->z_slots >= aclp->z_acl_count);
996fa9e4066Sahrens 
997fa9e4066Sahrens 	return (aclp);
998fa9e4066Sahrens }
999fa9e4066Sahrens 
1000fa9e4066Sahrens /*
1001fa9e4066Sahrens  * Create file system object initial permissions
1002fa9e4066Sahrens  * including inheritable ACEs.
1003fa9e4066Sahrens  */
1004fa9e4066Sahrens void
1005fa9e4066Sahrens zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
1006fa9e4066Sahrens     vattr_t *vap, dmu_tx_t *tx, cred_t *cr)
1007fa9e4066Sahrens {
1008fa9e4066Sahrens 	uint64_t	mode;
1009fa9e4066Sahrens 	uid_t		uid;
1010fa9e4066Sahrens 	gid_t		gid;
1011fa9e4066Sahrens 	int		error;
1012fa9e4066Sahrens 	int		pull_down;
1013fa9e4066Sahrens 	zfs_acl_t	*aclp, *paclp;
1014fa9e4066Sahrens 
1015fa9e4066Sahrens 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
1016fa9e4066Sahrens 
1017fa9e4066Sahrens 	/*
1018fa9e4066Sahrens 	 * Determine uid and gid.
1019fa9e4066Sahrens 	 */
1020fa9e4066Sahrens 	if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
1021fa9e4066Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
1022fa9e4066Sahrens 		uid = vap->va_uid;
1023fa9e4066Sahrens 		gid = vap->va_gid;
1024fa9e4066Sahrens 	} else {
1025fa9e4066Sahrens 		uid = crgetuid(cr);
1026fa9e4066Sahrens 		if ((vap->va_mask & AT_GID) &&
1027fa9e4066Sahrens 		    ((vap->va_gid == parent->z_phys->zp_gid) ||
1028fa9e4066Sahrens 		    groupmember(vap->va_gid, cr) ||
1029fa9e4066Sahrens 		    secpolicy_vnode_create_gid(cr)))
1030fa9e4066Sahrens 			gid = vap->va_gid;
1031fa9e4066Sahrens 		else
1032fa9e4066Sahrens 			gid = (parent->z_phys->zp_mode & S_ISGID) ?
1033fa9e4066Sahrens 			    parent->z_phys->zp_gid : crgetgid(cr);
1034fa9e4066Sahrens 	}
1035fa9e4066Sahrens 
1036fa9e4066Sahrens 	/*
1037fa9e4066Sahrens 	 * If we're creating a directory, and the parent directory has the
1038fa9e4066Sahrens 	 * set-GID bit set, set in on the new directory.
1039fa9e4066Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1040fa9e4066Sahrens 	 * file's new group, clear the file's set-GID bit.
1041fa9e4066Sahrens 	 */
1042fa9e4066Sahrens 
1043fa9e4066Sahrens 	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR))
1044fa9e4066Sahrens 		mode |= S_ISGID;
1045fa9e4066Sahrens 	else {
1046fa9e4066Sahrens 		if ((mode & S_ISGID) &&
1047fa9e4066Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
1048fa9e4066Sahrens 			mode &= ~S_ISGID;
1049fa9e4066Sahrens 	}
1050fa9e4066Sahrens 
1051fa9e4066Sahrens 	zp->z_phys->zp_uid = uid;
1052fa9e4066Sahrens 	zp->z_phys->zp_gid = gid;
1053fa9e4066Sahrens 	zp->z_phys->zp_mode = mode;
1054fa9e4066Sahrens 
1055fa9e4066Sahrens 	mutex_enter(&parent->z_lock);
1056fa9e4066Sahrens 	pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
1057fa9e4066Sahrens 	if (pull_down) {
1058fa9e4066Sahrens 		mutex_enter(&parent->z_acl_lock);
1059*ea8dc4b6Seschrock 		VERIFY(0 == zfs_acl_node_read(parent, &paclp));
1060fa9e4066Sahrens 		mutex_exit(&parent->z_acl_lock);
1061fa9e4066Sahrens 		aclp = zfs_acl_inherit(zp, paclp);
1062fa9e4066Sahrens 		zfs_acl_free(paclp);
1063fa9e4066Sahrens 	} else {
1064fa9e4066Sahrens 		aclp = zfs_acl_alloc(6);
1065fa9e4066Sahrens 	}
1066fa9e4066Sahrens 	mutex_exit(&parent->z_lock);
1067fa9e4066Sahrens 	mutex_enter(&zp->z_lock);
1068fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
1069fa9e4066Sahrens 	error = zfs_acl_chmod(zp, mode, aclp, tx);
1070fa9e4066Sahrens 	mutex_exit(&zp->z_lock);
1071fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1072fa9e4066Sahrens 	ASSERT3U(error, ==, 0);
1073fa9e4066Sahrens 	zfs_acl_free(aclp);
1074fa9e4066Sahrens }
1075fa9e4066Sahrens 
1076fa9e4066Sahrens /*
10770a787dc5Smarks  * Should ACE be inherited?
1078fa9e4066Sahrens  */
1079fa9e4066Sahrens static int
1080fa9e4066Sahrens zfs_ace_can_use(znode_t *zp, ace_t *acep)
1081fa9e4066Sahrens {
1082fa9e4066Sahrens 	int vtype = ZTOV(zp)->v_type;
1083fa9e4066Sahrens 
1084fa9e4066Sahrens 	int	iflags = (acep->a_flags & 0xf);
1085fa9e4066Sahrens 
1086fa9e4066Sahrens 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
1087fa9e4066Sahrens 		return (1);
1088fa9e4066Sahrens 	else if (iflags & ACE_FILE_INHERIT_ACE)
10890a787dc5Smarks 		return (!((vtype == VDIR) &&
10900a787dc5Smarks 		    (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
1091fa9e4066Sahrens 	return (0);
1092fa9e4066Sahrens }
1093fa9e4066Sahrens 
1094fa9e4066Sahrens /*
1095fa9e4066Sahrens  * Retrieve a files ACL
1096fa9e4066Sahrens  */
1097fa9e4066Sahrens int
1098fa9e4066Sahrens zfs_getacl(znode_t *zp, vsecattr_t  *vsecp, cred_t *cr)
1099fa9e4066Sahrens {
1100fa9e4066Sahrens 	zfs_acl_t	*aclp;
1101fa9e4066Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1102fa9e4066Sahrens 	int		error;
1103fa9e4066Sahrens 
1104fa9e4066Sahrens 	if (error = zfs_zaccess(zp, ACE_READ_ACL, cr)) {
1105fa9e4066Sahrens 		/*
1106fa9e4066Sahrens 		 * If owner of file then allow reading of the
1107fa9e4066Sahrens 		 * ACL.
1108fa9e4066Sahrens 		 */
1109fa9e4066Sahrens 		if (crgetuid(cr) != zp->z_phys->zp_uid)
1110fa9e4066Sahrens 			return (error);
1111fa9e4066Sahrens 	}
1112fa9e4066Sahrens 
1113fa9e4066Sahrens 	if (mask == 0)
1114fa9e4066Sahrens 		return (ENOSYS);
1115fa9e4066Sahrens 
1116fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
1117fa9e4066Sahrens 
1118*ea8dc4b6Seschrock 	error = zfs_acl_node_read(zp, &aclp);
1119*ea8dc4b6Seschrock 	if (error != 0) {
1120*ea8dc4b6Seschrock 		mutex_exit(&zp->z_acl_lock);
1121*ea8dc4b6Seschrock 		return (error);
1122*ea8dc4b6Seschrock 	}
1123*ea8dc4b6Seschrock 
1124fa9e4066Sahrens 
1125fa9e4066Sahrens 	if (mask & VSA_ACECNT) {
1126fa9e4066Sahrens 		vsecp->vsa_aclcnt = aclp->z_acl_count;
1127fa9e4066Sahrens 	}
1128fa9e4066Sahrens 
1129fa9e4066Sahrens 	if (mask & VSA_ACE) {
1130fa9e4066Sahrens 		vsecp->vsa_aclentp = kmem_alloc(aclp->z_acl_count *
1131fa9e4066Sahrens 		    sizeof (ace_t), KM_SLEEP);
1132fa9e4066Sahrens 		bcopy(aclp->z_acl, vsecp->vsa_aclentp,
1133fa9e4066Sahrens 		    aclp->z_acl_count * sizeof (ace_t));
1134fa9e4066Sahrens 	}
1135fa9e4066Sahrens 
1136fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1137fa9e4066Sahrens 
1138fa9e4066Sahrens 	zfs_acl_free(aclp);
1139fa9e4066Sahrens 
1140fa9e4066Sahrens 	return (0);
1141fa9e4066Sahrens }
1142fa9e4066Sahrens 
1143fa9e4066Sahrens /*
1144fa9e4066Sahrens  * Set a files ACL
1145fa9e4066Sahrens  */
1146fa9e4066Sahrens int
1147fa9e4066Sahrens zfs_setacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
1148fa9e4066Sahrens {
1149fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1150fa9e4066Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
1151fa9e4066Sahrens 	ace_t		*acep = vsecp->vsa_aclentp;
1152fa9e4066Sahrens 	int		aclcnt = vsecp->vsa_aclcnt;
1153fa9e4066Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1154fa9e4066Sahrens 	dmu_tx_t	*tx;
1155fa9e4066Sahrens 	int		error;
1156fa9e4066Sahrens 	int		inherit;
1157fa9e4066Sahrens 	zfs_acl_t	*aclp;
1158fa9e4066Sahrens 	uint64_t	seq = 0;
1159fa9e4066Sahrens 
1160fa9e4066Sahrens 	if (mask == 0)
1161fa9e4066Sahrens 		return (EINVAL);
1162fa9e4066Sahrens 
1163fa9e4066Sahrens 	if (!zfs_acl_valid(zp, acep, aclcnt, &inherit))
1164fa9e4066Sahrens 		return (EINVAL);
1165fa9e4066Sahrens top:
1166fa9e4066Sahrens 	error = zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr);
1167fa9e4066Sahrens 	if (error == EACCES || error == ACCESS_UNDETERMINED) {
1168fa9e4066Sahrens 		if ((error = secpolicy_vnode_setdac(cr,
1169fa9e4066Sahrens 		    zp->z_phys->zp_uid)) != 0) {
1170fa9e4066Sahrens 			return (error);
1171fa9e4066Sahrens 		}
1172fa9e4066Sahrens 	} else if (error) {
1173fa9e4066Sahrens 		return (error == EROFS ? error : EPERM);
1174fa9e4066Sahrens 	}
1175fa9e4066Sahrens 
1176fa9e4066Sahrens 	mutex_enter(&zp->z_lock);
1177fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
1178fa9e4066Sahrens 
1179fa9e4066Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
1180fa9e4066Sahrens 	dmu_tx_hold_bonus(tx, zp->z_id);
1181fa9e4066Sahrens 
1182fa9e4066Sahrens 	if (zp->z_phys->zp_acl.z_acl_extern_obj) {
1183fa9e4066Sahrens 		dmu_tx_hold_write(tx, zp->z_phys->zp_acl.z_acl_extern_obj,
1184fa9e4066Sahrens 		    0, ZFS_ACL_SIZE(aclcnt));
1185fa9e4066Sahrens 	} else if (aclcnt > ACE_SLOT_CNT) {
1186fa9e4066Sahrens 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, ZFS_ACL_SIZE(aclcnt));
1187fa9e4066Sahrens 	}
1188fa9e4066Sahrens 
1189fa9e4066Sahrens 	error = dmu_tx_assign(tx, zfsvfs->z_assign);
1190fa9e4066Sahrens 	if (error) {
1191fa9e4066Sahrens 		dmu_tx_abort(tx);
1192fa9e4066Sahrens 
1193fa9e4066Sahrens 		mutex_exit(&zp->z_acl_lock);
1194fa9e4066Sahrens 		mutex_exit(&zp->z_lock);
1195fa9e4066Sahrens 
1196fa9e4066Sahrens 		if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT) {
1197fa9e4066Sahrens 			txg_wait_open(dmu_objset_pool(zfsvfs->z_os), 0);
1198fa9e4066Sahrens 			goto top;
1199fa9e4066Sahrens 		}
1200fa9e4066Sahrens 		return (error);
1201fa9e4066Sahrens 	}
1202fa9e4066Sahrens 
1203fa9e4066Sahrens 	aclp = zfs_acl_alloc(aclcnt);
1204fa9e4066Sahrens 	bcopy(acep, aclp->z_acl, sizeof (ace_t) * aclcnt);
1205fa9e4066Sahrens 	aclp->z_acl_count = aclcnt;
1206fa9e4066Sahrens 	error = zfs_aclset_common(zp, aclp, tx, &inherit);
1207fa9e4066Sahrens 	ASSERT(error == 0);
1208fa9e4066Sahrens 
1209fa9e4066Sahrens 	zfs_acl_free(aclp);
1210fa9e4066Sahrens 	seq = zfs_log_acl(zilog, tx, TX_ACL, zp, aclcnt, acep);
1211fa9e4066Sahrens 	dmu_tx_commit(tx);
1212fa9e4066Sahrens done:
1213fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1214fa9e4066Sahrens 	mutex_exit(&zp->z_lock);
1215fa9e4066Sahrens 
1216fa9e4066Sahrens 	zil_commit(zilog, seq, 0);
1217fa9e4066Sahrens 
1218fa9e4066Sahrens 	return (error);
1219fa9e4066Sahrens }
1220fa9e4066Sahrens 
1221fa9e4066Sahrens static int
1222fa9e4066Sahrens zfs_ace_access(ace_t *zacep, int mode_wanted, int *working_mode)
1223fa9e4066Sahrens {
1224fa9e4066Sahrens 	if ((*working_mode & mode_wanted) == mode_wanted) {
1225fa9e4066Sahrens 		return (0);
1226fa9e4066Sahrens 	}
1227fa9e4066Sahrens 
1228fa9e4066Sahrens 	if (zacep->a_access_mask & mode_wanted) {
1229fa9e4066Sahrens 		if (zacep->a_type == ALLOW) {
1230fa9e4066Sahrens 			*working_mode |= (mode_wanted & zacep->a_access_mask);
1231fa9e4066Sahrens 			if ((*working_mode & mode_wanted) == mode_wanted)
1232fa9e4066Sahrens 				return (0);
1233fa9e4066Sahrens 		} else if (zacep->a_type == DENY) {
1234fa9e4066Sahrens 			return (EACCES);
1235fa9e4066Sahrens 		}
1236fa9e4066Sahrens 	}
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 	/*
1239fa9e4066Sahrens 	 * haven't been specifcally denied at this point
1240fa9e4066Sahrens 	 * so return UNDETERMINED.
1241fa9e4066Sahrens 	 */
1242fa9e4066Sahrens 
1243fa9e4066Sahrens 	return (ACCESS_UNDETERMINED);
1244fa9e4066Sahrens }
1245fa9e4066Sahrens 
1246fa9e4066Sahrens 
1247fa9e4066Sahrens static int
1248fa9e4066Sahrens zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
1249fa9e4066Sahrens {
1250fa9e4066Sahrens 	zfs_acl_t	*aclp;
1251fa9e4066Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1252fa9e4066Sahrens 	ace_t		*zacep;
1253fa9e4066Sahrens 	gid_t		gid;
1254fa9e4066Sahrens 	int		mode_wanted = v4_mode;
1255fa9e4066Sahrens 	int		cnt;
1256fa9e4066Sahrens 	int		i;
1257*ea8dc4b6Seschrock 	int		error;
1258fa9e4066Sahrens 	int		access_deny = ACCESS_UNDETERMINED;
1259fa9e4066Sahrens 	uint_t		entry_type;
1260fa9e4066Sahrens 	uid_t		uid = crgetuid(cr);
1261fa9e4066Sahrens 
1262fa9e4066Sahrens 	*working_mode = 0;
1263fa9e4066Sahrens 
1264fa9e4066Sahrens 	if (zfsvfs->z_assign >= TXG_INITIAL)		/* ZIL replay */
1265fa9e4066Sahrens 		return (0);
1266fa9e4066Sahrens 
1267fa9e4066Sahrens 	if ((v4_mode & WRITE_MASK) &&
1268fa9e4066Sahrens 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
1269fa9e4066Sahrens 	    (!IS_DEVVP(ZTOV(zp)))) {
1270fa9e4066Sahrens 		return (EROFS);
1271fa9e4066Sahrens 	}
1272fa9e4066Sahrens 
1273fa9e4066Sahrens 	mutex_enter(&zp->z_acl_lock);
1274fa9e4066Sahrens 
1275*ea8dc4b6Seschrock 	error = zfs_acl_node_read(zp, &aclp);
1276*ea8dc4b6Seschrock 	if (error != 0) {
1277*ea8dc4b6Seschrock 		mutex_exit(&zp->z_acl_lock);
1278*ea8dc4b6Seschrock 		return (error);
1279*ea8dc4b6Seschrock 	}
1280*ea8dc4b6Seschrock 
1281fa9e4066Sahrens 
1282fa9e4066Sahrens 	zacep = aclp->z_acl;
1283fa9e4066Sahrens 	cnt = aclp->z_acl_count;
1284fa9e4066Sahrens 
1285fa9e4066Sahrens 	for (i = 0; i != cnt; i++) {
1286fa9e4066Sahrens 
1287fa9e4066Sahrens 		if (zacep[i].a_flags & ACE_INHERIT_ONLY_ACE)
1288fa9e4066Sahrens 			continue;
1289fa9e4066Sahrens 
1290fa9e4066Sahrens 		entry_type = (zacep[i].a_flags & 0xf040);
1291fa9e4066Sahrens 		switch (entry_type) {
1292fa9e4066Sahrens 		case ACE_OWNER:
1293fa9e4066Sahrens 			if (uid == zp->z_phys->zp_uid) {
1294fa9e4066Sahrens 				access_deny = zfs_ace_access(&zacep[i],
1295fa9e4066Sahrens 				    mode_wanted, working_mode);
1296fa9e4066Sahrens 			}
1297fa9e4066Sahrens 			break;
1298fa9e4066Sahrens 		case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
1299fa9e4066Sahrens 		case ACE_IDENTIFIER_GROUP:
1300fa9e4066Sahrens 			/*
1301fa9e4066Sahrens 			 * Owning group gid is in znode not ACL
1302fa9e4066Sahrens 			 */
1303fa9e4066Sahrens 			if (entry_type == (ACE_IDENTIFIER_GROUP | ACE_GROUP))
1304fa9e4066Sahrens 				gid = zp->z_phys->zp_gid;
1305fa9e4066Sahrens 			else
1306fa9e4066Sahrens 				gid = zacep[i].a_who;
1307fa9e4066Sahrens 
1308fa9e4066Sahrens 			if (groupmember(gid, cr)) {
1309fa9e4066Sahrens 				access_deny = zfs_ace_access(&zacep[i],
1310fa9e4066Sahrens 				    mode_wanted, working_mode);
1311fa9e4066Sahrens 			}
1312fa9e4066Sahrens 			break;
1313fa9e4066Sahrens 		case ACE_EVERYONE:
1314fa9e4066Sahrens 			access_deny = zfs_ace_access(&zacep[i],
1315fa9e4066Sahrens 			    mode_wanted, working_mode);
1316fa9e4066Sahrens 			break;
1317fa9e4066Sahrens 
1318fa9e4066Sahrens 		/* USER Entry */
1319fa9e4066Sahrens 		default:
1320fa9e4066Sahrens 			if (entry_type == 0) {
1321fa9e4066Sahrens 				if (uid == zacep[i].a_who) {
1322fa9e4066Sahrens 					access_deny = zfs_ace_access(&zacep[i],
1323fa9e4066Sahrens 					    mode_wanted, working_mode);
1324fa9e4066Sahrens 				}
1325fa9e4066Sahrens 				break;
1326fa9e4066Sahrens 			}
1327fa9e4066Sahrens 			zfs_acl_free(aclp);
1328fa9e4066Sahrens 			mutex_exit(&zp->z_acl_lock);
1329fa9e4066Sahrens 			return (EIO);
1330fa9e4066Sahrens 		}
1331fa9e4066Sahrens 
1332fa9e4066Sahrens 		if (access_deny != ACCESS_UNDETERMINED)
1333fa9e4066Sahrens 			break;
1334fa9e4066Sahrens 
1335fa9e4066Sahrens 	}
1336fa9e4066Sahrens 
1337fa9e4066Sahrens 	mutex_exit(&zp->z_acl_lock);
1338fa9e4066Sahrens 	zfs_acl_free(aclp);
1339fa9e4066Sahrens 
1340fa9e4066Sahrens 	return (access_deny);
1341fa9e4066Sahrens }
1342fa9e4066Sahrens 
1343fa9e4066Sahrens 
1344fa9e4066Sahrens /*
1345fa9e4066Sahrens  * Determine whether Access should be granted/denied, invoking least
1346fa9e4066Sahrens  * priv subsytem when a deny is determined.
1347fa9e4066Sahrens  */
1348fa9e4066Sahrens int
1349fa9e4066Sahrens zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
1350fa9e4066Sahrens {
1351fa9e4066Sahrens 	int	working_mode = 0;
1352fa9e4066Sahrens 	int	error;
1353fa9e4066Sahrens 	int	is_attr;
1354fa9e4066Sahrens 	znode_t	*xzp;
1355fa9e4066Sahrens 	znode_t *check_zp = zp;
1356fa9e4066Sahrens 
1357fa9e4066Sahrens 	is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
1358fa9e4066Sahrens 	    (ZTOV(zp)->v_type == VDIR));
1359fa9e4066Sahrens 
1360fa9e4066Sahrens 	/*
1361fa9e4066Sahrens 	 * If attribute then validate against base file
1362fa9e4066Sahrens 	 */
1363fa9e4066Sahrens 	if (is_attr) {
1364fa9e4066Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
1365fa9e4066Sahrens 		    zp->z_phys->zp_parent, &xzp)) != 0)	{
1366fa9e4066Sahrens 			return (error);
1367fa9e4066Sahrens 		}
1368fa9e4066Sahrens 		check_zp = xzp;
1369fa9e4066Sahrens 		/*
1370fa9e4066Sahrens 		 * fixup mode to map to xattr perms
1371fa9e4066Sahrens 		 */
1372fa9e4066Sahrens 
1373fa9e4066Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
1374fa9e4066Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
1375fa9e4066Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
1376fa9e4066Sahrens 		}
1377fa9e4066Sahrens 
1378fa9e4066Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
1379fa9e4066Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
1380fa9e4066Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
1381fa9e4066Sahrens 		}
1382fa9e4066Sahrens 	}
1383fa9e4066Sahrens 
1384fa9e4066Sahrens 	error = zfs_zaccess_common(check_zp, mode, &working_mode, cr);
1385fa9e4066Sahrens 
1386fa9e4066Sahrens 	if (error == EROFS) {
1387fa9e4066Sahrens 		if (is_attr)
1388fa9e4066Sahrens 			VN_RELE(ZTOV(xzp));
1389fa9e4066Sahrens 		return (error);
1390fa9e4066Sahrens 	}
1391fa9e4066Sahrens 
1392fa9e4066Sahrens 	if (error || (working_mode != mode)) {
1393fa9e4066Sahrens 		error = secpolicy_vnode_access(cr, ZTOV(check_zp),
1394fa9e4066Sahrens 		    check_zp->z_phys->zp_uid, ~zfs_v4_to_unix(working_mode));
1395fa9e4066Sahrens 	}
1396fa9e4066Sahrens 
1397fa9e4066Sahrens 	if (is_attr)
1398fa9e4066Sahrens 		VN_RELE(ZTOV(xzp));
1399fa9e4066Sahrens 
1400fa9e4066Sahrens 	return (error);
1401fa9e4066Sahrens }
1402fa9e4066Sahrens 
1403fa9e4066Sahrens /*
1404fa9e4066Sahrens  * Special zaccess function to check for special nfsv4 perm.
1405fa9e4066Sahrens  * doesn't call secpolicy_vnode_access() for failure, since that
1406fa9e4066Sahrens  * would probably be the wrong policy function to call.
1407fa9e4066Sahrens  * instead its up to the caller to handle that situation.
1408fa9e4066Sahrens  */
1409fa9e4066Sahrens 
1410fa9e4066Sahrens int
1411fa9e4066Sahrens zfs_zaccess_v4_perm(znode_t *zp, int mode, cred_t *cr)
1412fa9e4066Sahrens {
1413fa9e4066Sahrens 	int working_mode = 0;
1414fa9e4066Sahrens 	return (zfs_zaccess_common(zp, mode, &working_mode, cr));
1415fa9e4066Sahrens }
1416fa9e4066Sahrens 
1417fa9e4066Sahrens /*
1418fa9e4066Sahrens  * Translate tradition unix VREAD/VWRITE/VEXEC mode into
1419fa9e4066Sahrens  * native ACL format and call zfs_zaccess()
1420fa9e4066Sahrens  */
1421fa9e4066Sahrens int
1422fa9e4066Sahrens zfs_zaccess_rwx(znode_t *zp, mode_t mode, cred_t *cr)
1423fa9e4066Sahrens {
1424fa9e4066Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
1425fa9e4066Sahrens 
1426fa9e4066Sahrens 	return (zfs_zaccess(zp, v4_mode, cr));
1427fa9e4066Sahrens }
1428fa9e4066Sahrens 
1429fa9e4066Sahrens /*
1430fa9e4066Sahrens  * Determine whether Access should be granted/deny, without
1431fa9e4066Sahrens  * consulting least priv subsystem.
1432fa9e4066Sahrens  *
1433fa9e4066Sahrens  *
1434fa9e4066Sahrens  * The following chart is the recommended NFSv4 enforcement for
1435fa9e4066Sahrens  * ability to delete an object.
1436fa9e4066Sahrens  *
1437fa9e4066Sahrens  *      -------------------------------------------------------
1438fa9e4066Sahrens  *      |   Parent Dir  |           Target Object Permissions |
1439fa9e4066Sahrens  *      |  permissions  |                                     |
1440fa9e4066Sahrens  *      -------------------------------------------------------
1441fa9e4066Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
1442fa9e4066Sahrens  *      |               |  Delete    |  Delete   | unspecified|
1443fa9e4066Sahrens  *      -------------------------------------------------------
1444fa9e4066Sahrens  *      |  ACL Allows   | Permit     | Permit    | Permit     |
1445fa9e4066Sahrens  *      |  DELETE_CHILD |                                     |
1446fa9e4066Sahrens  *      -------------------------------------------------------
1447fa9e4066Sahrens  *      |  ACL Denies   | Permit     | Deny      | Deny       |
1448fa9e4066Sahrens  *      |  DELETE_CHILD |            |           |            |
1449fa9e4066Sahrens  *      -------------------------------------------------------
1450fa9e4066Sahrens  *      | ACL specifies |            |           |            |
1451fa9e4066Sahrens  *      | only allow    | Permit     | Permit    | Permit     |
1452fa9e4066Sahrens  *      | write and     |            |           |            |
1453fa9e4066Sahrens  *      | execute       |            |           |            |
1454fa9e4066Sahrens  *      -------------------------------------------------------
1455fa9e4066Sahrens  *      | ACL denies    |            |           |            |
1456fa9e4066Sahrens  *      | write and     | Permit     | Deny      | Deny       |
1457fa9e4066Sahrens  *      | execute       |            |           |            |
1458fa9e4066Sahrens  *      -------------------------------------------------------
1459fa9e4066Sahrens  *         ^
1460fa9e4066Sahrens  *         |
1461fa9e4066Sahrens  *         No search privilege, can't even look up file?
1462fa9e4066Sahrens  *
1463fa9e4066Sahrens  */
1464fa9e4066Sahrens int
1465fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
1466fa9e4066Sahrens {
1467fa9e4066Sahrens 	int dzp_working_mode = 0;
1468fa9e4066Sahrens 	int zp_working_mode = 0;
1469fa9e4066Sahrens 	int dzp_error, zp_error;
147084c5a155Smarks 	int error;
1471fa9e4066Sahrens 
1472fa9e4066Sahrens 	/*
1473fa9e4066Sahrens 	 * Arghh, this check is going to require a couple of questions
1474fa9e4066Sahrens 	 * to be asked.  We want specific DELETE permissions to
1475fa9e4066Sahrens 	 * take precedence over WRITE/EXECUTE.  We don't
1476fa9e4066Sahrens 	 * want an ACL such as this to mess us up.
1477fa9e4066Sahrens 	 * user:sloar:write_data:deny,user:sloar:delete:allow
1478fa9e4066Sahrens 	 *
1479fa9e4066Sahrens 	 * However, deny permissions may ultimately be overridden
1480fa9e4066Sahrens 	 * by secpolicy_vnode_access().
1481fa9e4066Sahrens 	 */
1482fa9e4066Sahrens 
1483fa9e4066Sahrens 	dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
1484fa9e4066Sahrens 	    &dzp_working_mode, cr);
1485fa9e4066Sahrens 	zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, cr);
1486fa9e4066Sahrens 
1487fa9e4066Sahrens 	if (dzp_error == EROFS || zp_error == EROFS)
1488fa9e4066Sahrens 		return (dzp_error);
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 	/*
1491fa9e4066Sahrens 	 * First handle the first row
1492fa9e4066Sahrens 	 */
1493fa9e4066Sahrens 	if (dzp_working_mode & ACE_DELETE_CHILD)
1494fa9e4066Sahrens 		return (0);
1495fa9e4066Sahrens 
1496fa9e4066Sahrens 	/*
1497fa9e4066Sahrens 	 * Second row
1498fa9e4066Sahrens 	 */
1499fa9e4066Sahrens 
1500fa9e4066Sahrens 	if (zp_working_mode & ACE_DELETE)
1501fa9e4066Sahrens 		return (0);
1502fa9e4066Sahrens 
1503fa9e4066Sahrens 	/*
1504fa9e4066Sahrens 	 * Third Row
1505fa9e4066Sahrens 	 */
1506fa9e4066Sahrens 
1507fa9e4066Sahrens 	dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
1508fa9e4066Sahrens 	    &dzp_working_mode, cr);
1509fa9e4066Sahrens 
1510fa9e4066Sahrens 	if (dzp_error == EROFS)
1511fa9e4066Sahrens 		return (dzp_error);
1512fa9e4066Sahrens 
1513fa9e4066Sahrens 	if (dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE))
151484c5a155Smarks 		goto sticky;
1515fa9e4066Sahrens 
1516fa9e4066Sahrens 	/*
1517fa9e4066Sahrens 	 * Fourth Row
1518fa9e4066Sahrens 	 */
1519fa9e4066Sahrens 
1520fa9e4066Sahrens 	if (((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0) &&
1521fa9e4066Sahrens 	    (zp_working_mode & ACE_DELETE))
152284c5a155Smarks 		goto sticky;
152384c5a155Smarks 
152484c5a155Smarks 	error = secpolicy_vnode_access(cr, ZTOV(zp),
152584c5a155Smarks 	    dzp->z_phys->zp_uid, S_IWRITE|S_IEXEC);
152684c5a155Smarks 
152784c5a155Smarks 	if (error)
152884c5a155Smarks 		return (error);
152984c5a155Smarks 
153084c5a155Smarks sticky:
153184c5a155Smarks 	error = zfs_sticky_remove_access(dzp, zp, cr);
1532fa9e4066Sahrens 
153384c5a155Smarks 	return (error);
1534fa9e4066Sahrens }
1535fa9e4066Sahrens 
1536fa9e4066Sahrens int
1537fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
1538fa9e4066Sahrens     znode_t *tzp, cred_t *cr)
1539fa9e4066Sahrens {
1540fa9e4066Sahrens 	int add_perm;
1541fa9e4066Sahrens 	int error;
1542fa9e4066Sahrens 
1543fa9e4066Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
1544fa9e4066Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
1545fa9e4066Sahrens 
1546fa9e4066Sahrens 	/*
1547fa9e4066Sahrens 	 * Rename permissions are combination of delete permission +
1548fa9e4066Sahrens 	 * add file/subdir permission.
1549fa9e4066Sahrens 	 */
1550fa9e4066Sahrens 
1551fa9e4066Sahrens 	/*
1552fa9e4066Sahrens 	 * first make sure we do the delete portion.
1553fa9e4066Sahrens 	 *
1554fa9e4066Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
1555fa9e4066Sahrens 	 */
1556fa9e4066Sahrens 
1557fa9e4066Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
1558fa9e4066Sahrens 		return (error);
1559fa9e4066Sahrens 
1560fa9e4066Sahrens 	/*
1561fa9e4066Sahrens 	 * If we have a tzp, see if we can delete it?
1562fa9e4066Sahrens 	 */
1563fa9e4066Sahrens 	if (tzp) {
1564fa9e4066Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
1565fa9e4066Sahrens 			return (error);
1566fa9e4066Sahrens 	}
1567fa9e4066Sahrens 
1568fa9e4066Sahrens 	/*
1569fa9e4066Sahrens 	 * Now check for add permissions
1570fa9e4066Sahrens 	 */
157184c5a155Smarks 	error = zfs_zaccess(tdzp, add_perm, cr);
1572fa9e4066Sahrens 
1573fa9e4066Sahrens 	return (error);
1574fa9e4066Sahrens }
1575