xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision 865:4223fbdac5f3)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
5789Sahrens  * Common Development and Distribution License, Version 1.0 only
6789Sahrens  * (the "License").  You may not use this file except in compliance
7789Sahrens  * with the License.
8789Sahrens  *
9789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10789Sahrens  * or http://www.opensolaris.org/os/licensing.
11789Sahrens  * See the License for the specific language governing permissions
12789Sahrens  * and limitations under the License.
13789Sahrens  *
14789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19789Sahrens  *
20789Sahrens  * CDDL HEADER END
21789Sahrens  */
22789Sahrens /*
23789Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24789Sahrens  * Use is subject to license terms.
25789Sahrens  */
26789Sahrens 
27789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28789Sahrens 
29789Sahrens #include <sys/types.h>
30789Sahrens #include <sys/param.h>
31789Sahrens #include <sys/time.h>
32789Sahrens #include <sys/systm.h>
33789Sahrens #include <sys/sysmacros.h>
34789Sahrens #include <sys/resource.h>
35789Sahrens #include <sys/vfs.h>
36789Sahrens #include <sys/vnode.h>
37789Sahrens #include <sys/file.h>
38789Sahrens #include <sys/stat.h>
39789Sahrens #include <sys/kmem.h>
40789Sahrens #include <sys/cmn_err.h>
41789Sahrens #include <sys/errno.h>
42789Sahrens #include <sys/unistd.h>
43789Sahrens #include <sys/fs/zfs.h>
44789Sahrens #include <sys/mode.h>
45789Sahrens #include <sys/policy.h>
46789Sahrens #include <sys/zfs_znode.h>
47789Sahrens #include <sys/zfs_acl.h>
48789Sahrens #include <sys/zfs_dir.h>
49789Sahrens #include <sys/zfs_vfsops.h>
50789Sahrens #include <sys/dmu.h>
51789Sahrens #include <sys/zap.h>
52789Sahrens #include <util/qsort.h>
53789Sahrens #include "fs/fs_subr.h"
54789Sahrens #include <acl/acl_common.h>
55789Sahrens 
56789Sahrens #define	ALLOW	ACE_ACCESS_ALLOWED_ACE_TYPE
57789Sahrens #define	DENY	ACE_ACCESS_DENIED_ACE_TYPE
58789Sahrens 
59789Sahrens #define	OWNING_GROUP		(ACE_GROUP|ACE_IDENTIFIER_GROUP)
60789Sahrens #define	EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
61789Sahrens     ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
62789Sahrens #define	EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
63789Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
64789Sahrens #define	OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
65789Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
66789Sahrens #define	WRITE_MASK (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS| \
67789Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_ACL|ACE_WRITE_OWNER)
68789Sahrens 
69789Sahrens #define	OGE_CLEAR	(ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
70789Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
71789Sahrens 
72789Sahrens #define	OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
73789Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
74789Sahrens 
75789Sahrens #define	ALL_INHERIT	(ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
76789Sahrens     ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
77789Sahrens 
78789Sahrens #define	SECURE_NO_INHERIT	(ACE_WRITE_ACL|ACE_WRITE_OWNER)
79789Sahrens 
80789Sahrens #define	OGE_PAD	6		/* traditional owner/group/everyone ACES */
81789Sahrens 
82789Sahrens static int zfs_ace_can_use(znode_t *zp, ace_t *);
83789Sahrens 
84789Sahrens static zfs_acl_t *
85789Sahrens zfs_acl_alloc(int slots)
86789Sahrens {
87789Sahrens 	zfs_acl_t *aclp;
88789Sahrens 
89789Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
90789Sahrens 	if (slots != 0) {
91789Sahrens 		aclp->z_acl = kmem_alloc(ZFS_ACL_SIZE(slots), KM_SLEEP);
92789Sahrens 		aclp->z_acl_count = 0;
93789Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
94789Sahrens 	} else {
95789Sahrens 		aclp->z_state = 0;
96789Sahrens 	}
97789Sahrens 	aclp->z_slots = slots;
98789Sahrens 	return (aclp);
99789Sahrens }
100789Sahrens 
101789Sahrens void
102789Sahrens zfs_acl_free(zfs_acl_t *aclp)
103789Sahrens {
104789Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED) {
105789Sahrens 		kmem_free(aclp->z_acl, ZFS_ACL_SIZE(aclp->z_slots));
106789Sahrens 	}
107789Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
108789Sahrens }
109789Sahrens 
110789Sahrens static uint32_t
111789Sahrens zfs_v4_to_unix(uint32_t access_mask)
112789Sahrens {
113789Sahrens 	uint32_t new_mask = 0;
114789Sahrens 
115789Sahrens 	if (access_mask & (ACE_READ_DATA | ACE_LIST_DIRECTORY))
116789Sahrens 		new_mask |= S_IROTH;
117789Sahrens 	if (access_mask & (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_ADD_FILE))
118789Sahrens 		new_mask |= S_IWOTH;
119789Sahrens 	if (access_mask & (ACE_EXECUTE|ACE_READ_NAMED_ATTRS))
120789Sahrens 		new_mask |= S_IXOTH;
121789Sahrens 
122789Sahrens 	return (new_mask);
123789Sahrens }
124789Sahrens 
125789Sahrens /*
126789Sahrens  * Convert unix access mask to v4 access mask
127789Sahrens  */
128789Sahrens static uint32_t
129789Sahrens zfs_unix_to_v4(uint32_t access_mask)
130789Sahrens {
131789Sahrens 	uint32_t new_mask = 0;
132789Sahrens 
133789Sahrens 	if (access_mask & 01)
134789Sahrens 		new_mask |= (ACE_EXECUTE);
135789Sahrens 	if (access_mask & 02) {
136789Sahrens 		new_mask |= (ACE_WRITE_DATA);
137789Sahrens 	} if (access_mask & 04) {
138789Sahrens 		new_mask |= ACE_READ_DATA;
139789Sahrens 	}
140789Sahrens 	return (new_mask);
141789Sahrens }
142789Sahrens 
143789Sahrens static void
144789Sahrens zfs_set_ace(ace_t *zacep, uint32_t access_mask, int access_type,
145789Sahrens     uid_t uid, int entry_type)
146789Sahrens {
147789Sahrens 	zacep->a_access_mask = access_mask;
148789Sahrens 	zacep->a_type = access_type;
149789Sahrens 	zacep->a_who = uid;
150789Sahrens 	zacep->a_flags = entry_type;
151789Sahrens }
152789Sahrens 
153789Sahrens static uint64_t
154789Sahrens zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp)
155789Sahrens {
156789Sahrens 	int 	i;
157789Sahrens 	int	entry_type;
158789Sahrens 	mode_t	mode = (zp->z_phys->zp_mode &
159789Sahrens 	    (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
160789Sahrens 	mode_t	 seen = 0;
161789Sahrens 	ace_t 	*acep;
162789Sahrens 
163789Sahrens 	for (i = 0, acep = aclp->z_acl;
164789Sahrens 	    i != aclp->z_acl_count; i++, acep++) {
165789Sahrens 		entry_type = (acep->a_flags & 0xf040);
166789Sahrens 		if (entry_type == ACE_OWNER) {
167789Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA) &&
168789Sahrens 			    (!(seen & S_IRUSR))) {
169789Sahrens 				seen |= S_IRUSR;
170789Sahrens 				if (acep->a_type == ALLOW) {
171789Sahrens 					mode |= S_IRUSR;
172789Sahrens 				}
173789Sahrens 			}
174789Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA) &&
175789Sahrens 			    (!(seen & S_IWUSR))) {
176789Sahrens 				seen |= S_IWUSR;
177789Sahrens 				if (acep->a_type == ALLOW) {
178789Sahrens 					mode |= S_IWUSR;
179789Sahrens 				}
180789Sahrens 			}
181789Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE) &&
182789Sahrens 			    (!(seen & S_IXUSR))) {
183789Sahrens 				seen |= S_IXUSR;
184789Sahrens 				if (acep->a_type == ALLOW) {
185789Sahrens 					mode |= S_IXUSR;
186789Sahrens 				}
187789Sahrens 			}
188789Sahrens 		} else if (entry_type == OWNING_GROUP) {
189789Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA) &&
190789Sahrens 			    (!(seen & S_IRGRP))) {
191789Sahrens 				seen |= S_IRGRP;
192789Sahrens 				if (acep->a_type == ALLOW) {
193789Sahrens 					mode |= S_IRGRP;
194789Sahrens 				}
195789Sahrens 			}
196789Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA) &&
197789Sahrens 			    (!(seen & S_IWGRP))) {
198789Sahrens 				seen |= S_IWGRP;
199789Sahrens 				if (acep->a_type == ALLOW) {
200789Sahrens 					mode |= S_IWGRP;
201789Sahrens 				}
202789Sahrens 			}
203789Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE) &&
204789Sahrens 			    (!(seen & S_IXGRP))) {
205789Sahrens 				seen |= S_IXGRP;
206789Sahrens 				if (acep->a_type == ALLOW) {
207789Sahrens 					mode |= S_IXGRP;
208789Sahrens 				}
209789Sahrens 			}
210789Sahrens 		} else if (entry_type == ACE_EVERYONE) {
211789Sahrens 			if ((acep->a_access_mask & ACE_READ_DATA)) {
212789Sahrens 				if (!(seen & S_IRUSR)) {
213789Sahrens 					seen |= S_IRUSR;
214789Sahrens 					if (acep->a_type == ALLOW) {
215789Sahrens 						mode |= S_IRUSR;
216789Sahrens 					}
217789Sahrens 				}
218789Sahrens 				if (!(seen & S_IRGRP)) {
219789Sahrens 					seen |= S_IRGRP;
220789Sahrens 					if (acep->a_type == ALLOW) {
221789Sahrens 						mode |= S_IRGRP;
222789Sahrens 					}
223789Sahrens 				}
224789Sahrens 				if (!(seen & S_IROTH)) {
225789Sahrens 					seen |= S_IROTH;
226789Sahrens 					if (acep->a_type == ALLOW) {
227789Sahrens 						mode |= S_IROTH;
228789Sahrens 					}
229789Sahrens 				}
230789Sahrens 			}
231789Sahrens 			if ((acep->a_access_mask & ACE_WRITE_DATA)) {
232789Sahrens 				if (!(seen & S_IWUSR)) {
233789Sahrens 					seen |= S_IWUSR;
234789Sahrens 					if (acep->a_type == ALLOW) {
235789Sahrens 						mode |= S_IWUSR;
236789Sahrens 					}
237789Sahrens 				}
238789Sahrens 				if (!(seen & S_IWGRP)) {
239789Sahrens 					seen |= S_IWGRP;
240789Sahrens 					if (acep->a_type == ALLOW) {
241789Sahrens 						mode |= S_IWGRP;
242789Sahrens 					}
243789Sahrens 				}
244789Sahrens 				if (!(seen & S_IWOTH)) {
245789Sahrens 					seen |= S_IWOTH;
246789Sahrens 					if (acep->a_type == ALLOW) {
247789Sahrens 						mode |= S_IWOTH;
248789Sahrens 					}
249789Sahrens 				}
250789Sahrens 			}
251789Sahrens 			if ((acep->a_access_mask & ACE_EXECUTE)) {
252789Sahrens 				if (!(seen & S_IXUSR)) {
253789Sahrens 					seen |= S_IXUSR;
254789Sahrens 					if (acep->a_type == ALLOW) {
255789Sahrens 						mode |= S_IXUSR;
256789Sahrens 					}
257789Sahrens 				}
258789Sahrens 				if (!(seen & S_IXGRP)) {
259789Sahrens 					seen |= S_IXGRP;
260789Sahrens 					if (acep->a_type == ALLOW) {
261789Sahrens 						mode |= S_IXGRP;
262789Sahrens 					}
263789Sahrens 				}
264789Sahrens 				if (!(seen & S_IXOTH)) {
265789Sahrens 					seen |= S_IXOTH;
266789Sahrens 					if (acep->a_type == ALLOW) {
267789Sahrens 						mode |= S_IXOTH;
268789Sahrens 					}
269789Sahrens 				}
270789Sahrens 			}
271789Sahrens 		}
272789Sahrens 	}
273789Sahrens 	return (mode);
274789Sahrens }
275789Sahrens 
276789Sahrens static zfs_acl_t *
277789Sahrens zfs_acl_node_read_internal(znode_t *zp)
278789Sahrens {
279789Sahrens 	zfs_acl_t	*aclp;
280789Sahrens 
281789Sahrens 	aclp = zfs_acl_alloc(0);
282789Sahrens 	aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
283789Sahrens 	aclp->z_acl = &zp->z_phys->zp_acl.z_ace_data[0];
284789Sahrens 
285789Sahrens 	return (aclp);
286789Sahrens }
287789Sahrens 
288789Sahrens /*
289789Sahrens  * Read an external acl object.
290789Sahrens  */
291789Sahrens zfs_acl_t *
292789Sahrens zfs_acl_node_read(znode_t *zp)
293789Sahrens {
294789Sahrens 	uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
295789Sahrens 	zfs_acl_t	*aclp;
296789Sahrens 
297789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
298789Sahrens 
299789Sahrens 	if (zp->z_phys->zp_acl.z_acl_extern_obj == 0)
300789Sahrens 		return (zfs_acl_node_read_internal(zp));
301789Sahrens 
302789Sahrens 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_count);
303789Sahrens 
304789Sahrens 	dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
305789Sahrens 	    ZFS_ACL_SIZE(zp->z_phys->zp_acl.z_acl_count), aclp->z_acl);
306789Sahrens 
307789Sahrens 	aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
308789Sahrens 
309789Sahrens 	return (aclp);
310789Sahrens }
311789Sahrens 
312789Sahrens static boolean_t
313789Sahrens zfs_acl_valid(znode_t *zp, ace_t *uace, int aclcnt, int *inherit)
314789Sahrens {
315789Sahrens 	ace_t 	*acep;
316789Sahrens 	int i;
317789Sahrens 
318789Sahrens 	*inherit = 0;
319789Sahrens 
320789Sahrens 	if (aclcnt > MAX_ACL_ENTRIES || aclcnt <= 0) {
321789Sahrens 		return (B_FALSE);
322789Sahrens 	}
323789Sahrens 
324789Sahrens 	for (i = 0, acep = uace; i != aclcnt; i++, acep++) {
325789Sahrens 
326789Sahrens 		/*
327789Sahrens 		 * first check type of entry
328789Sahrens 		 */
329789Sahrens 
330789Sahrens 		switch (acep->a_flags & 0xf040) {
331789Sahrens 		case ACE_OWNER:
332789Sahrens 			acep->a_who = -1;
333789Sahrens 			break;
334789Sahrens 		case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
335789Sahrens 		case ACE_IDENTIFIER_GROUP:
336789Sahrens 			if (acep->a_flags & ACE_GROUP) {
337789Sahrens 				acep->a_who = -1;
338789Sahrens 			}
339789Sahrens 			break;
340789Sahrens 		case ACE_EVERYONE:
341789Sahrens 			acep->a_who = -1;
342789Sahrens 			break;
343789Sahrens 		}
344789Sahrens 
345789Sahrens 		/*
346789Sahrens 		 * next check inheritance level flags
347789Sahrens 		 */
348789Sahrens 
349789Sahrens 		if (acep->a_type != ALLOW && acep->a_type != DENY)
350789Sahrens 			return (B_FALSE);
351789Sahrens 
352789Sahrens 		/*
353789Sahrens 		 * Only directories should have inheritance flags.
354789Sahrens 		 */
355789Sahrens 		if (ZTOV(zp)->v_type != VDIR && (acep->a_flags &
356789Sahrens 		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE|
357789Sahrens 		    ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE))) {
358789Sahrens 			return (B_FALSE);
359789Sahrens 		}
360789Sahrens 
361789Sahrens 		if (acep->a_flags &
362789Sahrens 		    (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))
363789Sahrens 			*inherit = 1;
364789Sahrens 
365789Sahrens 		if (acep->a_flags &
366789Sahrens 		    (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
367789Sahrens 			if ((acep->a_flags & (ACE_FILE_INHERIT_ACE|
368789Sahrens 			    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
369789Sahrens 				return (B_FALSE);
370789Sahrens 			}
371789Sahrens 		}
372789Sahrens 	}
373789Sahrens 
374789Sahrens 	return (B_TRUE);
375789Sahrens }
376789Sahrens /*
377789Sahrens  * common code for setting acl's.
378789Sahrens  *
379789Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
380789Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
381789Sahrens  * already checked the acl and knows whether to inherit.
382789Sahrens  */
383789Sahrens int
384789Sahrens zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, dmu_tx_t *tx, int *ihp)
385789Sahrens {
386789Sahrens 	int 		inherit = 0;
387789Sahrens 	int		error;
388789Sahrens 	znode_phys_t	*zphys = zp->z_phys;
389789Sahrens 	zfs_znode_acl_t	*zacl = &zphys->zp_acl;
390789Sahrens 	uint32_t	acl_phys_size = ZFS_ACL_SIZE(aclp->z_acl_count);
391789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
392789Sahrens 	uint64_t	aoid = zphys->zp_acl.z_acl_extern_obj;
393789Sahrens 
394789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
395789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
396789Sahrens 
397789Sahrens 	if (ihp)
398789Sahrens 		inherit = *ihp;		/* already determined by caller */
399789Sahrens 	else if (!zfs_acl_valid(zp, aclp->z_acl,
400789Sahrens 	    aclp->z_acl_count, &inherit)) {
401789Sahrens 		return (EINVAL);
402789Sahrens 	}
403789Sahrens 
404789Sahrens 	dmu_buf_will_dirty(zp->z_dbuf, tx);
405789Sahrens 
406789Sahrens 	/*
407789Sahrens 	 * Will ACL fit internally?
408789Sahrens 	 */
409789Sahrens 	if (aclp->z_acl_count > ACE_SLOT_CNT) {
410789Sahrens 		if (aoid == 0) {
411789Sahrens 			aoid = dmu_object_alloc(zfsvfs->z_os,
412789Sahrens 			    DMU_OT_ACL, acl_phys_size, DMU_OT_NONE, 0, tx);
413789Sahrens 		} else {
414789Sahrens 			(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
415789Sahrens 			    acl_phys_size, 0, tx);
416789Sahrens 		}
417789Sahrens 		zphys->zp_acl.z_acl_extern_obj = aoid;
418789Sahrens 		zphys->zp_acl.z_acl_count = aclp->z_acl_count;
419789Sahrens 		dmu_write(zfsvfs->z_os, aoid, 0,
420789Sahrens 		    acl_phys_size, aclp->z_acl, tx);
421789Sahrens 	} else {
422789Sahrens 		/*
423789Sahrens 		 * Migrating back embedded?
424789Sahrens 		 */
425789Sahrens 		if (zphys->zp_acl.z_acl_extern_obj) {
426789Sahrens 			error = dmu_object_free(zfsvfs->z_os,
427789Sahrens 				zp->z_phys->zp_acl.z_acl_extern_obj, tx);
428789Sahrens 			if (error)
429789Sahrens 				return (error);
430789Sahrens 			zphys->zp_acl.z_acl_extern_obj = 0;
431789Sahrens 		}
432789Sahrens 		bcopy(aclp->z_acl, zacl->z_ace_data,
433789Sahrens 		    aclp->z_acl_count * sizeof (ace_t));
434789Sahrens 		zacl->z_acl_count = aclp->z_acl_count;
435789Sahrens 	}
436789Sahrens 	if (inherit)
437789Sahrens 		zp->z_phys->zp_flags |= ZFS_INHERIT_ACE;
438789Sahrens 	else
439789Sahrens 		zp->z_phys->zp_flags &= ~ZFS_INHERIT_ACE;
440789Sahrens 
441789Sahrens 	zphys->zp_mode = zfs_mode_compute(zp, aclp);
442789Sahrens 	zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
443789Sahrens 
444789Sahrens 	return (0);
445789Sahrens }
446789Sahrens 
447789Sahrens /*
448789Sahrens  * Create space for slots_needed ACEs to be append
449789Sahrens  * to aclp.
450789Sahrens  */
451789Sahrens static void
452789Sahrens zfs_acl_append(zfs_acl_t *aclp, int slots_needed)
453789Sahrens {
454789Sahrens 	ace_t	*newacep;
455789Sahrens 	ace_t	*oldaclp;
456789Sahrens 	int	slot_cnt;
457789Sahrens 	int 	slots_left = aclp->z_slots - aclp->z_acl_count;
458789Sahrens 
459789Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED)
460789Sahrens 		ASSERT(aclp->z_slots >= aclp->z_acl_count);
461789Sahrens 	if (slots_left < slots_needed || aclp->z_state != ACL_DATA_ALLOCED) {
462789Sahrens 		slot_cnt = aclp->z_slots +  1 + (slots_needed - slots_left);
463789Sahrens 		newacep = kmem_alloc(ZFS_ACL_SIZE(slot_cnt), KM_SLEEP);
464789Sahrens 		bcopy(aclp->z_acl, newacep,
465789Sahrens 		    ZFS_ACL_SIZE(aclp->z_acl_count));
466789Sahrens 		oldaclp = aclp->z_acl;
467789Sahrens 		if (aclp->z_state == ACL_DATA_ALLOCED)
468789Sahrens 			kmem_free(oldaclp, ZFS_ACL_SIZE(aclp->z_slots));
469789Sahrens 		aclp->z_acl = newacep;
470789Sahrens 		aclp->z_slots = slot_cnt;
471789Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
472789Sahrens 	}
473789Sahrens }
474789Sahrens 
475789Sahrens /*
476789Sahrens  * Remove "slot" ACE from aclp
477789Sahrens  */
478789Sahrens static void
479789Sahrens zfs_ace_remove(zfs_acl_t *aclp, int slot)
480789Sahrens {
481789Sahrens 	if (aclp->z_acl_count > 1) {
482789Sahrens 		(void) memmove(&aclp->z_acl[slot],
483789Sahrens 		    &aclp->z_acl[slot +1], sizeof (ace_t) *
484789Sahrens 		    (--aclp->z_acl_count - slot));
485789Sahrens 	} else
486789Sahrens 		aclp->z_acl_count--;
487789Sahrens }
488789Sahrens 
489789Sahrens /*
490789Sahrens  * Update access mask for prepended ACE
491789Sahrens  *
492789Sahrens  * This applies the "groupmask" value for aclmode property.
493789Sahrens  */
494789Sahrens static void
495789Sahrens zfs_acl_prepend_fixup(ace_t *acep, ace_t *origacep, mode_t mode, uid_t owner)
496789Sahrens {
497789Sahrens 
498789Sahrens 	int	rmask, wmask, xmask;
499789Sahrens 	int	user_ace;
500789Sahrens 
501789Sahrens 	user_ace = (!(acep->a_flags &
502789Sahrens 	    (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
503789Sahrens 
504789Sahrens 	if (user_ace && (acep->a_who == owner)) {
505789Sahrens 		rmask = S_IRUSR;
506789Sahrens 		wmask = S_IWUSR;
507789Sahrens 		xmask = S_IXUSR;
508789Sahrens 	} else {
509789Sahrens 		rmask = S_IRGRP;
510789Sahrens 		wmask = S_IWGRP;
511789Sahrens 		xmask = S_IXGRP;
512789Sahrens 	}
513789Sahrens 
514789Sahrens 	if (origacep->a_access_mask & ACE_READ_DATA) {
515789Sahrens 		if (mode & rmask)
516789Sahrens 			acep->a_access_mask &= ~ACE_READ_DATA;
517789Sahrens 		else
518789Sahrens 			acep->a_access_mask |= ACE_READ_DATA;
519789Sahrens 	}
520789Sahrens 
521789Sahrens 	if (origacep->a_access_mask & ACE_WRITE_DATA) {
522789Sahrens 		if (mode & wmask)
523789Sahrens 			acep->a_access_mask &= ~ACE_WRITE_DATA;
524789Sahrens 		else
525789Sahrens 			acep->a_access_mask |= ACE_WRITE_DATA;
526789Sahrens 	}
527789Sahrens 
528789Sahrens 	if (origacep->a_access_mask & ACE_APPEND_DATA) {
529789Sahrens 		if (mode & wmask)
530789Sahrens 			acep->a_access_mask &= ~ACE_APPEND_DATA;
531789Sahrens 		else
532789Sahrens 			acep->a_access_mask |= ACE_APPEND_DATA;
533789Sahrens 	}
534789Sahrens 
535789Sahrens 	if (origacep->a_access_mask & ACE_EXECUTE) {
536789Sahrens 		if (mode & xmask)
537789Sahrens 			acep->a_access_mask &= ~ACE_EXECUTE;
538789Sahrens 		else
539789Sahrens 			acep->a_access_mask |= ACE_EXECUTE;
540789Sahrens 	}
541789Sahrens }
542789Sahrens 
543789Sahrens /*
544789Sahrens  * Apply mode to canonical six ACEs.
545789Sahrens  */
546789Sahrens static void
547789Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
548789Sahrens {
549789Sahrens 	int	cnt;
550789Sahrens 	ace_t	*acep;
551789Sahrens 
552789Sahrens 	cnt = aclp->z_acl_count -1;
553789Sahrens 	acep = aclp->z_acl;
554789Sahrens 
555789Sahrens 	/*
556789Sahrens 	 * Fixup final ACEs to match the mode
557789Sahrens 	 */
558789Sahrens 
559789Sahrens 	ASSERT(cnt >= 5);
560789Sahrens 	adjust_ace_pair(&acep[cnt - 1], mode);	/* everyone@ */
561789Sahrens 	adjust_ace_pair(&acep[cnt - 3], (mode & 0070) >> 3);	/* group@ */
562789Sahrens 	adjust_ace_pair(&acep[cnt - 5], (mode & 0700) >> 6);	/* owner@ */
563789Sahrens }
564789Sahrens 
565789Sahrens 
566789Sahrens static int
567789Sahrens zfs_acl_ace_match(ace_t *acep, int allow_deny, int type, int mask)
568789Sahrens {
569789Sahrens 	return (acep->a_access_mask == mask && acep->a_type == allow_deny &&
570789Sahrens 	    ((acep->a_flags & 0xf040) == type));
571789Sahrens }
572789Sahrens 
573789Sahrens /*
574789Sahrens  * Can prepended ACE be reused?
575789Sahrens  */
576789Sahrens static int
577789Sahrens zfs_reuse_deny(ace_t *acep, int i)
578789Sahrens {
579789Sahrens 	int okay_masks;
580789Sahrens 
581789Sahrens 	if (i < 1)
582789Sahrens 		return (B_FALSE);
583789Sahrens 
584789Sahrens 	if (acep[i-1].a_type != DENY)
585789Sahrens 		return (B_FALSE);
586789Sahrens 
587789Sahrens 	if (acep[i-1].a_flags != (acep[i].a_flags & ACE_IDENTIFIER_GROUP))
588789Sahrens 		return (B_FALSE);
589789Sahrens 
590789Sahrens 	okay_masks = (acep[i].a_access_mask & OKAY_MASK_BITS);
591789Sahrens 
592789Sahrens 	if (acep[i-1].a_access_mask & ~okay_masks)
593789Sahrens 		return (B_FALSE);
594789Sahrens 
595789Sahrens 	return (B_TRUE);
596789Sahrens }
597789Sahrens 
598789Sahrens /*
599789Sahrens  * Create space to prepend an ACE
600789Sahrens  */
601789Sahrens static void
602789Sahrens zfs_acl_prepend(zfs_acl_t *aclp, int i)
603789Sahrens {
604789Sahrens 	ace_t	*oldaclp = NULL;
605789Sahrens 	ace_t	*to, *from;
606789Sahrens 	int	slots_left = aclp->z_slots - aclp->z_acl_count;
607789Sahrens 	int	oldslots;
608789Sahrens 	int	need_free = 0;
609789Sahrens 
610789Sahrens 	if (aclp->z_state == ACL_DATA_ALLOCED)
611789Sahrens 		ASSERT(aclp->z_slots >= aclp->z_acl_count);
612789Sahrens 
613789Sahrens 	if (slots_left == 0 || aclp->z_state != ACL_DATA_ALLOCED) {
614789Sahrens 
615789Sahrens 		to = kmem_alloc(ZFS_ACL_SIZE(aclp->z_acl_count +
616789Sahrens 		    OGE_PAD), KM_SLEEP);
617789Sahrens 		if (aclp->z_state == ACL_DATA_ALLOCED)
618789Sahrens 			need_free++;
619789Sahrens 		from = aclp->z_acl;
620789Sahrens 		oldaclp = aclp->z_acl;
621789Sahrens 		(void) memmove(to, from,
622789Sahrens 		    sizeof (ace_t) * aclp->z_acl_count);
623789Sahrens 		aclp->z_state = ACL_DATA_ALLOCED;
624789Sahrens 	} else {
625789Sahrens 		from = aclp->z_acl;
626789Sahrens 		to = aclp->z_acl;
627789Sahrens 	}
628789Sahrens 
629789Sahrens 
630789Sahrens 	(void) memmove(&to[i + 1], &from[i],
631789Sahrens 	    sizeof (ace_t) * (aclp->z_acl_count - i));
632789Sahrens 
633789Sahrens 	if (oldaclp) {
634789Sahrens 		aclp->z_acl = to;
635789Sahrens 		oldslots = aclp->z_slots;
636789Sahrens 		aclp->z_slots = aclp->z_acl_count + OGE_PAD;
637789Sahrens 		if (need_free)
638789Sahrens 			kmem_free(oldaclp, ZFS_ACL_SIZE(oldslots));
639789Sahrens 	}
640789Sahrens 
641789Sahrens }
642789Sahrens 
643789Sahrens /*
644789Sahrens  * Prepend deny ACE
645789Sahrens  */
646789Sahrens static void
647789Sahrens zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, int i,
648789Sahrens     mode_t mode)
649789Sahrens {
650789Sahrens 	ace_t	*acep;
651789Sahrens 
652789Sahrens 	zfs_acl_prepend(aclp, i);
653789Sahrens 
654789Sahrens 	acep = aclp->z_acl;
655789Sahrens 	zfs_set_ace(&acep[i], 0, DENY, acep[i + 1].a_who,
656789Sahrens 	    (acep[i + 1].a_flags & 0xf040));
657789Sahrens 	zfs_acl_prepend_fixup(&acep[i], &acep[i+1], mode, zp->z_phys->zp_uid);
658789Sahrens 	aclp->z_acl_count++;
659789Sahrens }
660789Sahrens 
661789Sahrens /*
662789Sahrens  * Split an inherited ACE into inherit_only ACE
663789Sahrens  * and original ACE with inheritance flags stripped off.
664789Sahrens  */
665789Sahrens static void
666789Sahrens zfs_acl_split_ace(zfs_acl_t *aclp, int i)
667789Sahrens {
668789Sahrens 	ace_t *acep = aclp->z_acl;
669789Sahrens 
670789Sahrens 	zfs_acl_prepend(aclp, i);
671789Sahrens 	acep = aclp->z_acl;
672789Sahrens 	acep[i] = acep[i + 1];
673789Sahrens 	acep[i].a_flags |= ACE_INHERIT_ONLY_ACE;
674789Sahrens 	acep[i + 1].a_flags &= ~ALL_INHERIT;
675789Sahrens 	aclp->z_acl_count++;
676789Sahrens }
677789Sahrens 
678789Sahrens /*
679789Sahrens  * Are ACES started at index i, the canonical six ACES?
680789Sahrens  */
681789Sahrens static int
682789Sahrens zfs_have_canonical_six(zfs_acl_t *aclp, int i)
683789Sahrens {
684789Sahrens 	ace_t *acep = aclp->z_acl;
685789Sahrens 
686789Sahrens 	if ((zfs_acl_ace_match(&acep[i],
687789Sahrens 	    DENY, ACE_OWNER, 0) &&
688789Sahrens 	    zfs_acl_ace_match(&acep[i + 1], ALLOW, ACE_OWNER,
689789Sahrens 	    OWNER_ALLOW_MASK) && zfs_acl_ace_match(&acep[i + 2],
690789Sahrens 	    DENY, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 3],
691789Sahrens 	    ALLOW, OWNING_GROUP, 0) && zfs_acl_ace_match(&acep[i + 4],
692789Sahrens 	    DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
693789Sahrens 	    zfs_acl_ace_match(&acep[i + 5], ALLOW, ACE_EVERYONE,
694789Sahrens 	    EVERYONE_ALLOW_MASK))) {
695789Sahrens 		return (1);
696789Sahrens 	} else {
697789Sahrens 		return (0);
698789Sahrens 	}
699789Sahrens }
700789Sahrens 
701789Sahrens /*
702789Sahrens  * Apply step 1g, to group entries
703789Sahrens  *
704789Sahrens  * Need to deal with corner case where group may have
705789Sahrens  * greater permissions than owner.  If so then limit
706789Sahrens  * group permissions, based on what extra permissions
707789Sahrens  * group has.
708789Sahrens  */
709789Sahrens static void
710789Sahrens zfs_fixup_group_entries(ace_t *acep, mode_t mode)
711789Sahrens {
712789Sahrens 	mode_t extramode = (mode >> 3) & 07;
713789Sahrens 	mode_t ownermode = (mode >> 6);
714789Sahrens 
715789Sahrens 	if (acep[0].a_flags & ACE_IDENTIFIER_GROUP) {
716789Sahrens 
717789Sahrens 		extramode &= ~ownermode;
718789Sahrens 
719789Sahrens 		if (extramode) {
720789Sahrens 			if (extramode & 04) {
721789Sahrens 				acep[0].a_access_mask &= ~ACE_READ_DATA;
722789Sahrens 				acep[1].a_access_mask &= ~ACE_READ_DATA;
723789Sahrens 			}
724789Sahrens 			if (extramode & 02) {
725789Sahrens 				acep[0].a_access_mask &=
726789Sahrens 				    ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
727789Sahrens 				acep[1].a_access_mask &=
728789Sahrens 				    ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
729789Sahrens 			}
730789Sahrens 			if (extramode & 01) {
731789Sahrens 				acep[0].a_access_mask &= ~ACE_EXECUTE;
732789Sahrens 				acep[1].a_access_mask &= ~ACE_EXECUTE;
733789Sahrens 			}
734789Sahrens 		}
735789Sahrens 	}
736789Sahrens }
737789Sahrens 
738789Sahrens /*
739789Sahrens  * Apply the chmod algorithm as described
740789Sahrens  * in PSARC/2002/240
741789Sahrens  */
742789Sahrens static int
743789Sahrens zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
744789Sahrens     dmu_tx_t *tx)
745789Sahrens {
746789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
747789Sahrens 	ace_t 		*acep;
748789Sahrens 	int 		i;
749789Sahrens 	int		error;
750789Sahrens 	int 		entry_type;
751789Sahrens 	int 		reuse_deny;
752789Sahrens 	int 		need_canonical_six = 1;
753789Sahrens 
754789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
755789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
756789Sahrens 
757789Sahrens 	i = 0;
758789Sahrens 	while (i < aclp->z_acl_count) {
759789Sahrens 		acep = aclp->z_acl;
760789Sahrens 		entry_type = (acep[i].a_flags & 0xf040);
761789Sahrens 
762789Sahrens 		if ((acep[i].a_type != ALLOW && acep[i].a_type != DENY) ||
763789Sahrens 		    (acep[i].a_flags & ACE_INHERIT_ONLY_ACE)) {
764789Sahrens 			i++;
765789Sahrens 			continue;
766789Sahrens 		}
767789Sahrens 
768789Sahrens 
769789Sahrens 		if (zfsvfs->z_acl_mode == DISCARD) {
770789Sahrens 			zfs_ace_remove(aclp, i);
771789Sahrens 			continue;
772789Sahrens 		}
773789Sahrens 
774789Sahrens 		/*
775789Sahrens 		 * Need to split ace into two?
776789Sahrens 		 */
777789Sahrens 		if ((acep[i].a_flags & (ACE_FILE_INHERIT_ACE|
778789Sahrens 		    ACE_DIRECTORY_INHERIT_ACE)) &&
779789Sahrens 		    (!(acep[i].a_flags & ACE_INHERIT_ONLY_ACE))) {
780789Sahrens 			zfs_acl_split_ace(aclp, i);
781789Sahrens 			i++;
782789Sahrens 			continue;
783789Sahrens 		}
784789Sahrens 
785789Sahrens 		if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
786789Sahrens 		    (entry_type == OWNING_GROUP)) {
787789Sahrens 			acep[i].a_access_mask &= ~OGE_CLEAR;
788789Sahrens 			i++;
789789Sahrens 			continue;
790789Sahrens 
791789Sahrens 		} else {
792789Sahrens 			if (acep[i].a_type == ALLOW) {
793789Sahrens 
794789Sahrens 				/*
795789Sahrens 				 * Check preceding ACE if any, to see
796789Sahrens 				 * if we need to prepend a DENY ACE.
797789Sahrens 				 * This is only applicable when the acl_mode
798789Sahrens 				 * property == groupmask.
799789Sahrens 				 */
800789Sahrens 				if (zfsvfs->z_acl_mode == GROUPMASK) {
801789Sahrens 
802789Sahrens 					reuse_deny = zfs_reuse_deny(acep, i);
803789Sahrens 
804789Sahrens 					if (reuse_deny == B_FALSE) {
805789Sahrens 						zfs_acl_prepend_deny(zp, aclp,
806789Sahrens 						    i, mode);
807789Sahrens 						i++;
808789Sahrens 						acep = aclp->z_acl;
809789Sahrens 					} else {
810789Sahrens 						zfs_acl_prepend_fixup(
811789Sahrens 						    &acep[i - 1],
812789Sahrens 						    &acep[i], mode,
813789Sahrens 						    zp->z_phys->zp_uid);
814789Sahrens 					}
815789Sahrens 					zfs_fixup_group_entries(&acep[i - 1],
816789Sahrens 					    mode);
817789Sahrens 				}
818789Sahrens 			}
819789Sahrens 			i++;
820789Sahrens 		}
821789Sahrens 	}
822789Sahrens 
823789Sahrens 	/*
824789Sahrens 	 * Check out last six aces, if we have six.
825789Sahrens 	 */
826789Sahrens 
827789Sahrens 	if (aclp->z_acl_count >= 6) {
828789Sahrens 		i = aclp->z_acl_count - 6;
829789Sahrens 
830789Sahrens 		if (zfs_have_canonical_six(aclp, i)) {
831789Sahrens 			need_canonical_six = 0;
832789Sahrens 		}
833789Sahrens 	}
834789Sahrens 
835789Sahrens 	if (need_canonical_six) {
836789Sahrens 
837789Sahrens 		zfs_acl_append(aclp, 6);
838789Sahrens 		i = aclp->z_acl_count;
839789Sahrens 		acep = aclp->z_acl;
840789Sahrens 		zfs_set_ace(&acep[i++], 0, DENY, -1, ACE_OWNER);
841789Sahrens 		zfs_set_ace(&acep[i++], OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
842789Sahrens 		zfs_set_ace(&acep[i++], 0, DENY, -1, OWNING_GROUP);
843789Sahrens 		zfs_set_ace(&acep[i++], 0, ALLOW, -1, OWNING_GROUP);
844789Sahrens 		zfs_set_ace(&acep[i++], EVERYONE_DENY_MASK,
845789Sahrens 		    DENY, -1, ACE_EVERYONE);
846789Sahrens 		zfs_set_ace(&acep[i++], EVERYONE_ALLOW_MASK,
847789Sahrens 		    ALLOW, -1, ACE_EVERYONE);
848789Sahrens 		aclp->z_acl_count += 6;
849789Sahrens 	}
850789Sahrens 
851789Sahrens 	zfs_acl_fixup_canonical_six(aclp, mode);
852789Sahrens 
853789Sahrens 	zp->z_phys->zp_mode = mode;
854789Sahrens 	error = zfs_aclset_common(zp, aclp, tx, NULL);
855789Sahrens 	return (error);
856789Sahrens }
857789Sahrens 
858789Sahrens 
859789Sahrens int
860789Sahrens zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
861789Sahrens {
862789Sahrens 	zfs_acl_t *aclp;
863789Sahrens 	int error;
864789Sahrens 
865789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
866789Sahrens 	mutex_enter(&zp->z_acl_lock);
867789Sahrens 	aclp = zfs_acl_node_read(zp);
868789Sahrens 	error = zfs_acl_chmod(zp, mode, aclp, tx);
869789Sahrens 	mutex_exit(&zp->z_acl_lock);
870789Sahrens 	zfs_acl_free(aclp);
871789Sahrens 	return (error);
872789Sahrens }
873789Sahrens 
874789Sahrens /*
875789Sahrens  * strip off write_owner and write_acl
876789Sahrens  */
877789Sahrens static void
878789Sahrens zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep)
879789Sahrens {
880789Sahrens 	if ((zfsvfs->z_acl_inherit == SECURE) &&
881789Sahrens 	    acep->a_type == ALLOW)
882789Sahrens 		acep->a_access_mask &= ~SECURE_NO_INHERIT;
883789Sahrens }
884789Sahrens 
885789Sahrens /*
886789Sahrens  * inherit inheritable ACEs from parent
887789Sahrens  */
888789Sahrens static zfs_acl_t *
889789Sahrens zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
890789Sahrens {
891789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
892789Sahrens 	ace_t 		*pacep;
893789Sahrens 	ace_t		*acep;
894789Sahrens 	int 		ace_cnt = 0;
895789Sahrens 	int		pace_cnt;
896789Sahrens 	int 		i, j;
897789Sahrens 	zfs_acl_t	*aclp = NULL;
898789Sahrens 
899789Sahrens 	i = j = 0;
900789Sahrens 	pace_cnt = paclp->z_acl_count;
901789Sahrens 	pacep = paclp->z_acl;
902789Sahrens 	if (zfsvfs->z_acl_inherit != DISCARD) {
903789Sahrens 		for (i = 0; i != pace_cnt; i++) {
904789Sahrens 
905789Sahrens 			if (zfsvfs->z_acl_inherit == NOALLOW &&
906789Sahrens 			    pacep[i].a_type == ALLOW)
907789Sahrens 				continue;
908789Sahrens 
909789Sahrens 			if (zfs_ace_can_use(zp, &pacep[i])) {
910789Sahrens 				ace_cnt++;
911789Sahrens 				if (!(pacep[i].a_flags &
912789Sahrens 				    ACE_NO_PROPAGATE_INHERIT_ACE))
913789Sahrens 					ace_cnt++;
914789Sahrens 			}
915789Sahrens 		}
916789Sahrens 	}
917789Sahrens 
918789Sahrens 	aclp = zfs_acl_alloc(ace_cnt + OGE_PAD);
919789Sahrens 	if (ace_cnt && zfsvfs->z_acl_inherit != DISCARD) {
920789Sahrens 		acep = aclp->z_acl;
921789Sahrens 		pacep = paclp->z_acl;
922789Sahrens 		for (i = 0; i != pace_cnt; i++) {
923789Sahrens 
924789Sahrens 			if (zfsvfs->z_acl_inherit == NOALLOW &&
925789Sahrens 			    pacep[i].a_type == ALLOW)
926789Sahrens 				continue;
927789Sahrens 
928789Sahrens 			if (zfs_ace_can_use(zp, &pacep[i])) {
929789Sahrens 				/*
930789Sahrens 				 * Now create entry for inherited ace
931789Sahrens 				 */
932789Sahrens 				acep[j] = pacep[i];
933789Sahrens 
934789Sahrens 				if (pacep[i].a_flags &
935789Sahrens 				    ACE_NO_PROPAGATE_INHERIT_ACE) {
936789Sahrens 					acep[j].a_flags &= ~ALL_INHERIT;
937789Sahrens 					j++;
938789Sahrens 					continue;
939789Sahrens 				}
940789Sahrens 
941789Sahrens 				if (pacep[i].a_type != ALLOW &&
942789Sahrens 				    pacep[i].a_type != DENY) {
943789Sahrens 					zfs_securemode_update(zfsvfs, &acep[j]);
944789Sahrens 					j++;
945789Sahrens 					continue;
946789Sahrens 				}
947789Sahrens 
948789Sahrens 				if (ZTOV(zp)->v_type != VDIR) {
949789Sahrens 					acep[j].a_flags &= ~ALL_INHERIT;
950789Sahrens 					zfs_securemode_update(zfsvfs, &acep[j]);
951789Sahrens 					j++;
952789Sahrens 					continue;
953789Sahrens 				}
954789Sahrens 
955789Sahrens 				ASSERT(ZTOV(zp)->v_type == VDIR);
956789Sahrens 
957789Sahrens 				/*
958789Sahrens 				 * If we are inheriting an ACE targeted for
959*865Smarks 				 * only files, then make sure inherit_only
960*865Smarks 				 * is on for future propagation.
961789Sahrens 				 */
962789Sahrens 				if ((acep[j].a_flags & (ACE_FILE_INHERIT_ACE |
963*865Smarks 				    ACE_DIRECTORY_INHERIT_ACE)) ==
964*865Smarks 				    ACE_FILE_INHERIT_ACE) {
965*865Smarks 					acep[j].a_flags |= ACE_INHERIT_ONLY_ACE;
966*865Smarks 				} else {
967789Sahrens 					acep[j].a_flags &=
968789Sahrens 					    ~ACE_INHERIT_ONLY_ACE;
969*865Smarks 				}
970789Sahrens 
971789Sahrens 				zfs_securemode_update(zfsvfs, &acep[j]);
972789Sahrens 				j++;
973789Sahrens 			}
974789Sahrens 		}
975789Sahrens 	}
976789Sahrens 	aclp->z_acl_count = j;
977789Sahrens 	ASSERT(aclp->z_slots >= aclp->z_acl_count);
978789Sahrens 
979789Sahrens 	return (aclp);
980789Sahrens }
981789Sahrens 
982789Sahrens /*
983789Sahrens  * Create file system object initial permissions
984789Sahrens  * including inheritable ACEs.
985789Sahrens  */
986789Sahrens void
987789Sahrens zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
988789Sahrens     vattr_t *vap, dmu_tx_t *tx, cred_t *cr)
989789Sahrens {
990789Sahrens 	uint64_t	mode;
991789Sahrens 	uid_t		uid;
992789Sahrens 	gid_t		gid;
993789Sahrens 	int		error;
994789Sahrens 	int		pull_down;
995789Sahrens 	zfs_acl_t	*aclp, *paclp;
996789Sahrens 
997789Sahrens 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
998789Sahrens 
999789Sahrens 	/*
1000789Sahrens 	 * Determine uid and gid.
1001789Sahrens 	 */
1002789Sahrens 	if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
1003789Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
1004789Sahrens 		uid = vap->va_uid;
1005789Sahrens 		gid = vap->va_gid;
1006789Sahrens 	} else {
1007789Sahrens 		uid = crgetuid(cr);
1008789Sahrens 		if ((vap->va_mask & AT_GID) &&
1009789Sahrens 		    ((vap->va_gid == parent->z_phys->zp_gid) ||
1010789Sahrens 		    groupmember(vap->va_gid, cr) ||
1011789Sahrens 		    secpolicy_vnode_create_gid(cr)))
1012789Sahrens 			gid = vap->va_gid;
1013789Sahrens 		else
1014789Sahrens 			gid = (parent->z_phys->zp_mode & S_ISGID) ?
1015789Sahrens 			    parent->z_phys->zp_gid : crgetgid(cr);
1016789Sahrens 	}
1017789Sahrens 
1018789Sahrens 	/*
1019789Sahrens 	 * If we're creating a directory, and the parent directory has the
1020789Sahrens 	 * set-GID bit set, set in on the new directory.
1021789Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1022789Sahrens 	 * file's new group, clear the file's set-GID bit.
1023789Sahrens 	 */
1024789Sahrens 
1025789Sahrens 	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR))
1026789Sahrens 		mode |= S_ISGID;
1027789Sahrens 	else {
1028789Sahrens 		if ((mode & S_ISGID) &&
1029789Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
1030789Sahrens 			mode &= ~S_ISGID;
1031789Sahrens 	}
1032789Sahrens 
1033789Sahrens 	zp->z_phys->zp_uid = uid;
1034789Sahrens 	zp->z_phys->zp_gid = gid;
1035789Sahrens 	zp->z_phys->zp_mode = mode;
1036789Sahrens 
1037789Sahrens 	mutex_enter(&parent->z_lock);
1038789Sahrens 	pull_down = (parent->z_phys->zp_flags & ZFS_INHERIT_ACE);
1039789Sahrens 	if (pull_down) {
1040789Sahrens 		mutex_enter(&parent->z_acl_lock);
1041789Sahrens 		paclp = zfs_acl_node_read(parent);
1042789Sahrens 		mutex_exit(&parent->z_acl_lock);
1043789Sahrens 		aclp = zfs_acl_inherit(zp, paclp);
1044789Sahrens 		zfs_acl_free(paclp);
1045789Sahrens 	} else {
1046789Sahrens 		aclp = zfs_acl_alloc(6);
1047789Sahrens 	}
1048789Sahrens 	mutex_exit(&parent->z_lock);
1049789Sahrens 	mutex_enter(&zp->z_lock);
1050789Sahrens 	mutex_enter(&zp->z_acl_lock);
1051789Sahrens 	error = zfs_acl_chmod(zp, mode, aclp, tx);
1052789Sahrens 	mutex_exit(&zp->z_lock);
1053789Sahrens 	mutex_exit(&zp->z_acl_lock);
1054789Sahrens 	ASSERT3U(error, ==, 0);
1055789Sahrens 	zfs_acl_free(aclp);
1056789Sahrens }
1057789Sahrens 
1058789Sahrens /*
1059789Sahrens  * Can use be used for inheritance
1060789Sahrens  */
1061789Sahrens static int
1062789Sahrens zfs_ace_can_use(znode_t *zp, ace_t *acep)
1063789Sahrens {
1064789Sahrens 	int vtype = ZTOV(zp)->v_type;
1065789Sahrens 
1066789Sahrens 	int	iflags = (acep->a_flags & 0xf);
1067789Sahrens 
1068789Sahrens 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
1069789Sahrens 		return (1);
1070789Sahrens 
1071789Sahrens 	else if (iflags & ACE_FILE_INHERIT_ACE)
1072789Sahrens 		return (1);
1073789Sahrens 
1074789Sahrens 	return (0);
1075789Sahrens }
1076789Sahrens 
1077789Sahrens /*
1078789Sahrens  * Retrieve a files ACL
1079789Sahrens  */
1080789Sahrens int
1081789Sahrens zfs_getacl(znode_t *zp, vsecattr_t  *vsecp, cred_t *cr)
1082789Sahrens {
1083789Sahrens 	zfs_acl_t	*aclp;
1084789Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1085789Sahrens 	int		error;
1086789Sahrens 
1087789Sahrens 	if (error = zfs_zaccess(zp, ACE_READ_ACL, cr)) {
1088789Sahrens 		/*
1089789Sahrens 		 * If owner of file then allow reading of the
1090789Sahrens 		 * ACL.
1091789Sahrens 		 */
1092789Sahrens 		if (crgetuid(cr) != zp->z_phys->zp_uid)
1093789Sahrens 			return (error);
1094789Sahrens 	}
1095789Sahrens 
1096789Sahrens 	if (mask == 0)
1097789Sahrens 		return (ENOSYS);
1098789Sahrens 
1099789Sahrens 	mutex_enter(&zp->z_acl_lock);
1100789Sahrens 
1101789Sahrens 	aclp = zfs_acl_node_read(zp);
1102789Sahrens 
1103789Sahrens 	if (mask & VSA_ACECNT) {
1104789Sahrens 		vsecp->vsa_aclcnt = aclp->z_acl_count;
1105789Sahrens 	}
1106789Sahrens 
1107789Sahrens 	if (mask & VSA_ACE) {
1108789Sahrens 		vsecp->vsa_aclentp = kmem_alloc(aclp->z_acl_count *
1109789Sahrens 		    sizeof (ace_t), KM_SLEEP);
1110789Sahrens 		bcopy(aclp->z_acl, vsecp->vsa_aclentp,
1111789Sahrens 		    aclp->z_acl_count * sizeof (ace_t));
1112789Sahrens 	}
1113789Sahrens 
1114789Sahrens 	mutex_exit(&zp->z_acl_lock);
1115789Sahrens 
1116789Sahrens 	zfs_acl_free(aclp);
1117789Sahrens 
1118789Sahrens 	return (0);
1119789Sahrens }
1120789Sahrens 
1121789Sahrens /*
1122789Sahrens  * Set a files ACL
1123789Sahrens  */
1124789Sahrens int
1125789Sahrens zfs_setacl(znode_t *zp, vsecattr_t *vsecp, cred_t *cr)
1126789Sahrens {
1127789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1128789Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
1129789Sahrens 	ace_t		*acep = vsecp->vsa_aclentp;
1130789Sahrens 	int		aclcnt = vsecp->vsa_aclcnt;
1131789Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1132789Sahrens 	dmu_tx_t	*tx;
1133789Sahrens 	int		error;
1134789Sahrens 	int		inherit;
1135789Sahrens 	zfs_acl_t	*aclp;
1136789Sahrens 	uint64_t	seq = 0;
1137789Sahrens 
1138789Sahrens 	if (mask == 0)
1139789Sahrens 		return (EINVAL);
1140789Sahrens 
1141789Sahrens 	if (!zfs_acl_valid(zp, acep, aclcnt, &inherit))
1142789Sahrens 		return (EINVAL);
1143789Sahrens top:
1144789Sahrens 	error = zfs_zaccess_v4_perm(zp, ACE_WRITE_ACL, cr);
1145789Sahrens 	if (error == EACCES || error == ACCESS_UNDETERMINED) {
1146789Sahrens 		if ((error = secpolicy_vnode_setdac(cr,
1147789Sahrens 		    zp->z_phys->zp_uid)) != 0) {
1148789Sahrens 			return (error);
1149789Sahrens 		}
1150789Sahrens 	} else if (error) {
1151789Sahrens 		return (error == EROFS ? error : EPERM);
1152789Sahrens 	}
1153789Sahrens 
1154789Sahrens 	mutex_enter(&zp->z_lock);
1155789Sahrens 	mutex_enter(&zp->z_acl_lock);
1156789Sahrens 
1157789Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
1158789Sahrens 	dmu_tx_hold_bonus(tx, zp->z_id);
1159789Sahrens 
1160789Sahrens 	if (zp->z_phys->zp_acl.z_acl_extern_obj) {
1161789Sahrens 		dmu_tx_hold_write(tx, zp->z_phys->zp_acl.z_acl_extern_obj,
1162789Sahrens 		    0, ZFS_ACL_SIZE(aclcnt));
1163789Sahrens 	} else if (aclcnt > ACE_SLOT_CNT) {
1164789Sahrens 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, ZFS_ACL_SIZE(aclcnt));
1165789Sahrens 	}
1166789Sahrens 
1167789Sahrens 	error = dmu_tx_assign(tx, zfsvfs->z_assign);
1168789Sahrens 	if (error) {
1169789Sahrens 		dmu_tx_abort(tx);
1170789Sahrens 
1171789Sahrens 		mutex_exit(&zp->z_acl_lock);
1172789Sahrens 		mutex_exit(&zp->z_lock);
1173789Sahrens 
1174789Sahrens 		if (error == ERESTART && zfsvfs->z_assign == TXG_NOWAIT) {
1175789Sahrens 			txg_wait_open(dmu_objset_pool(zfsvfs->z_os), 0);
1176789Sahrens 			goto top;
1177789Sahrens 		}
1178789Sahrens 		return (error);
1179789Sahrens 	}
1180789Sahrens 
1181789Sahrens 	aclp = zfs_acl_alloc(aclcnt);
1182789Sahrens 	bcopy(acep, aclp->z_acl, sizeof (ace_t) * aclcnt);
1183789Sahrens 	aclp->z_acl_count = aclcnt;
1184789Sahrens 	error = zfs_aclset_common(zp, aclp, tx, &inherit);
1185789Sahrens 	ASSERT(error == 0);
1186789Sahrens 
1187789Sahrens 	zfs_acl_free(aclp);
1188789Sahrens 	seq = zfs_log_acl(zilog, tx, TX_ACL, zp, aclcnt, acep);
1189789Sahrens 	dmu_tx_commit(tx);
1190789Sahrens done:
1191789Sahrens 	mutex_exit(&zp->z_acl_lock);
1192789Sahrens 	mutex_exit(&zp->z_lock);
1193789Sahrens 
1194789Sahrens 	zil_commit(zilog, seq, 0);
1195789Sahrens 
1196789Sahrens 	return (error);
1197789Sahrens }
1198789Sahrens 
1199789Sahrens static int
1200789Sahrens zfs_ace_access(ace_t *zacep, int mode_wanted, int *working_mode)
1201789Sahrens {
1202789Sahrens 	if ((*working_mode & mode_wanted) == mode_wanted) {
1203789Sahrens 		return (0);
1204789Sahrens 	}
1205789Sahrens 
1206789Sahrens 	if (zacep->a_access_mask & mode_wanted) {
1207789Sahrens 		if (zacep->a_type == ALLOW) {
1208789Sahrens 			*working_mode |= (mode_wanted & zacep->a_access_mask);
1209789Sahrens 			if ((*working_mode & mode_wanted) == mode_wanted)
1210789Sahrens 				return (0);
1211789Sahrens 		} else if (zacep->a_type == DENY) {
1212789Sahrens 			return (EACCES);
1213789Sahrens 		}
1214789Sahrens 	}
1215789Sahrens 
1216789Sahrens 	/*
1217789Sahrens 	 * haven't been specifcally denied at this point
1218789Sahrens 	 * so return UNDETERMINED.
1219789Sahrens 	 */
1220789Sahrens 
1221789Sahrens 	return (ACCESS_UNDETERMINED);
1222789Sahrens }
1223789Sahrens 
1224789Sahrens 
1225789Sahrens static int
1226789Sahrens zfs_zaccess_common(znode_t *zp, int v4_mode, int *working_mode, cred_t *cr)
1227789Sahrens {
1228789Sahrens 	zfs_acl_t	*aclp;
1229789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1230789Sahrens 	ace_t		*zacep;
1231789Sahrens 	gid_t		gid;
1232789Sahrens 	int		mode_wanted = v4_mode;
1233789Sahrens 	int		cnt;
1234789Sahrens 	int		i;
1235789Sahrens 	int		access_deny = ACCESS_UNDETERMINED;
1236789Sahrens 	uint_t		entry_type;
1237789Sahrens 	uid_t		uid = crgetuid(cr);
1238789Sahrens 
1239789Sahrens 	*working_mode = 0;
1240789Sahrens 
1241789Sahrens 	if (zfsvfs->z_assign >= TXG_INITIAL)		/* ZIL replay */
1242789Sahrens 		return (0);
1243789Sahrens 
1244789Sahrens 	if ((v4_mode & WRITE_MASK) &&
1245789Sahrens 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
1246789Sahrens 	    (!IS_DEVVP(ZTOV(zp)))) {
1247789Sahrens 		return (EROFS);
1248789Sahrens 	}
1249789Sahrens 
1250789Sahrens 	mutex_enter(&zp->z_acl_lock);
1251789Sahrens 
1252789Sahrens 	aclp = zfs_acl_node_read(zp);
1253789Sahrens 
1254789Sahrens 	zacep = aclp->z_acl;
1255789Sahrens 	cnt = aclp->z_acl_count;
1256789Sahrens 
1257789Sahrens 	for (i = 0; i != cnt; i++) {
1258789Sahrens 
1259789Sahrens 		if (zacep[i].a_flags & ACE_INHERIT_ONLY_ACE)
1260789Sahrens 			continue;
1261789Sahrens 
1262789Sahrens 		entry_type = (zacep[i].a_flags & 0xf040);
1263789Sahrens 		switch (entry_type) {
1264789Sahrens 		case ACE_OWNER:
1265789Sahrens 			if (uid == zp->z_phys->zp_uid) {
1266789Sahrens 				access_deny = zfs_ace_access(&zacep[i],
1267789Sahrens 				    mode_wanted, working_mode);
1268789Sahrens 			}
1269789Sahrens 			break;
1270789Sahrens 		case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
1271789Sahrens 		case ACE_IDENTIFIER_GROUP:
1272789Sahrens 			/*
1273789Sahrens 			 * Owning group gid is in znode not ACL
1274789Sahrens 			 */
1275789Sahrens 			if (entry_type == (ACE_IDENTIFIER_GROUP | ACE_GROUP))
1276789Sahrens 				gid = zp->z_phys->zp_gid;
1277789Sahrens 			else
1278789Sahrens 				gid = zacep[i].a_who;
1279789Sahrens 
1280789Sahrens 			if (groupmember(gid, cr)) {
1281789Sahrens 				access_deny = zfs_ace_access(&zacep[i],
1282789Sahrens 				    mode_wanted, working_mode);
1283789Sahrens 			}
1284789Sahrens 			break;
1285789Sahrens 		case ACE_EVERYONE:
1286789Sahrens 			access_deny = zfs_ace_access(&zacep[i],
1287789Sahrens 			    mode_wanted, working_mode);
1288789Sahrens 			break;
1289789Sahrens 
1290789Sahrens 		/* USER Entry */
1291789Sahrens 		default:
1292789Sahrens 			if (entry_type == 0) {
1293789Sahrens 				if (uid == zacep[i].a_who) {
1294789Sahrens 					access_deny = zfs_ace_access(&zacep[i],
1295789Sahrens 					    mode_wanted, working_mode);
1296789Sahrens 				}
1297789Sahrens 				break;
1298789Sahrens 			}
1299789Sahrens 			zfs_acl_free(aclp);
1300789Sahrens 			mutex_exit(&zp->z_acl_lock);
1301789Sahrens 			return (EIO);
1302789Sahrens 		}
1303789Sahrens 
1304789Sahrens 		if (access_deny != ACCESS_UNDETERMINED)
1305789Sahrens 			break;
1306789Sahrens 
1307789Sahrens 	}
1308789Sahrens 
1309789Sahrens 	mutex_exit(&zp->z_acl_lock);
1310789Sahrens 	zfs_acl_free(aclp);
1311789Sahrens 
1312789Sahrens 	return (access_deny);
1313789Sahrens }
1314789Sahrens 
1315789Sahrens 
1316789Sahrens /*
1317789Sahrens  * Determine whether Access should be granted/denied, invoking least
1318789Sahrens  * priv subsytem when a deny is determined.
1319789Sahrens  */
1320789Sahrens int
1321789Sahrens zfs_zaccess(znode_t *zp, int mode, cred_t *cr)
1322789Sahrens {
1323789Sahrens 	int	working_mode = 0;
1324789Sahrens 	int	error;
1325789Sahrens 	int	is_attr;
1326789Sahrens 	znode_t	*xzp;
1327789Sahrens 	znode_t *check_zp = zp;
1328789Sahrens 
1329789Sahrens 	is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
1330789Sahrens 	    (ZTOV(zp)->v_type == VDIR));
1331789Sahrens 
1332789Sahrens 	/*
1333789Sahrens 	 * If attribute then validate against base file
1334789Sahrens 	 */
1335789Sahrens 	if (is_attr) {
1336789Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
1337789Sahrens 		    zp->z_phys->zp_parent, &xzp)) != 0)	{
1338789Sahrens 			return (error);
1339789Sahrens 		}
1340789Sahrens 		check_zp = xzp;
1341789Sahrens 		/*
1342789Sahrens 		 * fixup mode to map to xattr perms
1343789Sahrens 		 */
1344789Sahrens 
1345789Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
1346789Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
1347789Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
1348789Sahrens 		}
1349789Sahrens 
1350789Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
1351789Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
1352789Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
1353789Sahrens 		}
1354789Sahrens 	}
1355789Sahrens 
1356789Sahrens 	error = zfs_zaccess_common(check_zp, mode, &working_mode, cr);
1357789Sahrens 
1358789Sahrens 	if (error == EROFS) {
1359789Sahrens 		if (is_attr)
1360789Sahrens 			VN_RELE(ZTOV(xzp));
1361789Sahrens 		return (error);
1362789Sahrens 	}
1363789Sahrens 
1364789Sahrens 	if (error || (working_mode != mode)) {
1365789Sahrens 		error = secpolicy_vnode_access(cr, ZTOV(check_zp),
1366789Sahrens 		    check_zp->z_phys->zp_uid, ~zfs_v4_to_unix(working_mode));
1367789Sahrens 	}
1368789Sahrens 
1369789Sahrens 	if (is_attr)
1370789Sahrens 		VN_RELE(ZTOV(xzp));
1371789Sahrens 
1372789Sahrens 	return (error);
1373789Sahrens }
1374789Sahrens 
1375789Sahrens /*
1376789Sahrens  * Special zaccess function to check for special nfsv4 perm.
1377789Sahrens  * doesn't call secpolicy_vnode_access() for failure, since that
1378789Sahrens  * would probably be the wrong policy function to call.
1379789Sahrens  * instead its up to the caller to handle that situation.
1380789Sahrens  */
1381789Sahrens 
1382789Sahrens int
1383789Sahrens zfs_zaccess_v4_perm(znode_t *zp, int mode, cred_t *cr)
1384789Sahrens {
1385789Sahrens 	int working_mode = 0;
1386789Sahrens 	return (zfs_zaccess_common(zp, mode, &working_mode, cr));
1387789Sahrens }
1388789Sahrens 
1389789Sahrens /*
1390789Sahrens  * Translate tradition unix VREAD/VWRITE/VEXEC mode into
1391789Sahrens  * native ACL format and call zfs_zaccess()
1392789Sahrens  */
1393789Sahrens int
1394789Sahrens zfs_zaccess_rwx(znode_t *zp, mode_t mode, cred_t *cr)
1395789Sahrens {
1396789Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
1397789Sahrens 
1398789Sahrens 	return (zfs_zaccess(zp, v4_mode, cr));
1399789Sahrens }
1400789Sahrens 
1401789Sahrens /*
1402789Sahrens  * Determine whether Access should be granted/deny, without
1403789Sahrens  * consulting least priv subsystem.
1404789Sahrens  *
1405789Sahrens  *
1406789Sahrens  * The following chart is the recommended NFSv4 enforcement for
1407789Sahrens  * ability to delete an object.
1408789Sahrens  *
1409789Sahrens  *      -------------------------------------------------------
1410789Sahrens  *      |   Parent Dir  |           Target Object Permissions |
1411789Sahrens  *      |  permissions  |                                     |
1412789Sahrens  *      -------------------------------------------------------
1413789Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
1414789Sahrens  *      |               |  Delete    |  Delete   | unspecified|
1415789Sahrens  *      -------------------------------------------------------
1416789Sahrens  *      |  ACL Allows   | Permit     | Permit    | Permit     |
1417789Sahrens  *      |  DELETE_CHILD |                                     |
1418789Sahrens  *      -------------------------------------------------------
1419789Sahrens  *      |  ACL Denies   | Permit     | Deny      | Deny       |
1420789Sahrens  *      |  DELETE_CHILD |            |           |            |
1421789Sahrens  *      -------------------------------------------------------
1422789Sahrens  *      | ACL specifies |            |           |            |
1423789Sahrens  *      | only allow    | Permit     | Permit    | Permit     |
1424789Sahrens  *      | write and     |            |           |            |
1425789Sahrens  *      | execute       |            |           |            |
1426789Sahrens  *      -------------------------------------------------------
1427789Sahrens  *      | ACL denies    |            |           |            |
1428789Sahrens  *      | write and     | Permit     | Deny      | Deny       |
1429789Sahrens  *      | execute       |            |           |            |
1430789Sahrens  *      -------------------------------------------------------
1431789Sahrens  *         ^
1432789Sahrens  *         |
1433789Sahrens  *         No search privilege, can't even look up file?
1434789Sahrens  *
1435789Sahrens  */
1436789Sahrens int
1437789Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
1438789Sahrens {
1439789Sahrens 	int dzp_working_mode = 0;
1440789Sahrens 	int zp_working_mode = 0;
1441789Sahrens 	int dzp_error, zp_error;
1442789Sahrens 
1443789Sahrens 	/*
1444789Sahrens 	 * Arghh, this check is going to require a couple of questions
1445789Sahrens 	 * to be asked.  We want specific DELETE permissions to
1446789Sahrens 	 * take precedence over WRITE/EXECUTE.  We don't
1447789Sahrens 	 * want an ACL such as this to mess us up.
1448789Sahrens 	 * user:sloar:write_data:deny,user:sloar:delete:allow
1449789Sahrens 	 *
1450789Sahrens 	 * However, deny permissions may ultimately be overridden
1451789Sahrens 	 * by secpolicy_vnode_access().
1452789Sahrens 	 */
1453789Sahrens 
1454789Sahrens 	dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
1455789Sahrens 	    &dzp_working_mode, cr);
1456789Sahrens 	zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, cr);
1457789Sahrens 
1458789Sahrens 	if (dzp_error == EROFS || zp_error == EROFS)
1459789Sahrens 		return (dzp_error);
1460789Sahrens 
1461789Sahrens 	/*
1462789Sahrens 	 * First handle the first row
1463789Sahrens 	 */
1464789Sahrens 	if (dzp_working_mode & ACE_DELETE_CHILD)
1465789Sahrens 		return (0);
1466789Sahrens 
1467789Sahrens 	/*
1468789Sahrens 	 * Second row
1469789Sahrens 	 */
1470789Sahrens 
1471789Sahrens 	if (zp_working_mode & ACE_DELETE)
1472789Sahrens 		return (0);
1473789Sahrens 
1474789Sahrens 	/*
1475789Sahrens 	 * Third Row
1476789Sahrens 	 */
1477789Sahrens 
1478789Sahrens 	dzp_error = zfs_zaccess_common(dzp, ACE_WRITE_DATA|ACE_EXECUTE,
1479789Sahrens 	    &dzp_working_mode, cr);
1480789Sahrens 
1481789Sahrens 	if (dzp_error == EROFS)
1482789Sahrens 		return (dzp_error);
1483789Sahrens 
1484789Sahrens 	if (dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE))
1485789Sahrens 		return (0);
1486789Sahrens 
1487789Sahrens 	/*
1488789Sahrens 	 * Fourth Row
1489789Sahrens 	 */
1490789Sahrens 
1491789Sahrens 	if (((dzp_working_mode & (ACE_WRITE_DATA|ACE_EXECUTE)) == 0) &&
1492789Sahrens 	    (zp_working_mode & ACE_DELETE))
1493789Sahrens 		return (0);
1494789Sahrens 
1495789Sahrens 	return (secpolicy_vnode_access(cr, ZTOV(zp), dzp->z_phys->zp_uid,
1496789Sahrens 	    S_IWRITE|S_IEXEC));
1497789Sahrens }
1498789Sahrens 
1499789Sahrens int
1500789Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
1501789Sahrens     znode_t *tzp, cred_t *cr)
1502789Sahrens {
1503789Sahrens 	int add_perm;
1504789Sahrens 	int error;
1505789Sahrens 
1506789Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
1507789Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
1508789Sahrens 
1509789Sahrens 	/*
1510789Sahrens 	 * Rename permissions are combination of delete permission +
1511789Sahrens 	 * add file/subdir permission.
1512789Sahrens 	 */
1513789Sahrens 
1514789Sahrens 	/*
1515789Sahrens 	 * first make sure we do the delete portion.
1516789Sahrens 	 *
1517789Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
1518789Sahrens 	 */
1519789Sahrens 
1520789Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
1521789Sahrens 		return (error);
1522789Sahrens 
1523789Sahrens 	/*
1524789Sahrens 	 * If we have a tzp, see if we can delete it?
1525789Sahrens 	 */
1526789Sahrens 	if (tzp) {
1527789Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
1528789Sahrens 			return (error);
1529789Sahrens 	}
1530789Sahrens 
1531789Sahrens 	/*
1532789Sahrens 	 * Now check for add permissions
1533789Sahrens 	 */
1534789Sahrens 	if (error = zfs_zaccess(sdzp, add_perm, cr))
1535789Sahrens 		return (error);
1536789Sahrens 
1537789Sahrens 	error = zfs_sticky_remove_access(sdzp, szp, cr);
1538789Sahrens 
1539789Sahrens 	return (error);
1540789Sahrens }
1541