xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision 8952:c2f95230b0ff)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51544Seschrock  * Common Development and Distribution License (the "License").
61544Seschrock  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21789Sahrens /*
22*8952SMark.Shellenbaum@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #include <sys/types.h>
27789Sahrens #include <sys/param.h>
28789Sahrens #include <sys/time.h>
29789Sahrens #include <sys/systm.h>
30789Sahrens #include <sys/sysmacros.h>
31789Sahrens #include <sys/resource.h>
32789Sahrens #include <sys/vfs.h>
33789Sahrens #include <sys/vnode.h>
345331Samw #include <sys/sid.h>
35789Sahrens #include <sys/file.h>
36789Sahrens #include <sys/stat.h>
37789Sahrens #include <sys/kmem.h>
38789Sahrens #include <sys/cmn_err.h>
39789Sahrens #include <sys/errno.h>
40789Sahrens #include <sys/unistd.h>
411576Smarks #include <sys/sdt.h>
42789Sahrens #include <sys/fs/zfs.h>
43789Sahrens #include <sys/mode.h>
44789Sahrens #include <sys/policy.h>
45789Sahrens #include <sys/zfs_znode.h>
465331Samw #include <sys/zfs_fuid.h>
47789Sahrens #include <sys/zfs_acl.h>
48789Sahrens #include <sys/zfs_dir.h>
49789Sahrens #include <sys/zfs_vfsops.h>
50789Sahrens #include <sys/dmu.h>
515331Samw #include <sys/dnode.h>
52789Sahrens #include <sys/zap.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
585331Samw #define	MAX_ACE_TYPE	ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
597559SMark.Shellenbaum@Sun.COM #define	MIN_ACE_TYPE	ALLOW
60789Sahrens 
61789Sahrens #define	OWNING_GROUP		(ACE_GROUP|ACE_IDENTIFIER_GROUP)
62789Sahrens #define	EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
63789Sahrens     ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE)
64789Sahrens #define	EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
65789Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
66789Sahrens #define	OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
67789Sahrens     ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS)
685331Samw 
695331Samw #define	ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
705331Samw     ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
715331Samw     ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
725331Samw     ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
735331Samw 
74*8952SMark.Shellenbaum@Sun.COM #define	WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
75*8952SMark.Shellenbaum@Sun.COM #define	WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
76*8952SMark.Shellenbaum@Sun.COM     ACE_DELETE|ACE_DELETE_CHILD)
77*8952SMark.Shellenbaum@Sun.COM #define	WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS)
78789Sahrens 
79789Sahrens #define	OGE_CLEAR	(ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
80789Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
81789Sahrens 
82789Sahrens #define	OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
83789Sahrens     ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
84789Sahrens 
85789Sahrens #define	ALL_INHERIT	(ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
865331Samw     ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
87789Sahrens 
886385Smarks #define	RESTRICTED_CLEAR	(ACE_WRITE_ACL|ACE_WRITE_OWNER)
89789Sahrens 
905331Samw #define	V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
915331Samw     ZFS_ACL_PROTECTED)
925331Samw 
935331Samw #define	ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
945331Samw     ZFS_ACL_OBJ_ACE)
955331Samw 
965331Samw static uint16_t
975331Samw zfs_ace_v0_get_type(void *acep)
985331Samw {
995331Samw 	return (((zfs_oldace_t *)acep)->z_type);
1005331Samw }
1015331Samw 
1025331Samw static uint16_t
1035331Samw zfs_ace_v0_get_flags(void *acep)
1045331Samw {
1055331Samw 	return (((zfs_oldace_t *)acep)->z_flags);
1065331Samw }
1075331Samw 
1085331Samw static uint32_t
1095331Samw zfs_ace_v0_get_mask(void *acep)
1105331Samw {
1115331Samw 	return (((zfs_oldace_t *)acep)->z_access_mask);
1125331Samw }
1135331Samw 
1145331Samw static uint64_t
1155331Samw zfs_ace_v0_get_who(void *acep)
1165331Samw {
1175331Samw 	return (((zfs_oldace_t *)acep)->z_fuid);
1185331Samw }
1195331Samw 
1205331Samw static void
1215331Samw zfs_ace_v0_set_type(void *acep, uint16_t type)
1225331Samw {
1235331Samw 	((zfs_oldace_t *)acep)->z_type = type;
1245331Samw }
1255331Samw 
1265331Samw static void
1275331Samw zfs_ace_v0_set_flags(void *acep, uint16_t flags)
1285331Samw {
1295331Samw 	((zfs_oldace_t *)acep)->z_flags = flags;
1305331Samw }
1315331Samw 
1325331Samw static void
1335331Samw zfs_ace_v0_set_mask(void *acep, uint32_t mask)
1345331Samw {
1355331Samw 	((zfs_oldace_t *)acep)->z_access_mask = mask;
1365331Samw }
1375331Samw 
1385331Samw static void
1395331Samw zfs_ace_v0_set_who(void *acep, uint64_t who)
1405331Samw {
1415331Samw 	((zfs_oldace_t *)acep)->z_fuid = who;
1425331Samw }
1435331Samw 
1445331Samw /*ARGSUSED*/
1455331Samw static size_t
1465331Samw zfs_ace_v0_size(void *acep)
1475331Samw {
1485331Samw 	return (sizeof (zfs_oldace_t));
1495331Samw }
1505331Samw 
1515331Samw static size_t
1525331Samw zfs_ace_v0_abstract_size(void)
1535331Samw {
1545331Samw 	return (sizeof (zfs_oldace_t));
1555331Samw }
1565331Samw 
1575331Samw static int
1585331Samw zfs_ace_v0_mask_off(void)
1595331Samw {
1605331Samw 	return (offsetof(zfs_oldace_t, z_access_mask));
1615331Samw }
1625331Samw 
1635331Samw /*ARGSUSED*/
1645331Samw static int
1655331Samw zfs_ace_v0_data(void *acep, void **datap)
1665331Samw {
1675331Samw 	*datap = NULL;
1685331Samw 	return (0);
1695331Samw }
1705331Samw 
1715331Samw static acl_ops_t zfs_acl_v0_ops = {
1725331Samw 	zfs_ace_v0_get_mask,
1735331Samw 	zfs_ace_v0_set_mask,
1745331Samw 	zfs_ace_v0_get_flags,
1755331Samw 	zfs_ace_v0_set_flags,
1765331Samw 	zfs_ace_v0_get_type,
1775331Samw 	zfs_ace_v0_set_type,
1785331Samw 	zfs_ace_v0_get_who,
1795331Samw 	zfs_ace_v0_set_who,
1805331Samw 	zfs_ace_v0_size,
1815331Samw 	zfs_ace_v0_abstract_size,
1825331Samw 	zfs_ace_v0_mask_off,
1835331Samw 	zfs_ace_v0_data
1845331Samw };
1855331Samw 
1865331Samw static uint16_t
1875331Samw zfs_ace_fuid_get_type(void *acep)
1885331Samw {
1895331Samw 	return (((zfs_ace_hdr_t *)acep)->z_type);
1905331Samw }
1915331Samw 
1925331Samw static uint16_t
1935331Samw zfs_ace_fuid_get_flags(void *acep)
1945331Samw {
1955331Samw 	return (((zfs_ace_hdr_t *)acep)->z_flags);
1965331Samw }
1975331Samw 
1985331Samw static uint32_t
1995331Samw zfs_ace_fuid_get_mask(void *acep)
2005331Samw {
2015331Samw 	return (((zfs_ace_hdr_t *)acep)->z_access_mask);
2025331Samw }
2035331Samw 
2045331Samw static uint64_t
2055331Samw zfs_ace_fuid_get_who(void *args)
2065331Samw {
2075331Samw 	uint16_t entry_type;
2085331Samw 	zfs_ace_t *acep = args;
2095331Samw 
2105331Samw 	entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
211789Sahrens 
2125331Samw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
2135331Samw 	    entry_type == ACE_EVERYONE)
2145331Samw 		return (-1);
2155331Samw 	return (((zfs_ace_t *)acep)->z_fuid);
2165331Samw }
2175331Samw 
2185331Samw static void
2195331Samw zfs_ace_fuid_set_type(void *acep, uint16_t type)
2205331Samw {
2215331Samw 	((zfs_ace_hdr_t *)acep)->z_type = type;
2225331Samw }
2235331Samw 
2245331Samw static void
2255331Samw zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
2265331Samw {
2275331Samw 	((zfs_ace_hdr_t *)acep)->z_flags = flags;
2285331Samw }
2295331Samw 
2305331Samw static void
2315331Samw zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
2325331Samw {
2335331Samw 	((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
2345331Samw }
2355331Samw 
2365331Samw static void
2375331Samw zfs_ace_fuid_set_who(void *arg, uint64_t who)
2385331Samw {
2395331Samw 	zfs_ace_t *acep = arg;
2405331Samw 
2415331Samw 	uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
2425331Samw 
2435331Samw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
2445331Samw 	    entry_type == ACE_EVERYONE)
2455331Samw 		return;
2465331Samw 	acep->z_fuid = who;
2475331Samw }
2485331Samw 
2495331Samw static size_t
2505331Samw zfs_ace_fuid_size(void *acep)
2515331Samw {
2525331Samw 	zfs_ace_hdr_t *zacep = acep;
2535331Samw 	uint16_t entry_type;
2545331Samw 
2555331Samw 	switch (zacep->z_type) {
2565331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
2575331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
2585331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
2595331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
2605331Samw 		return (sizeof (zfs_object_ace_t));
2615331Samw 	case ALLOW:
2625331Samw 	case DENY:
2635331Samw 		entry_type =
2645331Samw 		    (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
2655331Samw 		if (entry_type == ACE_OWNER ||
2667328SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP ||
2675331Samw 		    entry_type == ACE_EVERYONE)
2685331Samw 			return (sizeof (zfs_ace_hdr_t));
2695331Samw 		/*FALLTHROUGH*/
2705331Samw 	default:
2715331Samw 		return (sizeof (zfs_ace_t));
2725331Samw 	}
2735331Samw }
2745331Samw 
2755331Samw static size_t
2765331Samw zfs_ace_fuid_abstract_size(void)
2775331Samw {
2785331Samw 	return (sizeof (zfs_ace_hdr_t));
2795331Samw }
2805331Samw 
2815331Samw static int
2825331Samw zfs_ace_fuid_mask_off(void)
2835331Samw {
2845331Samw 	return (offsetof(zfs_ace_hdr_t, z_access_mask));
2855331Samw }
2865331Samw 
2875331Samw static int
2885331Samw zfs_ace_fuid_data(void *acep, void **datap)
2895331Samw {
2905331Samw 	zfs_ace_t *zacep = acep;
2915331Samw 	zfs_object_ace_t *zobjp;
2925331Samw 
2935331Samw 	switch (zacep->z_hdr.z_type) {
2945331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
2955331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
2965331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
2975331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
2985331Samw 		zobjp = acep;
2995331Samw 		*datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
3005331Samw 		return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
3015331Samw 	default:
3025331Samw 		*datap = NULL;
3035331Samw 		return (0);
3045331Samw 	}
3055331Samw }
3065331Samw 
3075331Samw static acl_ops_t zfs_acl_fuid_ops = {
3085331Samw 	zfs_ace_fuid_get_mask,
3095331Samw 	zfs_ace_fuid_set_mask,
3105331Samw 	zfs_ace_fuid_get_flags,
3115331Samw 	zfs_ace_fuid_set_flags,
3125331Samw 	zfs_ace_fuid_get_type,
3135331Samw 	zfs_ace_fuid_set_type,
3145331Samw 	zfs_ace_fuid_get_who,
3155331Samw 	zfs_ace_fuid_set_who,
3165331Samw 	zfs_ace_fuid_size,
3175331Samw 	zfs_ace_fuid_abstract_size,
3185331Samw 	zfs_ace_fuid_mask_off,
3195331Samw 	zfs_ace_fuid_data
3205331Samw };
3215331Samw 
3225331Samw static int
3235331Samw zfs_acl_version(int version)
3245331Samw {
3255331Samw 	if (version < ZPL_VERSION_FUID)
3265331Samw 		return (ZFS_ACL_VERSION_INITIAL);
3275331Samw 	else
3285331Samw 		return (ZFS_ACL_VERSION_FUID);
3295331Samw }
3305331Samw 
3315331Samw static int
3325331Samw zfs_acl_version_zp(znode_t *zp)
3335331Samw {
3345331Samw 	return (zfs_acl_version(zp->z_zfsvfs->z_version));
3355331Samw }
336789Sahrens 
337789Sahrens static zfs_acl_t *
3385331Samw zfs_acl_alloc(int vers)
339789Sahrens {
340789Sahrens 	zfs_acl_t *aclp;
341789Sahrens 
342789Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
3435331Samw 	list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
3445331Samw 	    offsetof(zfs_acl_node_t, z_next));
3455331Samw 	aclp->z_version = vers;
3465331Samw 	if (vers == ZFS_ACL_VERSION_FUID)
3475331Samw 		aclp->z_ops = zfs_acl_fuid_ops;
3485331Samw 	else
3495331Samw 		aclp->z_ops = zfs_acl_v0_ops;
3505331Samw 	return (aclp);
3515331Samw }
3525331Samw 
3535331Samw static zfs_acl_node_t *
3545331Samw zfs_acl_node_alloc(size_t bytes)
3555331Samw {
3565331Samw 	zfs_acl_node_t *aclnode;
3575331Samw 
3585331Samw 	aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
3595331Samw 	if (bytes) {
3605331Samw 		aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
3615331Samw 		aclnode->z_allocdata = aclnode->z_acldata;
3625331Samw 		aclnode->z_allocsize = bytes;
3635331Samw 		aclnode->z_size = bytes;
364789Sahrens 	}
3655331Samw 
3665331Samw 	return (aclnode);
3675331Samw }
3685331Samw 
3695331Samw static void
3705331Samw zfs_acl_node_free(zfs_acl_node_t *aclnode)
3715331Samw {
3725331Samw 	if (aclnode->z_allocsize)
3735331Samw 		kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
3745331Samw 	kmem_free(aclnode, sizeof (zfs_acl_node_t));
375789Sahrens }
376789Sahrens 
3775489Smarks static void
3785489Smarks zfs_acl_release_nodes(zfs_acl_t *aclp)
379789Sahrens {
3805331Samw 	zfs_acl_node_t *aclnode;
3815331Samw 
3825331Samw 	while (aclnode = list_head(&aclp->z_acl)) {
3835331Samw 		list_remove(&aclp->z_acl, aclnode);
3845331Samw 		zfs_acl_node_free(aclnode);
385789Sahrens 	}
3865489Smarks 	aclp->z_acl_count = 0;
3875489Smarks 	aclp->z_acl_bytes = 0;
3885489Smarks }
3895331Samw 
3905489Smarks void
3915489Smarks zfs_acl_free(zfs_acl_t *aclp)
3925489Smarks {
3935489Smarks 	zfs_acl_release_nodes(aclp);
3945331Samw 	list_destroy(&aclp->z_acl);
395789Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
396789Sahrens }
397789Sahrens 
3985331Samw static boolean_t
3997559SMark.Shellenbaum@Sun.COM zfs_acl_valid_ace_type(uint_t type, uint_t flags)
4007559SMark.Shellenbaum@Sun.COM {
4017559SMark.Shellenbaum@Sun.COM 	uint16_t entry_type;
4027559SMark.Shellenbaum@Sun.COM 
4037559SMark.Shellenbaum@Sun.COM 	switch (type) {
4047559SMark.Shellenbaum@Sun.COM 	case ALLOW:
4057559SMark.Shellenbaum@Sun.COM 	case DENY:
4067559SMark.Shellenbaum@Sun.COM 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
4077559SMark.Shellenbaum@Sun.COM 	case ACE_SYSTEM_ALARM_ACE_TYPE:
4087559SMark.Shellenbaum@Sun.COM 		entry_type = flags & ACE_TYPE_FLAGS;
4097559SMark.Shellenbaum@Sun.COM 		return (entry_type == ACE_OWNER ||
4107559SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP ||
4117559SMark.Shellenbaum@Sun.COM 		    entry_type == ACE_EVERYONE || entry_type == 0 ||
4127559SMark.Shellenbaum@Sun.COM 		    entry_type == ACE_IDENTIFIER_GROUP);
4137559SMark.Shellenbaum@Sun.COM 	default:
4147559SMark.Shellenbaum@Sun.COM 		if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
4157559SMark.Shellenbaum@Sun.COM 			return (B_TRUE);
4167559SMark.Shellenbaum@Sun.COM 	}
4177559SMark.Shellenbaum@Sun.COM 	return (B_FALSE);
4187559SMark.Shellenbaum@Sun.COM }
4197559SMark.Shellenbaum@Sun.COM 
4207559SMark.Shellenbaum@Sun.COM static boolean_t
4215331Samw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
422789Sahrens {
4235331Samw 	/*
4245331Samw 	 * first check type of entry
4255331Samw 	 */
4265331Samw 
4277559SMark.Shellenbaum@Sun.COM 	if (!zfs_acl_valid_ace_type(type, iflags))
4285331Samw 		return (B_FALSE);
4295331Samw 
4305331Samw 	switch (type) {
4315331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
4325331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
4335331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
4345331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
4355331Samw 		if (aclp->z_version < ZFS_ACL_VERSION_FUID)
4365331Samw 			return (B_FALSE);
4375331Samw 		aclp->z_hints |= ZFS_ACL_OBJ_ACE;
4385331Samw 	}
439789Sahrens 
4407559SMark.Shellenbaum@Sun.COM 	/*
4417559SMark.Shellenbaum@Sun.COM 	 * next check inheritance level flags
4427559SMark.Shellenbaum@Sun.COM 	 */
4437559SMark.Shellenbaum@Sun.COM 
4447057Smarks 	if (obj_type == VDIR &&
4457057Smarks 	    (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
4465331Samw 		aclp->z_hints |= ZFS_INHERIT_ACE;
4475331Samw 
4485331Samw 	if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
4495331Samw 		if ((iflags & (ACE_FILE_INHERIT_ACE|
4505331Samw 		    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
4515331Samw 			return (B_FALSE);
4525331Samw 		}
4535331Samw 	}
4545331Samw 
4555331Samw 	return (B_TRUE);
4565331Samw }
4575331Samw 
4585331Samw static void *
4595331Samw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
4605331Samw     uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
4615331Samw {
4625331Samw 	zfs_acl_node_t *aclnode;
4635331Samw 
4645331Samw 	if (start == NULL) {
4655331Samw 		aclnode = list_head(&aclp->z_acl);
4665331Samw 		if (aclnode == NULL)
4675331Samw 			return (NULL);
4685331Samw 
4695331Samw 		aclp->z_next_ace = aclnode->z_acldata;
4705331Samw 		aclp->z_curr_node = aclnode;
4715331Samw 		aclnode->z_ace_idx = 0;
4725331Samw 	}
4735331Samw 
4745331Samw 	aclnode = aclp->z_curr_node;
4755331Samw 
4765331Samw 	if (aclnode == NULL)
4775331Samw 		return (NULL);
4785331Samw 
4795331Samw 	if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
4805331Samw 		aclnode = list_next(&aclp->z_acl, aclnode);
4815331Samw 		if (aclnode == NULL)
4825331Samw 			return (NULL);
4835331Samw 		else {
4845331Samw 			aclp->z_curr_node = aclnode;
4855331Samw 			aclnode->z_ace_idx = 0;
4865331Samw 			aclp->z_next_ace = aclnode->z_acldata;
4875331Samw 		}
4885331Samw 	}
4895331Samw 
4905331Samw 	if (aclnode->z_ace_idx < aclnode->z_ace_count) {
4915331Samw 		void *acep = aclp->z_next_ace;
4927559SMark.Shellenbaum@Sun.COM 		size_t ace_size;
4937559SMark.Shellenbaum@Sun.COM 
4947559SMark.Shellenbaum@Sun.COM 		/*
4957559SMark.Shellenbaum@Sun.COM 		 * Make sure we don't overstep our bounds
4967559SMark.Shellenbaum@Sun.COM 		 */
4977559SMark.Shellenbaum@Sun.COM 		ace_size = aclp->z_ops.ace_size(acep);
4987559SMark.Shellenbaum@Sun.COM 
4997559SMark.Shellenbaum@Sun.COM 		if (((caddr_t)acep + ace_size) >
5007559SMark.Shellenbaum@Sun.COM 		    ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
5017559SMark.Shellenbaum@Sun.COM 			return (NULL);
5027559SMark.Shellenbaum@Sun.COM 		}
5037559SMark.Shellenbaum@Sun.COM 
5045331Samw 		*iflags = aclp->z_ops.ace_flags_get(acep);
5055331Samw 		*type = aclp->z_ops.ace_type_get(acep);
5065331Samw 		*access_mask = aclp->z_ops.ace_mask_get(acep);
5075331Samw 		*who = aclp->z_ops.ace_who_get(acep);
5087559SMark.Shellenbaum@Sun.COM 		aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size;
5095331Samw 		aclnode->z_ace_idx++;
5105331Samw 		return ((void *)acep);
5115331Samw 	}
5125331Samw 	return (NULL);
5135331Samw }
5145331Samw 
5155331Samw /*ARGSUSED*/
5165331Samw static uint64_t
5175331Samw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
5185331Samw     uint16_t *flags, uint16_t *type, uint32_t *mask)
5195331Samw {
5205331Samw 	zfs_acl_t *aclp = datap;
5215331Samw 	zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
5225331Samw 	uint64_t who;
5235331Samw 
5245331Samw 	acep = zfs_acl_next_ace(aclp, acep, &who, mask,
5255331Samw 	    flags, type);
5265331Samw 	return ((uint64_t)(uintptr_t)acep);
5275331Samw }
5285331Samw 
5295331Samw static zfs_acl_node_t *
5305331Samw zfs_acl_curr_node(zfs_acl_t *aclp)
5315331Samw {
5325331Samw 	ASSERT(aclp->z_curr_node);
5335331Samw 	return (aclp->z_curr_node);
5345331Samw }
5355331Samw 
5365331Samw /*
5375331Samw  * Copy ACE to internal ZFS format.
5385331Samw  * While processing the ACL each ACE will be validated for correctness.
5395331Samw  * ACE FUIDs will be created later.
5405331Samw  */
5415331Samw int
5425331Samw zfs_copy_ace_2_fuid(vtype_t obj_type, zfs_acl_t *aclp, void *datap,
5435331Samw     zfs_ace_t *z_acl, int aclcnt, size_t *size)
5445331Samw {
5455331Samw 	int i;
5465331Samw 	uint16_t entry_type;
5475331Samw 	zfs_ace_t *aceptr = z_acl;
5485331Samw 	ace_t *acep = datap;
5495331Samw 	zfs_object_ace_t *zobjacep;
5505331Samw 	ace_object_t *aceobjp;
5515331Samw 
5525331Samw 	for (i = 0; i != aclcnt; i++) {
5535331Samw 		aceptr->z_hdr.z_access_mask = acep->a_access_mask;
5545331Samw 		aceptr->z_hdr.z_flags = acep->a_flags;
5555331Samw 		aceptr->z_hdr.z_type = acep->a_type;
5565331Samw 		entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
5575331Samw 		if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
5585824Smarks 		    entry_type != ACE_EVERYONE) {
5595824Smarks 			if (!aclp->z_has_fuids)
5605959Smarks 				aclp->z_has_fuids = IS_EPHEMERAL(acep->a_who);
5615331Samw 			aceptr->z_fuid = (uint64_t)acep->a_who;
5625824Smarks 		}
5635824Smarks 
5645331Samw 		/*
5655331Samw 		 * Make sure ACE is valid
5665331Samw 		 */
5675331Samw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
5685331Samw 		    aceptr->z_hdr.z_flags) != B_TRUE)
5695331Samw 			return (EINVAL);
5705331Samw 
5715331Samw 		switch (acep->a_type) {
5725331Samw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
5735331Samw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
5745331Samw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
5755331Samw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
5765331Samw 			zobjacep = (zfs_object_ace_t *)aceptr;
5775331Samw 			aceobjp = (ace_object_t *)acep;
5785331Samw 
5795331Samw 			bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
5805331Samw 			    sizeof (aceobjp->a_obj_type));
5815331Samw 			bcopy(aceobjp->a_inherit_obj_type,
5825331Samw 			    zobjacep->z_inherit_type,
5835331Samw 			    sizeof (aceobjp->a_inherit_obj_type));
5845331Samw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
5855331Samw 			break;
5865331Samw 		default:
5875331Samw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
5885331Samw 		}
5895331Samw 
5905331Samw 		aceptr = (zfs_ace_t *)((caddr_t)aceptr +
5915331Samw 		    aclp->z_ops.ace_size(aceptr));
5925331Samw 	}
5935331Samw 
5945331Samw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
595789Sahrens 
5965331Samw 	return (0);
5975331Samw }
5985331Samw 
5995331Samw /*
6005331Samw  * Copy ZFS ACEs to fixed size ace_t layout
6015331Samw  */
6025331Samw static void
6035771Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
6045771Sjp151216     void *datap, int filter)
6055331Samw {
6065331Samw 	uint64_t who;
6075331Samw 	uint32_t access_mask;
6085331Samw 	uint16_t iflags, type;
6095331Samw 	zfs_ace_hdr_t *zacep = NULL;
6105331Samw 	ace_t *acep = datap;
6115331Samw 	ace_object_t *objacep;
6125331Samw 	zfs_object_ace_t *zobjacep;
6135331Samw 	size_t ace_size;
6145331Samw 	uint16_t entry_type;
6155331Samw 
6165331Samw 	while (zacep = zfs_acl_next_ace(aclp, zacep,
6175331Samw 	    &who, &access_mask, &iflags, &type)) {
6185331Samw 
6195331Samw 		switch (type) {
6205331Samw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
6215331Samw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
6225331Samw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
6235331Samw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
6245331Samw 			if (filter) {
6255331Samw 				continue;
6265331Samw 			}
6275331Samw 			zobjacep = (zfs_object_ace_t *)zacep;
6285331Samw 			objacep = (ace_object_t *)acep;
6295331Samw 			bcopy(zobjacep->z_object_type,
6305331Samw 			    objacep->a_obj_type,
6315331Samw 			    sizeof (zobjacep->z_object_type));
6325331Samw 			bcopy(zobjacep->z_inherit_type,
6335331Samw 			    objacep->a_inherit_obj_type,
6345331Samw 			    sizeof (zobjacep->z_inherit_type));
6355331Samw 			ace_size = sizeof (ace_object_t);
6365331Samw 			break;
6375331Samw 		default:
6385331Samw 			ace_size = sizeof (ace_t);
6395331Samw 			break;
6405331Samw 		}
6415331Samw 
6425331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
6435331Samw 		if ((entry_type != ACE_OWNER &&
6447328SMark.Shellenbaum@Sun.COM 		    entry_type != OWNING_GROUP &&
6455959Smarks 		    entry_type != ACE_EVERYONE)) {
6465959Smarks 			acep->a_who = zfs_fuid_map_id(zfsvfs, who,
6475959Smarks 			    cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
6485959Smarks 			    ZFS_ACE_GROUP : ZFS_ACE_USER);
6495959Smarks 		} else {
6505331Samw 			acep->a_who = (uid_t)(int64_t)who;
6515959Smarks 		}
6525331Samw 		acep->a_access_mask = access_mask;
6535331Samw 		acep->a_flags = iflags;
6545331Samw 		acep->a_type = type;
6555331Samw 		acep = (ace_t *)((caddr_t)acep + ace_size);
6565331Samw 	}
6575331Samw }
6585331Samw 
6595331Samw static int
6605331Samw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
6615331Samw     zfs_oldace_t *z_acl, int aclcnt, size_t *size)
6625331Samw {
6635331Samw 	int i;
6645331Samw 	zfs_oldace_t *aceptr = z_acl;
6655331Samw 
6665331Samw 	for (i = 0; i != aclcnt; i++, aceptr++) {
6675331Samw 		aceptr->z_access_mask = acep[i].a_access_mask;
6685331Samw 		aceptr->z_type = acep[i].a_type;
6695331Samw 		aceptr->z_flags = acep[i].a_flags;
6705331Samw 		aceptr->z_fuid = acep[i].a_who;
6715331Samw 		/*
6725331Samw 		 * Make sure ACE is valid
6735331Samw 		 */
6745331Samw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
6755331Samw 		    aceptr->z_flags) != B_TRUE)
6765331Samw 			return (EINVAL);
6775331Samw 	}
6785331Samw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
6795331Samw 	return (0);
6805331Samw }
6815331Samw 
6825331Samw /*
6835331Samw  * convert old ACL format to new
6845331Samw  */
6855331Samw void
6865331Samw zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp)
6875331Samw {
6885331Samw 	zfs_oldace_t *oldaclp;
6895331Samw 	int i;
6905331Samw 	uint16_t type, iflags;
6915331Samw 	uint32_t access_mask;
6925331Samw 	uint64_t who;
6935331Samw 	void *cookie = NULL;
6945489Smarks 	zfs_acl_node_t *newaclnode;
6955331Samw 
6965331Samw 	ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
6975331Samw 	/*
6985331Samw 	 * First create the ACE in a contiguous piece of memory
6995331Samw 	 * for zfs_copy_ace_2_fuid().
7005331Samw 	 *
7015331Samw 	 * We only convert an ACL once, so this won't happen
7025331Samw 	 * everytime.
7035331Samw 	 */
7045331Samw 	oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
7055331Samw 	    KM_SLEEP);
7065331Samw 	i = 0;
7075331Samw 	while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
7085331Samw 	    &access_mask, &iflags, &type)) {
7095331Samw 		oldaclp[i].z_flags = iflags;
7105331Samw 		oldaclp[i].z_type = type;
7115331Samw 		oldaclp[i].z_fuid = who;
7125331Samw 		oldaclp[i++].z_access_mask = access_mask;
7135331Samw 	}
7145331Samw 
7155331Samw 	newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
7165331Samw 	    sizeof (zfs_object_ace_t));
7175331Samw 	aclp->z_ops = zfs_acl_fuid_ops;
7185331Samw 	VERIFY(zfs_copy_ace_2_fuid(ZTOV(zp)->v_type, aclp, oldaclp,
7195331Samw 	    newaclnode->z_acldata, aclp->z_acl_count,
7205331Samw 	    &newaclnode->z_size) == 0);
7215331Samw 	newaclnode->z_ace_count = aclp->z_acl_count;
7225331Samw 	aclp->z_version = ZFS_ACL_VERSION;
7235331Samw 	kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
7245331Samw 
7255331Samw 	/*
7265331Samw 	 * Release all previous ACL nodes
7275331Samw 	 */
7285331Samw 
7295489Smarks 	zfs_acl_release_nodes(aclp);
7305489Smarks 
7315331Samw 	list_insert_head(&aclp->z_acl, newaclnode);
7325489Smarks 
7335489Smarks 	aclp->z_acl_bytes = newaclnode->z_size;
7345489Smarks 	aclp->z_acl_count = newaclnode->z_ace_count;
7355489Smarks 
736789Sahrens }
737789Sahrens 
738789Sahrens /*
739789Sahrens  * Convert unix access mask to v4 access mask
740789Sahrens  */
741789Sahrens static uint32_t
742789Sahrens zfs_unix_to_v4(uint32_t access_mask)
743789Sahrens {
744789Sahrens 	uint32_t new_mask = 0;
745789Sahrens 
7465331Samw 	if (access_mask & S_IXOTH)
7475331Samw 		new_mask |= ACE_EXECUTE;
7485331Samw 	if (access_mask & S_IWOTH)
7495331Samw 		new_mask |= ACE_WRITE_DATA;
7505331Samw 	if (access_mask & S_IROTH)
751789Sahrens 		new_mask |= ACE_READ_DATA;
752789Sahrens 	return (new_mask);
753789Sahrens }
754789Sahrens 
755789Sahrens static void
7565331Samw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
7575331Samw     uint16_t access_type, uint64_t fuid, uint16_t entry_type)
758789Sahrens {
7595331Samw 	uint16_t type = entry_type & ACE_TYPE_FLAGS;
7605331Samw 
7615331Samw 	aclp->z_ops.ace_mask_set(acep, access_mask);
7625331Samw 	aclp->z_ops.ace_type_set(acep, access_type);
7635331Samw 	aclp->z_ops.ace_flags_set(acep, entry_type);
7647328SMark.Shellenbaum@Sun.COM 	if ((type != ACE_OWNER && type != OWNING_GROUP &&
7655331Samw 	    type != ACE_EVERYONE))
7665331Samw 		aclp->z_ops.ace_who_set(acep, fuid);
767789Sahrens }
768789Sahrens 
7695331Samw /*
7705331Samw  * Determine mode of file based on ACL.
7715331Samw  * Also, create FUIDs for any User/Group ACEs
7725331Samw  */
773789Sahrens static uint64_t
7745771Sjp151216 zfs_mode_fuid_compute(znode_t *zp, zfs_acl_t *aclp, cred_t *cr,
7755771Sjp151216     zfs_fuid_info_t **fuidp, dmu_tx_t *tx)
776789Sahrens {
7775331Samw 	int		entry_type;
7785331Samw 	mode_t		mode;
7795331Samw 	mode_t		seen = 0;
7805331Samw 	zfs_ace_hdr_t 	*acep = NULL;
7815331Samw 	uint64_t	who;
7825331Samw 	uint16_t	iflags, type;
7835331Samw 	uint32_t	access_mask;
784789Sahrens 
7855331Samw 	mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
7865331Samw 
7875331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who,
7885331Samw 	    &access_mask, &iflags, &type)) {
7894869Smarks 
7907559SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
7917559SMark.Shellenbaum@Sun.COM 			continue;
7927559SMark.Shellenbaum@Sun.COM 
7937328SMark.Shellenbaum@Sun.COM 		entry_type = (iflags & ACE_TYPE_FLAGS);
7947328SMark.Shellenbaum@Sun.COM 
7954869Smarks 		/*
7967328SMark.Shellenbaum@Sun.COM 		 * Skip over owner@, group@ or everyone@ inherit only ACEs
7974869Smarks 		 */
7987328SMark.Shellenbaum@Sun.COM 		if ((iflags & ACE_INHERIT_ONLY_ACE) &&
7997328SMark.Shellenbaum@Sun.COM 		    (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
8007328SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP))
8014869Smarks 			continue;
8024869Smarks 
803789Sahrens 		if (entry_type == ACE_OWNER) {
8045331Samw 			if ((access_mask & ACE_READ_DATA) &&
805789Sahrens 			    (!(seen & S_IRUSR))) {
806789Sahrens 				seen |= S_IRUSR;
8075331Samw 				if (type == ALLOW) {
808789Sahrens 					mode |= S_IRUSR;
809789Sahrens 				}
810789Sahrens 			}
8115331Samw 			if ((access_mask & ACE_WRITE_DATA) &&
812789Sahrens 			    (!(seen & S_IWUSR))) {
813789Sahrens 				seen |= S_IWUSR;
8145331Samw 				if (type == ALLOW) {
815789Sahrens 					mode |= S_IWUSR;
816789Sahrens 				}
817789Sahrens 			}
8185331Samw 			if ((access_mask & ACE_EXECUTE) &&
819789Sahrens 			    (!(seen & S_IXUSR))) {
820789Sahrens 				seen |= S_IXUSR;
8215331Samw 				if (type == ALLOW) {
822789Sahrens 					mode |= S_IXUSR;
823789Sahrens 				}
824789Sahrens 			}
825789Sahrens 		} else if (entry_type == OWNING_GROUP) {
8265331Samw 			if ((access_mask & ACE_READ_DATA) &&
827789Sahrens 			    (!(seen & S_IRGRP))) {
828789Sahrens 				seen |= S_IRGRP;
8295331Samw 				if (type == ALLOW) {
830789Sahrens 					mode |= S_IRGRP;
831789Sahrens 				}
832789Sahrens 			}
8335331Samw 			if ((access_mask & ACE_WRITE_DATA) &&
834789Sahrens 			    (!(seen & S_IWGRP))) {
835789Sahrens 				seen |= S_IWGRP;
8365331Samw 				if (type == ALLOW) {
837789Sahrens 					mode |= S_IWGRP;
838789Sahrens 				}
839789Sahrens 			}
8405331Samw 			if ((access_mask & ACE_EXECUTE) &&
841789Sahrens 			    (!(seen & S_IXGRP))) {
842789Sahrens 				seen |= S_IXGRP;
8435331Samw 				if (type == ALLOW) {
844789Sahrens 					mode |= S_IXGRP;
845789Sahrens 				}
846789Sahrens 			}
847789Sahrens 		} else if (entry_type == ACE_EVERYONE) {
8485331Samw 			if ((access_mask & ACE_READ_DATA)) {
849789Sahrens 				if (!(seen & S_IRUSR)) {
850789Sahrens 					seen |= S_IRUSR;
8515331Samw 					if (type == ALLOW) {
852789Sahrens 						mode |= S_IRUSR;
853789Sahrens 					}
854789Sahrens 				}
855789Sahrens 				if (!(seen & S_IRGRP)) {
856789Sahrens 					seen |= S_IRGRP;
8575331Samw 					if (type == ALLOW) {
858789Sahrens 						mode |= S_IRGRP;
859789Sahrens 					}
860789Sahrens 				}
861789Sahrens 				if (!(seen & S_IROTH)) {
862789Sahrens 					seen |= S_IROTH;
8635331Samw 					if (type == ALLOW) {
864789Sahrens 						mode |= S_IROTH;
865789Sahrens 					}
866789Sahrens 				}
867789Sahrens 			}
8685331Samw 			if ((access_mask & ACE_WRITE_DATA)) {
869789Sahrens 				if (!(seen & S_IWUSR)) {
870789Sahrens 					seen |= S_IWUSR;
8715331Samw 					if (type == ALLOW) {
872789Sahrens 						mode |= S_IWUSR;
873789Sahrens 					}
874789Sahrens 				}
875789Sahrens 				if (!(seen & S_IWGRP)) {
876789Sahrens 					seen |= S_IWGRP;
8775331Samw 					if (type == ALLOW) {
878789Sahrens 						mode |= S_IWGRP;
879789Sahrens 					}
880789Sahrens 				}
881789Sahrens 				if (!(seen & S_IWOTH)) {
882789Sahrens 					seen |= S_IWOTH;
8835331Samw 					if (type == ALLOW) {
884789Sahrens 						mode |= S_IWOTH;
885789Sahrens 					}
886789Sahrens 				}
887789Sahrens 			}
8885331Samw 			if ((access_mask & ACE_EXECUTE)) {
889789Sahrens 				if (!(seen & S_IXUSR)) {
890789Sahrens 					seen |= S_IXUSR;
8915331Samw 					if (type == ALLOW) {
892789Sahrens 						mode |= S_IXUSR;
893789Sahrens 					}
894789Sahrens 				}
895789Sahrens 				if (!(seen & S_IXGRP)) {
896789Sahrens 					seen |= S_IXGRP;
8975331Samw 					if (type == ALLOW) {
898789Sahrens 						mode |= S_IXGRP;
899789Sahrens 					}
900789Sahrens 				}
901789Sahrens 				if (!(seen & S_IXOTH)) {
902789Sahrens 					seen |= S_IXOTH;
9035331Samw 					if (type == ALLOW) {
904789Sahrens 						mode |= S_IXOTH;
905789Sahrens 					}
906789Sahrens 				}
907789Sahrens 			}
908789Sahrens 		}
9095331Samw 		/*
9105331Samw 		 * Now handle FUID create for user/group ACEs
9115331Samw 		 */
9125331Samw 		if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
9135331Samw 			aclp->z_ops.ace_who_set(acep,
9145771Sjp151216 			    zfs_fuid_create(zp->z_zfsvfs, who, cr,
9155959Smarks 			    (entry_type == 0) ? ZFS_ACE_USER : ZFS_ACE_GROUP,
9165959Smarks 			    tx, fuidp));
9175331Samw 		}
918789Sahrens 	}
919789Sahrens 	return (mode);
920789Sahrens }
921789Sahrens 
922789Sahrens static zfs_acl_t *
9235331Samw zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify)
924789Sahrens {
925789Sahrens 	zfs_acl_t	*aclp;
9265331Samw 	zfs_acl_node_t	*aclnode;
927789Sahrens 
9285331Samw 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
9295331Samw 
9305331Samw 	/*
9315331Samw 	 * Version 0 to 1 znode_acl_phys has the size/count fields swapped.
9325331Samw 	 * Version 0 didn't have a size field, only a count.
9335331Samw 	 */
9345331Samw 	if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
9355331Samw 		aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size;
9365331Samw 		aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count);
9375331Samw 	} else {
9385331Samw 		aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count;
9395331Samw 		aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size;
9405331Samw 	}
9415331Samw 
9425331Samw 	aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0);
9435331Samw 	aclnode->z_ace_count = aclp->z_acl_count;
9445331Samw 	if (will_modify) {
9455331Samw 		bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata,
9465331Samw 		    aclp->z_acl_bytes);
9475331Samw 	} else {
9485331Samw 		aclnode->z_size = aclp->z_acl_bytes;
9495331Samw 		aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0];
9505331Samw 	}
9515331Samw 
9525331Samw 	list_insert_head(&aclp->z_acl, aclnode);
953789Sahrens 
954789Sahrens 	return (aclp);
955789Sahrens }
956789Sahrens 
957789Sahrens /*
958789Sahrens  * Read an external acl object.
959789Sahrens  */
9601544Seschrock static int
9615331Samw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
962789Sahrens {
963789Sahrens 	uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
964789Sahrens 	zfs_acl_t	*aclp;
9655331Samw 	size_t		aclsize;
9665331Samw 	size_t		acl_count;
9675331Samw 	zfs_acl_node_t	*aclnode;
9681544Seschrock 	int error;
969789Sahrens 
970789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
971789Sahrens 
9721544Seschrock 	if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) {
9735331Samw 		*aclpp = zfs_acl_node_read_internal(zp, will_modify);
9741544Seschrock 		return (0);
9751544Seschrock 	}
976789Sahrens 
9775331Samw 	aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version);
9785331Samw 	if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
9795331Samw 		zfs_acl_phys_v0_t *zacl0 =
9805331Samw 		    (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl;
981789Sahrens 
9825331Samw 		aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count);
9835331Samw 		acl_count = zacl0->z_acl_count;
9845331Samw 	} else {
9855331Samw 		aclsize = zp->z_phys->zp_acl.z_acl_size;
9865331Samw 		acl_count = zp->z_phys->zp_acl.z_acl_count;
9875331Samw 		if (aclsize == 0)
9885331Samw 			aclsize = acl_count * sizeof (zfs_ace_t);
9895331Samw 	}
9905331Samw 	aclnode = zfs_acl_node_alloc(aclsize);
9915331Samw 	list_insert_head(&aclp->z_acl, aclnode);
9921544Seschrock 	error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0,
9935331Samw 	    aclsize, aclnode->z_acldata);
9945331Samw 	aclnode->z_ace_count = acl_count;
9955331Samw 	aclp->z_acl_count = acl_count;
9965331Samw 	aclp->z_acl_bytes = aclsize;
9975331Samw 
9981544Seschrock 	if (error != 0) {
9991544Seschrock 		zfs_acl_free(aclp);
10007294Sperrin 		/* convert checksum errors into IO errors */
10017294Sperrin 		if (error == ECKSUM)
10027294Sperrin 			error = EIO;
10031544Seschrock 		return (error);
10041544Seschrock 	}
1005789Sahrens 
10061544Seschrock 	*aclpp = aclp;
10071544Seschrock 	return (0);
1008789Sahrens }
1009789Sahrens 
1010789Sahrens /*
10115331Samw  * common code for setting ACLs.
1012789Sahrens  *
1013789Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
1014789Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
1015789Sahrens  * already checked the acl and knows whether to inherit.
1016789Sahrens  */
1017789Sahrens int
10185771Sjp151216 zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr,
10195771Sjp151216     zfs_fuid_info_t **fuidp, dmu_tx_t *tx)
1020789Sahrens {
1021789Sahrens 	int		error;
1022789Sahrens 	znode_phys_t	*zphys = zp->z_phys;
10235331Samw 	zfs_acl_phys_t	*zacl = &zphys->zp_acl;
1024789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1025789Sahrens 	uint64_t	aoid = zphys->zp_acl.z_acl_extern_obj;
10265331Samw 	uint64_t	off = 0;
10275331Samw 	dmu_object_type_t otype;
10285331Samw 	zfs_acl_node_t	*aclnode;
1029789Sahrens 
1030789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
1031789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
1032789Sahrens 
10335331Samw 	dmu_buf_will_dirty(zp->z_dbuf, tx);
1034789Sahrens 
10355771Sjp151216 	zphys->zp_mode = zfs_mode_fuid_compute(zp, aclp, cr, fuidp, tx);
1036789Sahrens 
1037789Sahrens 	/*
10385331Samw 	 * Decide which opbject type to use.  If we are forced to
10395331Samw 	 * use old ACL format than transform ACL into zfs_oldace_t
10405331Samw 	 * layout.
1041789Sahrens 	 */
10425331Samw 	if (!zfsvfs->z_use_fuids) {
10435331Samw 		otype = DMU_OT_OLDACL;
10445331Samw 	} else {
10455331Samw 		if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
10465331Samw 		    (zfsvfs->z_version >= ZPL_VERSION_FUID))
10475331Samw 			zfs_acl_xform(zp, aclp);
10485331Samw 		ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
10495331Samw 		otype = DMU_OT_ACL;
10505331Samw 	}
10515331Samw 
10525331Samw 	if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
10535331Samw 		/*
10545331Samw 		 * If ACL was previously external and we are now
10555331Samw 		 * converting to new ACL format then release old
10565331Samw 		 * ACL object and create a new one.
10575331Samw 		 */
10585331Samw 		if (aoid && aclp->z_version != zacl->z_acl_version) {
10595331Samw 			error = dmu_object_free(zfsvfs->z_os,
10605331Samw 			    zp->z_phys->zp_acl.z_acl_extern_obj, tx);
10615331Samw 			if (error)
10625331Samw 				return (error);
10635331Samw 			aoid = 0;
10645331Samw 		}
1065789Sahrens 		if (aoid == 0) {
1066789Sahrens 			aoid = dmu_object_alloc(zfsvfs->z_os,
10675331Samw 			    otype, aclp->z_acl_bytes,
10685331Samw 			    otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE,
10695331Samw 			    otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx);
1070789Sahrens 		} else {
1071789Sahrens 			(void) dmu_object_set_blocksize(zfsvfs->z_os, aoid,
10725331Samw 			    aclp->z_acl_bytes, 0, tx);
1073789Sahrens 		}
1074789Sahrens 		zphys->zp_acl.z_acl_extern_obj = aoid;
10755331Samw 		for (aclnode = list_head(&aclp->z_acl); aclnode;
10765331Samw 		    aclnode = list_next(&aclp->z_acl, aclnode)) {
10775331Samw 			if (aclnode->z_ace_count == 0)
10785331Samw 				continue;
10795331Samw 			dmu_write(zfsvfs->z_os, aoid, off,
10805331Samw 			    aclnode->z_size, aclnode->z_acldata, tx);
10815331Samw 			off += aclnode->z_size;
10825331Samw 		}
1083789Sahrens 	} else {
10845331Samw 		void *start = zacl->z_ace_data;
1085789Sahrens 		/*
1086789Sahrens 		 * Migrating back embedded?
1087789Sahrens 		 */
1088789Sahrens 		if (zphys->zp_acl.z_acl_extern_obj) {
1089789Sahrens 			error = dmu_object_free(zfsvfs->z_os,
10904300Smarks 			    zp->z_phys->zp_acl.z_acl_extern_obj, tx);
1091789Sahrens 			if (error)
1092789Sahrens 				return (error);
1093789Sahrens 			zphys->zp_acl.z_acl_extern_obj = 0;
1094789Sahrens 		}
10955331Samw 
10965331Samw 		for (aclnode = list_head(&aclp->z_acl); aclnode;
10975331Samw 		    aclnode = list_next(&aclp->z_acl, aclnode)) {
10985331Samw 			if (aclnode->z_ace_count == 0)
10995331Samw 				continue;
11005331Samw 			bcopy(aclnode->z_acldata, start, aclnode->z_size);
11015331Samw 			start = (caddr_t)start + aclnode->z_size;
11025331Samw 		}
1103789Sahrens 	}
1104905Smarks 
11055331Samw 	/*
11065331Samw 	 * If Old version then swap count/bytes to match old
11075331Samw 	 * layout of znode_acl_phys_t.
11085331Samw 	 */
11095331Samw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
11105331Samw 		zphys->zp_acl.z_acl_size = aclp->z_acl_count;
11115331Samw 		zphys->zp_acl.z_acl_count = aclp->z_acl_bytes;
11125331Samw 	} else {
11135331Samw 		zphys->zp_acl.z_acl_size = aclp->z_acl_bytes;
11145331Samw 		zphys->zp_acl.z_acl_count = aclp->z_acl_count;
1115905Smarks 	}
1116789Sahrens 
11175331Samw 	zphys->zp_acl.z_acl_version = aclp->z_version;
11185331Samw 
11195331Samw 	/*
11205331Samw 	 * Replace ACL wide bits, but first clear them.
11215331Samw 	 */
11225331Samw 	zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS;
11235331Samw 
11245331Samw 	zp->z_phys->zp_flags |= aclp->z_hints;
11255331Samw 
11265331Samw 	if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
11275331Samw 		zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL;
11285331Samw 
1129789Sahrens 	zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
1130789Sahrens 	return (0);
1131789Sahrens }
1132789Sahrens 
1133789Sahrens /*
1134789Sahrens  * Update access mask for prepended ACE
1135789Sahrens  *
1136789Sahrens  * This applies the "groupmask" value for aclmode property.
1137789Sahrens  */
1138789Sahrens static void
11395331Samw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void  *acep, void  *origacep,
11405331Samw     mode_t mode, uint64_t owner)
1141789Sahrens {
1142789Sahrens 	int	rmask, wmask, xmask;
1143789Sahrens 	int	user_ace;
11445331Samw 	uint16_t aceflags;
11455331Samw 	uint32_t origmask, acepmask;
11465331Samw 	uint64_t fuid;
1147789Sahrens 
11485331Samw 	aceflags = aclp->z_ops.ace_flags_get(acep);
11495331Samw 	fuid = aclp->z_ops.ace_who_get(acep);
11505331Samw 	origmask = aclp->z_ops.ace_mask_get(origacep);
11515331Samw 	acepmask = aclp->z_ops.ace_mask_get(acep);
11525331Samw 
11535331Samw 	user_ace = (!(aceflags &
1154789Sahrens 	    (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
1155789Sahrens 
11565331Samw 	if (user_ace && (fuid == owner)) {
1157789Sahrens 		rmask = S_IRUSR;
1158789Sahrens 		wmask = S_IWUSR;
1159789Sahrens 		xmask = S_IXUSR;
1160789Sahrens 	} else {
1161789Sahrens 		rmask = S_IRGRP;
1162789Sahrens 		wmask = S_IWGRP;
1163789Sahrens 		xmask = S_IXGRP;
1164789Sahrens 	}
1165789Sahrens 
11665331Samw 	if (origmask & ACE_READ_DATA) {
11675331Samw 		if (mode & rmask) {
11685331Samw 			acepmask &= ~ACE_READ_DATA;
11695331Samw 		} else {
11705331Samw 			acepmask |= ACE_READ_DATA;
11715331Samw 		}
1172789Sahrens 	}
1173789Sahrens 
11745331Samw 	if (origmask & ACE_WRITE_DATA) {
11755331Samw 		if (mode & wmask) {
11765331Samw 			acepmask &= ~ACE_WRITE_DATA;
11775331Samw 		} else {
11785331Samw 			acepmask |= ACE_WRITE_DATA;
11795331Samw 		}
1180789Sahrens 	}
1181789Sahrens 
11825331Samw 	if (origmask & ACE_APPEND_DATA) {
11835331Samw 		if (mode & wmask) {
11845331Samw 			acepmask &= ~ACE_APPEND_DATA;
11855331Samw 		} else {
11865331Samw 			acepmask |= ACE_APPEND_DATA;
11875331Samw 		}
1188789Sahrens 	}
1189789Sahrens 
11905331Samw 	if (origmask & ACE_EXECUTE) {
11915331Samw 		if (mode & xmask) {
11925331Samw 			acepmask &= ~ACE_EXECUTE;
11935331Samw 		} else {
11945331Samw 			acepmask |= ACE_EXECUTE;
11955331Samw 		}
1196789Sahrens 	}
11975331Samw 	aclp->z_ops.ace_mask_set(acep, acepmask);
1198789Sahrens }
1199789Sahrens 
1200789Sahrens /*
1201789Sahrens  * Apply mode to canonical six ACEs.
1202789Sahrens  */
1203789Sahrens static void
1204789Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
1205789Sahrens {
12065331Samw 	zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
12075331Samw 	void	*acep;
12085331Samw 	int	maskoff = aclp->z_ops.ace_mask_off();
12095331Samw 	size_t abstract_size = aclp->z_ops.ace_abstract_size();
1210789Sahrens 
12115331Samw 	ASSERT(aclnode != NULL);
12125331Samw 
12135331Samw 	acep = (void *)((caddr_t)aclnode->z_acldata +
12145331Samw 	    aclnode->z_size - (abstract_size * 6));
1215789Sahrens 
1216789Sahrens 	/*
1217789Sahrens 	 * Fixup final ACEs to match the mode
1218789Sahrens 	 */
1219789Sahrens 
12205331Samw 	adjust_ace_pair_common(acep, maskoff, abstract_size,
12215331Samw 	    (mode & 0700) >> 6);	/* owner@ */
12225331Samw 
12235331Samw 	acep = (caddr_t)acep + (abstract_size * 2);
12245331Samw 
12255331Samw 	adjust_ace_pair_common(acep, maskoff, abstract_size,
12265331Samw 	    (mode & 0070) >> 3);	/* group@ */
12275331Samw 
12285331Samw 	acep = (caddr_t)acep + (abstract_size * 2);
12295331Samw 	adjust_ace_pair_common(acep, maskoff,
12305331Samw 	    abstract_size, mode);	/* everyone@ */
1231789Sahrens }
1232789Sahrens 
1233789Sahrens 
1234789Sahrens static int
12355331Samw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny,
12365331Samw     int entry_type, int accessmask)
1237789Sahrens {
12385331Samw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
12395331Samw 	uint16_t type = aclp->z_ops.ace_type_get(acep);
12405331Samw 	uint16_t flags = aclp->z_ops.ace_flags_get(acep);
12415331Samw 
12425331Samw 	return (mask == accessmask && type == allow_deny &&
12435331Samw 	    ((flags & ACE_TYPE_FLAGS) == entry_type));
1244789Sahrens }
1245789Sahrens 
1246789Sahrens /*
1247789Sahrens  * Can prepended ACE be reused?
1248789Sahrens  */
1249789Sahrens static int
12505331Samw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep)
1251789Sahrens {
1252789Sahrens 	int okay_masks;
12535331Samw 	uint16_t prevtype;
12545331Samw 	uint16_t prevflags;
12555331Samw 	uint16_t flags;
12565331Samw 	uint32_t mask, prevmask;
1257789Sahrens 
12585331Samw 	if (prevacep == NULL)
1259789Sahrens 		return (B_FALSE);
1260789Sahrens 
12615331Samw 	prevtype = aclp->z_ops.ace_type_get(prevacep);
12625331Samw 	prevflags = aclp->z_ops.ace_flags_get(prevacep);
12635331Samw 	flags = aclp->z_ops.ace_flags_get(acep);
12645331Samw 	mask = aclp->z_ops.ace_mask_get(acep);
12655331Samw 	prevmask = aclp->z_ops.ace_mask_get(prevacep);
12665331Samw 
12675331Samw 	if (prevtype != DENY)
1268789Sahrens 		return (B_FALSE);
1269789Sahrens 
12705331Samw 	if (prevflags != (flags & ACE_IDENTIFIER_GROUP))
1271789Sahrens 		return (B_FALSE);
1272789Sahrens 
12735331Samw 	okay_masks = (mask & OKAY_MASK_BITS);
1274789Sahrens 
12755331Samw 	if (prevmask & ~okay_masks)
1276789Sahrens 		return (B_FALSE);
1277789Sahrens 
1278789Sahrens 	return (B_TRUE);
1279789Sahrens }
1280789Sahrens 
1281789Sahrens 
12825331Samw /*
12835331Samw  * Insert new ACL node into chain of zfs_acl_node_t's
12845331Samw  *
12855331Samw  * This will result in two possible results.
12865331Samw  * 1. If the ACL is currently just a single zfs_acl_node and
12875331Samw  *    we are prepending the entry then current acl node will have
12885331Samw  *    a new node inserted above it.
12895331Samw  *
12905331Samw  * 2. If we are inserting in the middle of current acl node then
12915331Samw  *    the current node will be split in two and new node will be inserted
12925331Samw  *    in between the two split nodes.
12935331Samw  */
12945331Samw static zfs_acl_node_t *
12955331Samw zfs_acl_ace_insert(zfs_acl_t *aclp, void  *acep)
12965331Samw {
12975331Samw 	zfs_acl_node_t 	*newnode;
12985331Samw 	zfs_acl_node_t 	*trailernode = NULL;
12995331Samw 	zfs_acl_node_t 	*currnode = zfs_acl_curr_node(aclp);
13005331Samw 	int		curr_idx = aclp->z_curr_node->z_ace_idx;
13015331Samw 	int		trailer_count;
13025331Samw 	size_t		oldsize;
1303789Sahrens 
13045331Samw 	newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep));
13055331Samw 	newnode->z_ace_count = 1;
13065331Samw 
13075331Samw 	oldsize = currnode->z_size;
13085331Samw 
13095331Samw 	if (curr_idx != 1) {
13105331Samw 		trailernode = zfs_acl_node_alloc(0);
13115331Samw 		trailernode->z_acldata = acep;
13125331Samw 
13135331Samw 		trailer_count = currnode->z_ace_count - curr_idx + 1;
13145331Samw 		currnode->z_ace_count = curr_idx - 1;
13155331Samw 		currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata;
13165331Samw 		trailernode->z_size = oldsize - currnode->z_size;
13175331Samw 		trailernode->z_ace_count = trailer_count;
1318789Sahrens 	}
1319789Sahrens 
13205331Samw 	aclp->z_acl_count += 1;
13215331Samw 	aclp->z_acl_bytes += aclp->z_ops.ace_size(acep);
1322789Sahrens 
13235331Samw 	if (curr_idx == 1)
13245331Samw 		list_insert_before(&aclp->z_acl, currnode, newnode);
13255331Samw 	else
13265331Samw 		list_insert_after(&aclp->z_acl, currnode, newnode);
13275331Samw 	if (trailernode) {
13285331Samw 		list_insert_after(&aclp->z_acl, newnode, trailernode);
13295331Samw 		aclp->z_curr_node = trailernode;
13305331Samw 		trailernode->z_ace_idx = 1;
1331789Sahrens 	}
1332789Sahrens 
13335331Samw 	return (newnode);
1334789Sahrens }
1335789Sahrens 
1336789Sahrens /*
1337789Sahrens  * Prepend deny ACE
1338789Sahrens  */
13395331Samw static void *
13405331Samw zfs_acl_prepend_deny(znode_t *zp, zfs_acl_t *aclp, void *acep,
1341789Sahrens     mode_t mode)
1342789Sahrens {
13435331Samw 	zfs_acl_node_t *aclnode;
13445331Samw 	void  *newacep;
13455331Samw 	uint64_t fuid;
13465331Samw 	uint16_t flags;
1347789Sahrens 
13485331Samw 	aclnode = zfs_acl_ace_insert(aclp, acep);
13495331Samw 	newacep = aclnode->z_acldata;
13505331Samw 	fuid = aclp->z_ops.ace_who_get(acep);
13515331Samw 	flags = aclp->z_ops.ace_flags_get(acep);
13525331Samw 	zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS));
13535331Samw 	zfs_acl_prepend_fixup(aclp, newacep, acep, mode, zp->z_phys->zp_uid);
13545331Samw 
13555331Samw 	return (newacep);
1356789Sahrens }
1357789Sahrens 
1358789Sahrens /*
1359789Sahrens  * Split an inherited ACE into inherit_only ACE
1360789Sahrens  * and original ACE with inheritance flags stripped off.
1361789Sahrens  */
1362789Sahrens static void
13635331Samw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep)
1364789Sahrens {
13655331Samw 	zfs_acl_node_t *aclnode;
13665435Smarks 	zfs_acl_node_t *currnode;
13675331Samw 	void  *newacep;
13685331Samw 	uint16_t type, flags;
13695331Samw 	uint32_t mask;
13705331Samw 	uint64_t fuid;
1371789Sahrens 
13725331Samw 	type = aclp->z_ops.ace_type_get(acep);
13735331Samw 	flags = aclp->z_ops.ace_flags_get(acep);
13745331Samw 	mask = aclp->z_ops.ace_mask_get(acep);
13755331Samw 	fuid = aclp->z_ops.ace_who_get(acep);
13765331Samw 
13775331Samw 	aclnode = zfs_acl_ace_insert(aclp, acep);
13785331Samw 	newacep = aclnode->z_acldata;
13795331Samw 
13805331Samw 	aclp->z_ops.ace_type_set(newacep, type);
13815331Samw 	aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE);
13825331Samw 	aclp->z_ops.ace_mask_set(newacep, mask);
13835331Samw 	aclp->z_ops.ace_type_set(newacep, type);
13845331Samw 	aclp->z_ops.ace_who_set(newacep, fuid);
13855331Samw 	aclp->z_next_ace = acep;
13865331Samw 	flags &= ~ALL_INHERIT;
13875331Samw 	aclp->z_ops.ace_flags_set(acep, flags);
13885435Smarks 	currnode = zfs_acl_curr_node(aclp);
13895435Smarks 	ASSERT(currnode->z_ace_idx >= 1);
13905331Samw 	currnode->z_ace_idx -= 1;
1391789Sahrens }
1392789Sahrens 
1393789Sahrens /*
1394789Sahrens  * Are ACES started at index i, the canonical six ACES?
1395789Sahrens  */
1396789Sahrens static int
13975331Samw zfs_have_canonical_six(zfs_acl_t *aclp)
1398789Sahrens {
13995331Samw 	void *acep;
14005331Samw 	zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl);
14015331Samw 	int		i = 0;
14025331Samw 	size_t abstract_size = aclp->z_ops.ace_abstract_size();
14035331Samw 
14045331Samw 	ASSERT(aclnode != NULL);
1405789Sahrens 
14065331Samw 	if (aclnode->z_ace_count < 6)
14075331Samw 		return (0);
14085331Samw 
14095331Samw 	acep = (void *)((caddr_t)aclnode->z_acldata +
14105331Samw 	    aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6));
14115331Samw 
14125331Samw 	if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1413789Sahrens 	    DENY, ACE_OWNER, 0) &&
14145331Samw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
14155331Samw 	    ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) &&
14165331Samw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY,
14175331Samw 	    OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep +
14185331Samw 	    (abstract_size * i++),
14195331Samw 	    ALLOW, OWNING_GROUP, 0) &&
14205331Samw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
1421789Sahrens 	    DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) &&
14225331Samw 	    zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
14235331Samw 	    ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) {
1424789Sahrens 		return (1);
1425789Sahrens 	} else {
1426789Sahrens 		return (0);
1427789Sahrens 	}
1428789Sahrens }
1429789Sahrens 
14305331Samw 
1431789Sahrens /*
1432789Sahrens  * Apply step 1g, to group entries
1433789Sahrens  *
1434789Sahrens  * Need to deal with corner case where group may have
1435789Sahrens  * greater permissions than owner.  If so then limit
1436789Sahrens  * group permissions, based on what extra permissions
1437789Sahrens  * group has.
1438789Sahrens  */
1439789Sahrens static void
14405331Samw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep,
14415331Samw     mode_t mode)
1442789Sahrens {
14435331Samw 	uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep);
14445331Samw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
14455331Samw 	uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep);
1446789Sahrens 	mode_t extramode = (mode >> 3) & 07;
1447789Sahrens 	mode_t ownermode = (mode >> 6);
1448789Sahrens 
14495331Samw 	if (prevflags & ACE_IDENTIFIER_GROUP) {
1450789Sahrens 
1451789Sahrens 		extramode &= ~ownermode;
1452789Sahrens 
1453789Sahrens 		if (extramode) {
14545331Samw 			if (extramode & S_IROTH) {
14555331Samw 				prevmask &= ~ACE_READ_DATA;
14565331Samw 				mask &= ~ACE_READ_DATA;
1457789Sahrens 			}
14585331Samw 			if (extramode & S_IWOTH) {
14595331Samw 				prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
14605331Samw 				mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
1461789Sahrens 			}
14625331Samw 			if (extramode & S_IXOTH) {
14635331Samw 				prevmask  &= ~ACE_EXECUTE;
14645331Samw 				mask &= ~ACE_EXECUTE;
1465789Sahrens 			}
1466789Sahrens 		}
1467789Sahrens 	}
14685331Samw 	aclp->z_ops.ace_mask_set(acep, mask);
14695331Samw 	aclp->z_ops.ace_mask_set(prevacep, prevmask);
1470789Sahrens }
1471789Sahrens 
1472789Sahrens /*
1473789Sahrens  * Apply the chmod algorithm as described
1474789Sahrens  * in PSARC/2002/240
1475789Sahrens  */
14765824Smarks static void
14775824Smarks zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp)
1478789Sahrens {
1479789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
14805331Samw 	void		*acep = NULL, *prevacep = NULL;
14815331Samw 	uint64_t	who;
1482789Sahrens 	int 		i;
1483789Sahrens 	int 		entry_type;
1484789Sahrens 	int 		reuse_deny;
1485789Sahrens 	int 		need_canonical_six = 1;
14865331Samw 	uint16_t	iflags, type;
14875331Samw 	uint32_t	access_mask;
1488789Sahrens 
1489789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
1490789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_lock));
1491789Sahrens 
14925331Samw 	aclp->z_hints = (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
14935489Smarks 
14945489Smarks 	/*
14955489Smarks 	 * If discard then just discard all ACL nodes which
14965489Smarks 	 * represent the ACEs.
14975489Smarks 	 *
14985489Smarks 	 * New owner@/group@/everone@ ACEs will be added
14995489Smarks 	 * later.
15005489Smarks 	 */
15015489Smarks 	if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD)
15025489Smarks 		zfs_acl_release_nodes(aclp);
15035489Smarks 
15045331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
15055331Samw 	    &iflags, &type)) {
15065331Samw 
15075331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
15085331Samw 		iflags = (iflags & ALL_INHERIT);
1509789Sahrens 
15105331Samw 		if ((type != ALLOW && type != DENY) ||
1511905Smarks 		    (iflags & ACE_INHERIT_ONLY_ACE)) {
1512905Smarks 			if (iflags)
15135331Samw 				aclp->z_hints |= ZFS_INHERIT_ACE;
15145331Samw 			switch (type) {
15155331Samw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
15165331Samw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
15175331Samw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
15185331Samw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
15195331Samw 				aclp->z_hints |= ZFS_ACL_OBJ_ACE;
15205331Samw 				break;
15215331Samw 			}
15225331Samw 			goto nextace;
1523789Sahrens 		}
1524789Sahrens 
1525789Sahrens 		/*
1526789Sahrens 		 * Need to split ace into two?
1527789Sahrens 		 */
1528905Smarks 		if ((iflags & (ACE_FILE_INHERIT_ACE|
1529789Sahrens 		    ACE_DIRECTORY_INHERIT_ACE)) &&
1530905Smarks 		    (!(iflags & ACE_INHERIT_ONLY_ACE))) {
15315331Samw 			zfs_acl_split_ace(aclp, acep);
15325331Samw 			aclp->z_hints |= ZFS_INHERIT_ACE;
15335331Samw 			goto nextace;
1534789Sahrens 		}
1535789Sahrens 
1536789Sahrens 		if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
1537789Sahrens 		    (entry_type == OWNING_GROUP)) {
15385331Samw 			access_mask &= ~OGE_CLEAR;
15395331Samw 			aclp->z_ops.ace_mask_set(acep, access_mask);
15405331Samw 			goto nextace;
1541789Sahrens 		} else {
15425331Samw 			reuse_deny = B_TRUE;
15435331Samw 			if (type == ALLOW) {
1544789Sahrens 
1545789Sahrens 				/*
1546789Sahrens 				 * Check preceding ACE if any, to see
1547789Sahrens 				 * if we need to prepend a DENY ACE.
1548789Sahrens 				 * This is only applicable when the acl_mode
1549789Sahrens 				 * property == groupmask.
1550789Sahrens 				 */
15512676Seschrock 				if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) {
1552789Sahrens 
15535331Samw 					reuse_deny = zfs_reuse_deny(aclp, acep,
15545331Samw 					    prevacep);
1555789Sahrens 
15565959Smarks 					if (!reuse_deny) {
15575331Samw 						prevacep =
15585331Samw 						    zfs_acl_prepend_deny(zp,
15595331Samw 						    aclp, acep, mode);
1560789Sahrens 					} else {
1561789Sahrens 						zfs_acl_prepend_fixup(
15625331Samw 						    aclp, prevacep,
15635331Samw 						    acep, mode,
1564789Sahrens 						    zp->z_phys->zp_uid);
1565789Sahrens 					}
15665331Samw 					zfs_fixup_group_entries(aclp, acep,
15675331Samw 					    prevacep, mode);
15685331Samw 
1569789Sahrens 				}
1570789Sahrens 			}
1571789Sahrens 		}
15725331Samw nextace:
15735331Samw 		prevacep = acep;
1574789Sahrens 	}
1575789Sahrens 
1576789Sahrens 	/*
1577789Sahrens 	 * Check out last six aces, if we have six.
1578789Sahrens 	 */
1579789Sahrens 
1580789Sahrens 	if (aclp->z_acl_count >= 6) {
15815331Samw 		if (zfs_have_canonical_six(aclp)) {
1582789Sahrens 			need_canonical_six = 0;
1583789Sahrens 		}
1584789Sahrens 	}
1585789Sahrens 
1586789Sahrens 	if (need_canonical_six) {
15875331Samw 		size_t abstract_size = aclp->z_ops.ace_abstract_size();
15885331Samw 		void *zacep;
15895331Samw 		zfs_acl_node_t *aclnode =
15905331Samw 		    zfs_acl_node_alloc(abstract_size * 6);
1591789Sahrens 
15925331Samw 		aclnode->z_size = abstract_size * 6;
15935331Samw 		aclnode->z_ace_count = 6;
15945331Samw 		aclp->z_acl_bytes += aclnode->z_size;
15955331Samw 		list_insert_tail(&aclp->z_acl, aclnode);
15965331Samw 
15975331Samw 		zacep = aclnode->z_acldata;
15985331Samw 
15995331Samw 		i = 0;
16005331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
16015331Samw 		    0, DENY, -1, ACE_OWNER);
16025331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
16035331Samw 		    OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER);
16045331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
16055331Samw 		    DENY, -1, OWNING_GROUP);
16065331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
16075331Samw 		    ALLOW, -1, OWNING_GROUP);
16085331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
16095331Samw 		    EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE);
16105331Samw 		zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
16115331Samw 		    EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE);
1612789Sahrens 		aclp->z_acl_count += 6;
1613789Sahrens 	}
1614789Sahrens 
1615789Sahrens 	zfs_acl_fixup_canonical_six(aclp, mode);
1616789Sahrens }
1617789Sahrens 
1618789Sahrens int
16195824Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
1620789Sahrens {
1621789Sahrens 	int error;
1622789Sahrens 
16235824Smarks 	mutex_enter(&zp->z_lock);
1624789Sahrens 	mutex_enter(&zp->z_acl_lock);
16255824Smarks 	*aclp = NULL;
16265824Smarks 	error = zfs_acl_node_read(zp, aclp, B_TRUE);
16271544Seschrock 	if (error == 0)
16285824Smarks 		zfs_acl_chmod(zp, mode, *aclp);
1629789Sahrens 	mutex_exit(&zp->z_acl_lock);
16305824Smarks 	mutex_exit(&zp->z_lock);
1631789Sahrens 	return (error);
1632789Sahrens }
1633789Sahrens 
1634789Sahrens /*
1635789Sahrens  * strip off write_owner and write_acl
1636789Sahrens  */
1637789Sahrens static void
16386385Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
1639789Sahrens {
16405331Samw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
16415331Samw 
16426385Smarks 	if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) &&
16435331Samw 	    (aclp->z_ops.ace_type_get(acep) == ALLOW)) {
16446385Smarks 		mask &= ~RESTRICTED_CLEAR;
16455331Samw 		aclp->z_ops.ace_mask_set(acep, mask);
16465331Samw 	}
16475331Samw }
16485331Samw 
16495331Samw /*
16505331Samw  * Should ACE be inherited?
16515331Samw  */
16525331Samw static int
16535331Samw zfs_ace_can_use(znode_t *zp, uint16_t acep_flags)
16545331Samw {
16555331Samw 	int vtype = ZTOV(zp)->v_type;
16565331Samw 	int	iflags = (acep_flags & 0xf);
16575331Samw 
16585331Samw 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
16595331Samw 		return (1);
16605331Samw 	else if (iflags & ACE_FILE_INHERIT_ACE)
16615331Samw 		return (!((vtype == VDIR) &&
16625331Samw 		    (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
16635331Samw 	return (0);
1664789Sahrens }
1665789Sahrens 
1666789Sahrens /*
1667789Sahrens  * inherit inheritable ACEs from parent
1668789Sahrens  */
1669789Sahrens static zfs_acl_t *
16708053SMark.Shellenbaum@Sun.COM zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp, uint64_t mode,
16718053SMark.Shellenbaum@Sun.COM     boolean_t *need_chmod)
1672789Sahrens {
1673789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
16745331Samw 	void		*pacep;
16755331Samw 	void		*acep, *acep2;
16765331Samw 	zfs_acl_node_t  *aclnode, *aclnode2;
1677789Sahrens 	zfs_acl_t	*aclp = NULL;
16785331Samw 	uint64_t	who;
16795331Samw 	uint32_t	access_mask;
16805331Samw 	uint16_t	iflags, newflags, type;
16815331Samw 	size_t		ace_size;
16825331Samw 	void		*data1, *data2;
16835331Samw 	size_t		data1sz, data2sz;
16848053SMark.Shellenbaum@Sun.COM 	boolean_t	vdir = ZTOV(zp)->v_type == VDIR;
16858053SMark.Shellenbaum@Sun.COM 	boolean_t	vreg = ZTOV(zp)->v_type == VREG;
16868053SMark.Shellenbaum@Sun.COM 	boolean_t	passthrough, passthrough_x, noallow;
16878053SMark.Shellenbaum@Sun.COM 
16888053SMark.Shellenbaum@Sun.COM 	passthrough_x =
16898053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X;
16908053SMark.Shellenbaum@Sun.COM 	passthrough = passthrough_x ||
16918053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH;
16928053SMark.Shellenbaum@Sun.COM 	noallow =
16938053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW;
1694789Sahrens 
16956385Smarks 	*need_chmod = B_TRUE;
16965331Samw 	pacep = NULL;
16977559SMark.Shellenbaum@Sun.COM 	aclp = zfs_acl_alloc(paclp->z_version);
16988053SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD)
16998053SMark.Shellenbaum@Sun.COM 		return (aclp);
17008053SMark.Shellenbaum@Sun.COM 	while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
17018053SMark.Shellenbaum@Sun.COM 	    &access_mask, &iflags, &type)) {
17028053SMark.Shellenbaum@Sun.COM 
17038053SMark.Shellenbaum@Sun.COM 		/*
17048053SMark.Shellenbaum@Sun.COM 		 * don't inherit bogus ACEs
17058053SMark.Shellenbaum@Sun.COM 		 */
17068053SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
17078053SMark.Shellenbaum@Sun.COM 			continue;
17088053SMark.Shellenbaum@Sun.COM 
17098053SMark.Shellenbaum@Sun.COM 		if (noallow && type == ALLOW)
17108053SMark.Shellenbaum@Sun.COM 			continue;
17118053SMark.Shellenbaum@Sun.COM 
17128053SMark.Shellenbaum@Sun.COM 		ace_size = aclp->z_ops.ace_size(pacep);
17138053SMark.Shellenbaum@Sun.COM 
17148053SMark.Shellenbaum@Sun.COM 		if (!zfs_ace_can_use(zp, iflags))
17158053SMark.Shellenbaum@Sun.COM 			continue;
1716789Sahrens 
17178053SMark.Shellenbaum@Sun.COM 		/*
17188053SMark.Shellenbaum@Sun.COM 		 * If owner@, group@, or everyone@ inheritable
17198053SMark.Shellenbaum@Sun.COM 		 * then zfs_acl_chmod() isn't needed.
17208053SMark.Shellenbaum@Sun.COM 		 */
17218053SMark.Shellenbaum@Sun.COM 		if (passthrough &&
17228053SMark.Shellenbaum@Sun.COM 		    ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
17238053SMark.Shellenbaum@Sun.COM 		    ((iflags & OWNING_GROUP) ==
17248053SMark.Shellenbaum@Sun.COM 		    OWNING_GROUP)) && (vreg || (vdir && (iflags &
17258053SMark.Shellenbaum@Sun.COM 		    ACE_DIRECTORY_INHERIT_ACE)))) {
17268053SMark.Shellenbaum@Sun.COM 			*need_chmod = B_FALSE;
17277559SMark.Shellenbaum@Sun.COM 
17288053SMark.Shellenbaum@Sun.COM 			if (!vdir && passthrough_x &&
17298053SMark.Shellenbaum@Sun.COM 			    ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) {
17308053SMark.Shellenbaum@Sun.COM 				access_mask &= ~ACE_EXECUTE;
17318053SMark.Shellenbaum@Sun.COM 			}
17328053SMark.Shellenbaum@Sun.COM 		}
1733789Sahrens 
17348053SMark.Shellenbaum@Sun.COM 		aclnode = zfs_acl_node_alloc(ace_size);
17358053SMark.Shellenbaum@Sun.COM 		list_insert_tail(&aclp->z_acl, aclnode);
17368053SMark.Shellenbaum@Sun.COM 		acep = aclnode->z_acldata;
17376385Smarks 
17388053SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, acep, access_mask, type,
17398053SMark.Shellenbaum@Sun.COM 		    who, iflags|ACE_INHERITED_ACE);
17408053SMark.Shellenbaum@Sun.COM 
17418053SMark.Shellenbaum@Sun.COM 		/*
17428053SMark.Shellenbaum@Sun.COM 		 * Copy special opaque data if any
17438053SMark.Shellenbaum@Sun.COM 		 */
17448053SMark.Shellenbaum@Sun.COM 		if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) {
17458053SMark.Shellenbaum@Sun.COM 			VERIFY((data2sz = aclp->z_ops.ace_data(acep,
17468053SMark.Shellenbaum@Sun.COM 			    &data2)) == data1sz);
17478053SMark.Shellenbaum@Sun.COM 			bcopy(data1, data2, data2sz);
17488053SMark.Shellenbaum@Sun.COM 		}
17498053SMark.Shellenbaum@Sun.COM 		aclp->z_acl_count++;
17508053SMark.Shellenbaum@Sun.COM 		aclnode->z_ace_count++;
17518053SMark.Shellenbaum@Sun.COM 		aclp->z_acl_bytes += aclnode->z_size;
17528053SMark.Shellenbaum@Sun.COM 		newflags = aclp->z_ops.ace_flags_get(acep);
17538053SMark.Shellenbaum@Sun.COM 
17548053SMark.Shellenbaum@Sun.COM 		if (vdir)
17558053SMark.Shellenbaum@Sun.COM 			aclp->z_hints |= ZFS_INHERIT_ACE;
17566385Smarks 
17578053SMark.Shellenbaum@Sun.COM 		if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) {
17588053SMark.Shellenbaum@Sun.COM 			newflags &= ~ALL_INHERIT;
17598053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep,
17608053SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
17618053SMark.Shellenbaum@Sun.COM 			zfs_restricted_update(zfsvfs, aclp, acep);
17628053SMark.Shellenbaum@Sun.COM 			continue;
17638053SMark.Shellenbaum@Sun.COM 		}
17648053SMark.Shellenbaum@Sun.COM 
17658053SMark.Shellenbaum@Sun.COM 		ASSERT(vdir);
17668053SMark.Shellenbaum@Sun.COM 
17678053SMark.Shellenbaum@Sun.COM 		newflags = aclp->z_ops.ace_flags_get(acep);
17688053SMark.Shellenbaum@Sun.COM 		if ((iflags & (ACE_FILE_INHERIT_ACE |
17698053SMark.Shellenbaum@Sun.COM 		    ACE_DIRECTORY_INHERIT_ACE)) !=
17708053SMark.Shellenbaum@Sun.COM 		    ACE_FILE_INHERIT_ACE) {
17718053SMark.Shellenbaum@Sun.COM 			aclnode2 = zfs_acl_node_alloc(ace_size);
17728053SMark.Shellenbaum@Sun.COM 			list_insert_tail(&aclp->z_acl, aclnode2);
17738053SMark.Shellenbaum@Sun.COM 			acep2 = aclnode2->z_acldata;
17748053SMark.Shellenbaum@Sun.COM 			zfs_set_ace(aclp, acep2,
17758053SMark.Shellenbaum@Sun.COM 			    access_mask, type, who,
17768053SMark.Shellenbaum@Sun.COM 			    iflags|ACE_INHERITED_ACE);
17778053SMark.Shellenbaum@Sun.COM 			newflags |= ACE_INHERIT_ONLY_ACE;
17788053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep, newflags);
17798053SMark.Shellenbaum@Sun.COM 			newflags &= ~ALL_INHERIT;
17808053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep2,
17818053SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
1782789Sahrens 
17836385Smarks 			/*
17846385Smarks 			 * Copy special opaque data if any
17856385Smarks 			 */
17868053SMark.Shellenbaum@Sun.COM 			if ((data1sz = aclp->z_ops.ace_data(acep,
17876385Smarks 			    &data1)) != 0) {
17888053SMark.Shellenbaum@Sun.COM 				VERIFY((data2sz =
17898053SMark.Shellenbaum@Sun.COM 				    aclp->z_ops.ace_data(acep2,
17906385Smarks 				    &data2)) == data1sz);
17918053SMark.Shellenbaum@Sun.COM 				bcopy(data1, data2, data1sz);
17926385Smarks 			}
17936385Smarks 			aclp->z_acl_count++;
17948053SMark.Shellenbaum@Sun.COM 			aclnode2->z_ace_count++;
17956385Smarks 			aclp->z_acl_bytes += aclnode->z_size;
17968053SMark.Shellenbaum@Sun.COM 			zfs_restricted_update(zfsvfs, aclp, acep2);
17978053SMark.Shellenbaum@Sun.COM 		} else {
17988053SMark.Shellenbaum@Sun.COM 			newflags |= ACE_INHERIT_ONLY_ACE;
17998053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep,
18008053SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
1801789Sahrens 		}
1802789Sahrens 	}
1803789Sahrens 	return (aclp);
1804789Sahrens }
1805789Sahrens 
1806789Sahrens /*
1807789Sahrens  * Create file system object initial permissions
1808789Sahrens  * including inheritable ACEs.
1809789Sahrens  */
1810789Sahrens void
1811789Sahrens zfs_perm_init(znode_t *zp, znode_t *parent, int flag,
18125331Samw     vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
18135331Samw     zfs_acl_t *setaclp, zfs_fuid_info_t **fuidp)
1814789Sahrens {
18155959Smarks 	uint64_t	mode, fuid, fgid;
1816789Sahrens 	int		error;
18175331Samw 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
18185331Samw 	zfs_acl_t	*aclp = NULL;
18195331Samw 	zfs_acl_t	*paclp;
18205331Samw 	xvattr_t	*xvap = (xvattr_t *)vap;
18215959Smarks 	gid_t		gid;
18226385Smarks 	boolean_t	need_chmod = B_TRUE;
18235331Samw 
18245331Samw 	if (setaclp)
18255331Samw 		aclp = setaclp;
1826789Sahrens 
1827789Sahrens 	mode = MAKEIMODE(vap->va_type, vap->va_mode);
1828789Sahrens 
1829789Sahrens 	/*
1830789Sahrens 	 * Determine uid and gid.
1831789Sahrens 	 */
1832789Sahrens 	if ((flag & (IS_ROOT_NODE | IS_REPLAY)) ||
1833789Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
18345959Smarks 		fuid = zfs_fuid_create(zfsvfs, vap->va_uid, cr,
18355331Samw 		    ZFS_OWNER, tx, fuidp);
18365959Smarks 		fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
18375331Samw 		    ZFS_GROUP, tx, fuidp);
18385959Smarks 		gid = vap->va_gid;
1839789Sahrens 	} else {
18405959Smarks 		fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, tx, cr, fuidp);
18415959Smarks 		fgid = 0;
18425959Smarks 		if (vap->va_mask & AT_GID)  {
18435959Smarks 			fgid = zfs_fuid_create(zfsvfs, vap->va_gid, cr,
18445959Smarks 			    ZFS_GROUP, tx, fuidp);
18455959Smarks 			gid = vap->va_gid;
18465959Smarks 			if (fgid != parent->z_phys->zp_gid &&
18475959Smarks 			    !groupmember(vap->va_gid, cr) &&
18485959Smarks 			    secpolicy_vnode_create_gid(cr) != 0)
18495959Smarks 				fgid = 0;
18505959Smarks 		}
18515959Smarks 		if (fgid == 0) {
18525959Smarks 			if (parent->z_phys->zp_mode & S_ISGID) {
18535959Smarks 				fgid = parent->z_phys->zp_gid;
18545959Smarks 				gid = zfs_fuid_map_id(zfsvfs, fgid,
18555959Smarks 				    cr, ZFS_GROUP);
18565959Smarks 			} else {
18575959Smarks 				fgid = zfs_fuid_create_cred(zfsvfs,
18585959Smarks 				    ZFS_GROUP, tx, cr, fuidp);
18595959Smarks 				gid = crgetgid(cr);
18605959Smarks 			}
18615331Samw 		}
1862789Sahrens 	}
1863789Sahrens 
1864789Sahrens 	/*
1865789Sahrens 	 * If we're creating a directory, and the parent directory has the
1866789Sahrens 	 * set-GID bit set, set in on the new directory.
1867789Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1868789Sahrens 	 * file's new group, clear the file's set-GID bit.
1869789Sahrens 	 */
1870789Sahrens 
18715959Smarks 	if ((parent->z_phys->zp_mode & S_ISGID) && (vap->va_type == VDIR)) {
1872789Sahrens 		mode |= S_ISGID;
18735959Smarks 	} else {
1874789Sahrens 		if ((mode & S_ISGID) &&
1875789Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
1876789Sahrens 			mode &= ~S_ISGID;
1877789Sahrens 	}
1878789Sahrens 
18795959Smarks 	zp->z_phys->zp_uid = fuid;
18805959Smarks 	zp->z_phys->zp_gid = fgid;
1881789Sahrens 	zp->z_phys->zp_mode = mode;
1882789Sahrens 
18835331Samw 	if (aclp == NULL) {
18845331Samw 		mutex_enter(&parent->z_lock);
18857057Smarks 		if ((ZTOV(parent)->v_type == VDIR &&
18867328SMark.Shellenbaum@Sun.COM 		    (parent->z_phys->zp_flags & ZFS_INHERIT_ACE)) &&
18877328SMark.Shellenbaum@Sun.COM 		    !(zp->z_phys->zp_flags & ZFS_XATTR)) {
18885331Samw 			mutex_enter(&parent->z_acl_lock);
18895331Samw 			VERIFY(0 == zfs_acl_node_read(parent, &paclp, B_FALSE));
18905331Samw 			mutex_exit(&parent->z_acl_lock);
18918053SMark.Shellenbaum@Sun.COM 			aclp = zfs_acl_inherit(zp, paclp, mode, &need_chmod);
18925331Samw 			zfs_acl_free(paclp);
18935331Samw 		} else {
18945331Samw 			aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
18955331Samw 		}
18965331Samw 		mutex_exit(&parent->z_lock);
18975331Samw 		mutex_enter(&zp->z_lock);
18985331Samw 		mutex_enter(&zp->z_acl_lock);
18996385Smarks 		if (need_chmod)
19006385Smarks 			zfs_acl_chmod(zp, mode, aclp);
1901789Sahrens 	} else {
19025331Samw 		mutex_enter(&zp->z_lock);
19035331Samw 		mutex_enter(&zp->z_acl_lock);
1904789Sahrens 	}
19055331Samw 
19065331Samw 	/* Force auto_inherit on all new directory objects */
19075331Samw 	if (vap->va_type == VDIR)
19085331Samw 		aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
19095331Samw 
19105771Sjp151216 	error = zfs_aclset_common(zp, aclp, cr, fuidp, tx);
19115331Samw 
19125331Samw 	/* Set optional attributes if any */
19135331Samw 	if (vap->va_mask & AT_XVATTR)
19145331Samw 		zfs_xvattr_set(zp, xvap);
19155331Samw 
1916789Sahrens 	mutex_exit(&zp->z_lock);
1917789Sahrens 	mutex_exit(&zp->z_acl_lock);
1918789Sahrens 	ASSERT3U(error, ==, 0);
1919789Sahrens 
19205959Smarks 	if (aclp != setaclp)
19215331Samw 		zfs_acl_free(aclp);
1922789Sahrens }
1923789Sahrens 
1924789Sahrens /*
1925789Sahrens  * Retrieve a files ACL
1926789Sahrens  */
1927789Sahrens int
19285331Samw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1929789Sahrens {
1930789Sahrens 	zfs_acl_t	*aclp;
19315331Samw 	ulong_t		mask;
1932789Sahrens 	int		error;
19335331Samw 	int 		count = 0;
19345331Samw 	int		largeace = 0;
1935789Sahrens 
19365331Samw 	mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
19375331Samw 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
19385331Samw 
19395331Samw 	if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
19405331Samw 		return (error);
1941789Sahrens 
1942789Sahrens 	if (mask == 0)
1943789Sahrens 		return (ENOSYS);
1944789Sahrens 
1945789Sahrens 	mutex_enter(&zp->z_acl_lock);
1946789Sahrens 
19475331Samw 	error = zfs_acl_node_read(zp, &aclp, B_FALSE);
19481544Seschrock 	if (error != 0) {
19491544Seschrock 		mutex_exit(&zp->z_acl_lock);
19501544Seschrock 		return (error);
19511544Seschrock 	}
19521544Seschrock 
19535331Samw 	/*
19545331Samw 	 * Scan ACL to determine number of ACEs
19555331Samw 	 */
19565331Samw 	if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) &&
19575331Samw 	    !(mask & VSA_ACE_ALLTYPES)) {
19585331Samw 		void *zacep = NULL;
19595331Samw 		uint64_t who;
19605331Samw 		uint32_t access_mask;
19615331Samw 		uint16_t type, iflags;
19625331Samw 
19635331Samw 		while (zacep = zfs_acl_next_ace(aclp, zacep,
19645331Samw 		    &who, &access_mask, &iflags, &type)) {
19655331Samw 			switch (type) {
19665331Samw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
19675331Samw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
19685331Samw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
19695331Samw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
19705331Samw 				largeace++;
19715331Samw 				continue;
19725331Samw 			default:
19735331Samw 				count++;
19745331Samw 			}
19755331Samw 		}
19765331Samw 		vsecp->vsa_aclcnt = count;
19775331Samw 	} else
19785331Samw 		count = aclp->z_acl_count;
1979789Sahrens 
1980789Sahrens 	if (mask & VSA_ACECNT) {
19815331Samw 		vsecp->vsa_aclcnt = count;
1982789Sahrens 	}
1983789Sahrens 
1984789Sahrens 	if (mask & VSA_ACE) {
19855331Samw 		size_t aclsz;
19865331Samw 
19875331Samw 		zfs_acl_node_t *aclnode = list_head(&aclp->z_acl);
19885331Samw 
19895331Samw 		aclsz = count * sizeof (ace_t) +
19905331Samw 		    sizeof (ace_object_t) * largeace;
19915331Samw 
19925331Samw 		vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
19935331Samw 		vsecp->vsa_aclentsz = aclsz;
19945331Samw 
19955331Samw 		if (aclp->z_version == ZFS_ACL_VERSION_FUID)
19965771Sjp151216 			zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr,
19975331Samw 			    vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
19985331Samw 		else {
19995331Samw 			bcopy(aclnode->z_acldata, vsecp->vsa_aclentp,
20005331Samw 			    count * sizeof (ace_t));
20015331Samw 		}
20025331Samw 	}
20035331Samw 	if (mask & VSA_ACE_ACLFLAGS) {
20045331Samw 		vsecp->vsa_aclflags = 0;
20055331Samw 		if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED)
20065331Samw 			vsecp->vsa_aclflags |= ACL_DEFAULTED;
20075331Samw 		if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED)
20085331Samw 			vsecp->vsa_aclflags |= ACL_PROTECTED;
20095331Samw 		if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT)
20105331Samw 			vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
2011789Sahrens 	}
2012789Sahrens 
2013789Sahrens 	mutex_exit(&zp->z_acl_lock);
2014789Sahrens 
2015789Sahrens 	zfs_acl_free(aclp);
2016789Sahrens 
2017789Sahrens 	return (0);
2018789Sahrens }
2019789Sahrens 
20205331Samw int
20215331Samw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
20225331Samw     vsecattr_t *vsecp, zfs_acl_t **zaclp)
20235331Samw {
20245331Samw 	zfs_acl_t *aclp;
20255331Samw 	zfs_acl_node_t *aclnode;
20265331Samw 	int aclcnt = vsecp->vsa_aclcnt;
20275331Samw 	int error;
20285331Samw 
20295331Samw 	if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
20305331Samw 		return (EINVAL);
20315331Samw 
20325331Samw 	aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
20335331Samw 
20345331Samw 	aclp->z_hints = 0;
20355331Samw 	aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
20365331Samw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
20375331Samw 		if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
20385331Samw 		    (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
20395331Samw 		    aclcnt, &aclnode->z_size)) != 0) {
20405331Samw 			zfs_acl_free(aclp);
20415331Samw 			zfs_acl_node_free(aclnode);
20425331Samw 			return (error);
20435331Samw 		}
20445331Samw 	} else {
20455331Samw 		if ((error = zfs_copy_ace_2_fuid(obj_type, aclp,
20465331Samw 		    vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
20475331Samw 		    &aclnode->z_size)) != 0) {
20485331Samw 			zfs_acl_free(aclp);
20495331Samw 			zfs_acl_node_free(aclnode);
20505331Samw 			return (error);
20515331Samw 		}
20525331Samw 	}
20535331Samw 	aclp->z_acl_bytes = aclnode->z_size;
20545331Samw 	aclnode->z_ace_count = aclcnt;
20555331Samw 	aclp->z_acl_count = aclcnt;
20565331Samw 	list_insert_head(&aclp->z_acl, aclnode);
20575331Samw 
20585331Samw 	/*
20595331Samw 	 * If flags are being set then add them to z_hints
20605331Samw 	 */
20615331Samw 	if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
20625331Samw 		if (vsecp->vsa_aclflags & ACL_PROTECTED)
20635331Samw 			aclp->z_hints |= ZFS_ACL_PROTECTED;
20645331Samw 		if (vsecp->vsa_aclflags & ACL_DEFAULTED)
20655331Samw 			aclp->z_hints |= ZFS_ACL_DEFAULTED;
20665331Samw 		if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
20675331Samw 			aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
20685331Samw 	}
20695331Samw 
20705331Samw 	*zaclp = aclp;
20715331Samw 
20725331Samw 	return (0);
20735331Samw }
20745331Samw 
2075789Sahrens /*
2076789Sahrens  * Set a files ACL
2077789Sahrens  */
2078789Sahrens int
20795331Samw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
2080789Sahrens {
2081789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2082789Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
2083789Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
2084789Sahrens 	dmu_tx_t	*tx;
2085789Sahrens 	int		error;
2086789Sahrens 	zfs_acl_t	*aclp;
20875331Samw 	zfs_fuid_info_t	*fuidp = NULL;
2088789Sahrens 
2089789Sahrens 	if (mask == 0)
20904300Smarks 		return (ENOSYS);
2091789Sahrens 
20925331Samw 	if (zp->z_phys->zp_flags & ZFS_IMMUTABLE)
20935331Samw 		return (EPERM);
20945331Samw 
20955331Samw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
20965331Samw 		return (error);
20975331Samw 
20985331Samw 	error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, &aclp);
20995331Samw 	if (error)
21005331Samw 		return (error);
21015331Samw 
21025331Samw 	/*
21035331Samw 	 * If ACL wide flags aren't being set then preserve any
21045331Samw 	 * existing flags.
21055331Samw 	 */
21065331Samw 	if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
21075331Samw 		aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
21085331Samw 	}
2109789Sahrens top:
21105331Samw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) {
21115331Samw 		zfs_acl_free(aclp);
21125331Samw 		return (error);
2113789Sahrens 	}
2114789Sahrens 
2115789Sahrens 	mutex_enter(&zp->z_lock);
2116789Sahrens 	mutex_enter(&zp->z_acl_lock);
2117789Sahrens 
2118789Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
2119789Sahrens 	dmu_tx_hold_bonus(tx, zp->z_id);
2120789Sahrens 
2121789Sahrens 	if (zp->z_phys->zp_acl.z_acl_extern_obj) {
21225331Samw 		/* Are we upgrading ACL? */
21235331Samw 		if (zfsvfs->z_version <= ZPL_VERSION_FUID &&
21245331Samw 		    zp->z_phys->zp_acl.z_acl_version ==
21255331Samw 		    ZFS_ACL_VERSION_INITIAL) {
21265331Samw 			dmu_tx_hold_free(tx,
21275331Samw 			    zp->z_phys->zp_acl.z_acl_extern_obj,
21285331Samw 			    0, DMU_OBJECT_END);
21295331Samw 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
21305824Smarks 			    0, aclp->z_acl_bytes);
21315331Samw 		} else {
21325331Samw 			dmu_tx_hold_write(tx,
21335331Samw 			    zp->z_phys->zp_acl.z_acl_extern_obj,
21345331Samw 			    0, aclp->z_acl_bytes);
21355331Samw 		}
21365331Samw 	} else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
21375331Samw 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
21385331Samw 	}
21395824Smarks 	if (aclp->z_has_fuids) {
21405824Smarks 		if (zfsvfs->z_fuid_obj == 0) {
21415824Smarks 			dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
21425331Samw 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
21435824Smarks 			    FUID_SIZE_ESTIMATE(zfsvfs));
21445824Smarks 			dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, FALSE, NULL);
21455824Smarks 		} else {
21465824Smarks 			dmu_tx_hold_bonus(tx, zfsvfs->z_fuid_obj);
21475824Smarks 			dmu_tx_hold_write(tx, zfsvfs->z_fuid_obj, 0,
21485824Smarks 			    FUID_SIZE_ESTIMATE(zfsvfs));
21495824Smarks 		}
2150789Sahrens 	}
2151789Sahrens 
21528227SNeil.Perrin@Sun.COM 	error = dmu_tx_assign(tx, TXG_NOWAIT);
2153789Sahrens 	if (error) {
2154789Sahrens 		mutex_exit(&zp->z_acl_lock);
2155789Sahrens 		mutex_exit(&zp->z_lock);
2156789Sahrens 
21578227SNeil.Perrin@Sun.COM 		if (error == ERESTART) {
21582113Sahrens 			dmu_tx_wait(tx);
21592113Sahrens 			dmu_tx_abort(tx);
2160789Sahrens 			goto top;
2161789Sahrens 		}
21622113Sahrens 		dmu_tx_abort(tx);
21635331Samw 		zfs_acl_free(aclp);
2164789Sahrens 		return (error);
2165789Sahrens 	}
2166789Sahrens 
21675771Sjp151216 	error = zfs_aclset_common(zp, aclp, cr, &fuidp, tx);
2168789Sahrens 	ASSERT(error == 0);
2169789Sahrens 
21705331Samw 	zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
21715331Samw 
21725331Samw 	if (fuidp)
21735331Samw 		zfs_fuid_info_free(fuidp);
2174789Sahrens 	zfs_acl_free(aclp);
2175789Sahrens 	dmu_tx_commit(tx);
2176789Sahrens done:
2177789Sahrens 	mutex_exit(&zp->z_acl_lock);
2178789Sahrens 	mutex_exit(&zp->z_lock);
2179789Sahrens 
2180789Sahrens 	return (error);
2181789Sahrens }
2182789Sahrens 
21835331Samw /*
21845331Samw  * working_mode returns the permissions that were not granted
21855331Samw  */
2186789Sahrens static int
21875331Samw zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
21885331Samw     boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
2189789Sahrens {
2190789Sahrens 	zfs_acl_t	*aclp;
2191789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
21921544Seschrock 	int		error;
2193789Sahrens 	uid_t		uid = crgetuid(cr);
21945331Samw 	uint64_t 	who;
21955331Samw 	uint16_t	type, iflags;
21965331Samw 	uint16_t	entry_type;
21975331Samw 	uint32_t	access_mask;
21986056Smarks 	uint32_t	deny_mask = 0;
21995331Samw 	zfs_ace_hdr_t	*acep = NULL;
22005331Samw 	boolean_t	checkit;
22015331Samw 	uid_t		fowner;
22025331Samw 	uid_t		gowner;
22035331Samw 
22045331Samw 	/*
22055331Samw 	 * Short circuit empty requests
22065331Samw 	 */
22075331Samw 	if (v4_mode == 0)
22085331Samw 		return (0);
22095331Samw 
22105331Samw 	*check_privs = B_TRUE;
2211789Sahrens 
22128227SNeil.Perrin@Sun.COM 	if (zfsvfs->z_replay) {
22132638Sperrin 		*working_mode = 0;
22142638Sperrin 		return (0);
22152638Sperrin 	}
2216789Sahrens 
22172638Sperrin 	*working_mode = v4_mode;
2218789Sahrens 
2219789Sahrens 	if ((v4_mode & WRITE_MASK) &&
2220789Sahrens 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
2221*8952SMark.Shellenbaum@Sun.COM 	    (!IS_DEVVP(ZTOV(zp)) ||
2222*8952SMark.Shellenbaum@Sun.COM 	    (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
22235331Samw 		*check_privs = B_FALSE;
2224789Sahrens 		return (EROFS);
2225789Sahrens 	}
2226789Sahrens 
22275331Samw 	/*
22285331Samw 	 * Only check for READONLY on non-directories.
22295331Samw 	 */
22305331Samw 	if ((v4_mode & WRITE_MASK_DATA) &&
22315331Samw 	    (((ZTOV(zp)->v_type != VDIR) &&
22325331Samw 	    (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
22335331Samw 	    (ZTOV(zp)->v_type == VDIR &&
22345331Samw 	    (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) {
22355331Samw 		*check_privs = B_FALSE;
22365331Samw 		return (EPERM);
22375331Samw 	}
22385331Samw 
22395331Samw 	if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
22405331Samw 	    (zp->z_phys->zp_flags & ZFS_NOUNLINK)) {
22415331Samw 		*check_privs = B_FALSE;
22425331Samw 		return (EPERM);
22435331Samw 	}
22445331Samw 
22455331Samw 	if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
22465331Samw 	    (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) {
22475331Samw 		*check_privs = B_FALSE;
22485331Samw 		return (EACCES);
22495331Samw 	}
22505331Samw 
22515331Samw 	/*
22525331Samw 	 * The caller requested that the ACL check be skipped.  This
22535331Samw 	 * would only happen if the caller checked VOP_ACCESS() with a
22545331Samw 	 * 32 bit ACE mask and already had the appropriate permissions.
22555331Samw 	 */
22565331Samw 	if (skipaclchk) {
22575331Samw 		*working_mode = 0;
22585331Samw 		return (0);
22595331Samw 	}
22605331Samw 
22615771Sjp151216 	zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
22625331Samw 
2263789Sahrens 	mutex_enter(&zp->z_acl_lock);
2264789Sahrens 
22655331Samw 	error = zfs_acl_node_read(zp, &aclp, B_FALSE);
22661544Seschrock 	if (error != 0) {
22671544Seschrock 		mutex_exit(&zp->z_acl_lock);
22681544Seschrock 		return (error);
22691544Seschrock 	}
22701544Seschrock 
22715331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
22725331Samw 	    &iflags, &type)) {
2273789Sahrens 
22747559SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
22757559SMark.Shellenbaum@Sun.COM 			continue;
22767559SMark.Shellenbaum@Sun.COM 
22777057Smarks 		if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
2278789Sahrens 			continue;
2279789Sahrens 
22805331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
22815331Samw 
22825331Samw 		checkit = B_FALSE;
22835331Samw 
2284789Sahrens 		switch (entry_type) {
2285789Sahrens 		case ACE_OWNER:
22865331Samw 			if (uid == fowner)
22875331Samw 				checkit = B_TRUE;
2288789Sahrens 			break;
22895331Samw 		case OWNING_GROUP:
22905331Samw 			who = gowner;
22915331Samw 			/*FALLTHROUGH*/
2292789Sahrens 		case ACE_IDENTIFIER_GROUP:
22935331Samw 			checkit = zfs_groupmember(zfsvfs, who, cr);
2294789Sahrens 			break;
2295789Sahrens 		case ACE_EVERYONE:
22965331Samw 			checkit = B_TRUE;
2297789Sahrens 			break;
2298789Sahrens 
2299789Sahrens 		/* USER Entry */
2300789Sahrens 		default:
2301789Sahrens 			if (entry_type == 0) {
23025331Samw 				uid_t newid;
23035331Samw 
23045959Smarks 				newid = zfs_fuid_map_id(zfsvfs, who, cr,
23055959Smarks 				    ZFS_ACE_USER);
23065331Samw 				if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
23075331Samw 				    uid == newid)
23085331Samw 					checkit = B_TRUE;
2309789Sahrens 				break;
23105331Samw 			} else {
23115331Samw 				zfs_acl_free(aclp);
23125331Samw 				mutex_exit(&zp->z_acl_lock);
23135331Samw 				return (EIO);
2314789Sahrens 			}
23155331Samw 		}
23165331Samw 
23175331Samw 		if (checkit) {
23186056Smarks 			uint32_t mask_matched = (access_mask & *working_mode);
23196056Smarks 
23206056Smarks 			if (mask_matched) {
23216056Smarks 				if (type == DENY)
23226056Smarks 					deny_mask |= mask_matched;
23236056Smarks 
23246056Smarks 				*working_mode &= ~mask_matched;
23255331Samw 			}
2326789Sahrens 		}
2327789Sahrens 
23286056Smarks 		/* Are we done? */
23296056Smarks 		if (*working_mode == 0)
2330789Sahrens 			break;
2331789Sahrens 	}
2332789Sahrens 
2333789Sahrens 	mutex_exit(&zp->z_acl_lock);
2334789Sahrens 	zfs_acl_free(aclp);
23356056Smarks 
23366056Smarks 	/* Put the found 'denies' back on the working mode */
23377163Smarks 	if (deny_mask) {
23387163Smarks 		*working_mode |= deny_mask;
23396056Smarks 		return (EACCES);
23407163Smarks 	} else if (*working_mode) {
23417163Smarks 		return (-1);
23427163Smarks 	}
23436056Smarks 
23446056Smarks 	return (0);
2345789Sahrens }
2346789Sahrens 
23475331Samw static int
23485331Samw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
23495331Samw     cred_t *cr)
23505331Samw {
23515331Samw 	if (*working_mode != ACE_WRITE_DATA)
23525331Samw 		return (EACCES);
23535331Samw 
23545331Samw 	return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
23555331Samw 	    check_privs, B_FALSE, cr));
23565331Samw }
2357789Sahrens 
2358789Sahrens /*
2359789Sahrens  * Determine whether Access should be granted/denied, invoking least
2360789Sahrens  * priv subsytem when a deny is determined.
2361789Sahrens  */
2362789Sahrens int
23635331Samw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
2364789Sahrens {
23655331Samw 	uint32_t	working_mode;
23665331Samw 	int		error;
23675331Samw 	int		is_attr;
23685331Samw 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
23695331Samw 	boolean_t 	check_privs;
23705331Samw 	znode_t		*xzp;
23715331Samw 	znode_t 	*check_zp = zp;
2372789Sahrens 
2373789Sahrens 	is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) &&
2374789Sahrens 	    (ZTOV(zp)->v_type == VDIR));
2375789Sahrens 
2376789Sahrens 	/*
2377789Sahrens 	 * If attribute then validate against base file
2378789Sahrens 	 */
2379789Sahrens 	if (is_attr) {
2380789Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
2381789Sahrens 		    zp->z_phys->zp_parent, &xzp)) != 0)	{
2382789Sahrens 			return (error);
2383789Sahrens 		}
23845331Samw 
2385789Sahrens 		check_zp = xzp;
23865331Samw 
2387789Sahrens 		/*
2388789Sahrens 		 * fixup mode to map to xattr perms
2389789Sahrens 		 */
2390789Sahrens 
2391789Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
2392789Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
2393789Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
2394789Sahrens 		}
2395789Sahrens 
2396789Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
2397789Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
2398789Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
2399789Sahrens 		}
2400789Sahrens 	}
2401789Sahrens 
24025331Samw 	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
24035331Samw 	    &check_privs, skipaclchk, cr)) == 0) {
24045331Samw 		if (is_attr)
24055331Samw 			VN_RELE(ZTOV(xzp));
24065331Samw 		return (0);
24075331Samw 	}
2408789Sahrens 
24095959Smarks 	if (error && !check_privs) {
2410789Sahrens 		if (is_attr)
2411789Sahrens 			VN_RELE(ZTOV(xzp));
2412789Sahrens 		return (error);
2413789Sahrens 	}
2414789Sahrens 
24155331Samw 	if (error && (flags & V_APPEND)) {
24165331Samw 		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
24175331Samw 	}
24185331Samw 
24195331Samw 	if (error && check_privs) {
24205331Samw 		uid_t		owner;
24215331Samw 		mode_t		checkmode = 0;
24225331Samw 
24235959Smarks 		owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr,
24245959Smarks 		    ZFS_OWNER);
24255331Samw 
24265331Samw 		/*
24275331Samw 		 * First check for implicit owner permission on
24285331Samw 		 * read_acl/read_attributes
24295331Samw 		 */
24305331Samw 
24315331Samw 		error = 0;
24325331Samw 		ASSERT(working_mode != 0);
24335331Samw 
24345331Samw 		if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
24355331Samw 		    owner == crgetuid(cr)))
24365331Samw 			working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
24375331Samw 
24385331Samw 		if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
24397624SMark.Shellenbaum@Sun.COM 		    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
24405331Samw 			checkmode |= VREAD;
24415331Samw 		if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
24427624SMark.Shellenbaum@Sun.COM 		    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
24435331Samw 			checkmode |= VWRITE;
24445331Samw 		if (working_mode & ACE_EXECUTE)
24455331Samw 			checkmode |= VEXEC;
24465331Samw 
24475331Samw 		if (checkmode)
24485331Samw 			error = secpolicy_vnode_access(cr, ZTOV(check_zp),
24495331Samw 			    owner, checkmode);
24505331Samw 
24515331Samw 		if (error == 0 && (working_mode & ACE_WRITE_OWNER))
24527624SMark.Shellenbaum@Sun.COM 			error = secpolicy_vnode_chown(cr, B_TRUE);
24535331Samw 		if (error == 0 && (working_mode & ACE_WRITE_ACL))
24545331Samw 			error = secpolicy_vnode_setdac(cr, owner);
24555331Samw 
24565331Samw 		if (error == 0 && (working_mode &
24575331Samw 		    (ACE_DELETE|ACE_DELETE_CHILD)))
24585331Samw 			error = secpolicy_vnode_remove(cr);
24595331Samw 
24607624SMark.Shellenbaum@Sun.COM 		if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
24617624SMark.Shellenbaum@Sun.COM 			error = secpolicy_vnode_chown(cr, B_FALSE);
24627624SMark.Shellenbaum@Sun.COM 		}
24635331Samw 		if (error == 0) {
24645331Samw 			/*
24655331Samw 			 * See if any bits other than those already checked
24665331Samw 			 * for are still present.  If so then return EACCES
24675331Samw 			 */
24685331Samw 			if (working_mode & ~(ZFS_CHECKED_MASKS)) {
24695331Samw 				error = EACCES;
24705331Samw 			}
24715331Samw 		}
2472789Sahrens 	}
2473789Sahrens 
2474789Sahrens 	if (is_attr)
2475789Sahrens 		VN_RELE(ZTOV(xzp));
2476789Sahrens 
2477789Sahrens 	return (error);
2478789Sahrens }
2479789Sahrens 
2480789Sahrens /*
24815331Samw  * Translate traditional unix VREAD/VWRITE/VEXEC mode into
24825331Samw  * native ACL format and call zfs_zaccess()
2483789Sahrens  */
2484789Sahrens int
24855331Samw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
2486789Sahrens {
24875331Samw 	return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
2488789Sahrens }
2489789Sahrens 
2490789Sahrens /*
24915331Samw  * Access function for secpolicy_vnode_setattr
2492789Sahrens  */
2493789Sahrens int
24945331Samw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
2495789Sahrens {
2496789Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
2497789Sahrens 
24985331Samw 	return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
2499789Sahrens }
2500789Sahrens 
25012604Smarks static int
25026257Smarks zfs_delete_final_check(znode_t *zp, znode_t *dzp,
25036257Smarks     mode_t missing_perms, cred_t *cr)
25042604Smarks {
25052604Smarks 	int error;
25065331Samw 	uid_t downer;
25075331Samw 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
25082604Smarks 
25095959Smarks 	downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER);
25105331Samw 
25116257Smarks 	error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms);
25122604Smarks 
25132604Smarks 	if (error == 0)
25142604Smarks 		error = zfs_sticky_remove_access(dzp, zp, cr);
25152604Smarks 
25162604Smarks 	return (error);
25172604Smarks }
25182604Smarks 
2519789Sahrens /*
2520789Sahrens  * Determine whether Access should be granted/deny, without
2521789Sahrens  * consulting least priv subsystem.
2522789Sahrens  *
2523789Sahrens  *
2524789Sahrens  * The following chart is the recommended NFSv4 enforcement for
2525789Sahrens  * ability to delete an object.
2526789Sahrens  *
2527789Sahrens  *      -------------------------------------------------------
2528789Sahrens  *      |   Parent Dir  |           Target Object Permissions |
2529789Sahrens  *      |  permissions  |                                     |
2530789Sahrens  *      -------------------------------------------------------
2531789Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
2532789Sahrens  *      |               |  Delete    |  Delete   | unspecified|
2533789Sahrens  *      -------------------------------------------------------
2534789Sahrens  *      |  ACL Allows   | Permit     | Permit    | Permit     |
2535789Sahrens  *      |  DELETE_CHILD |                                     |
2536789Sahrens  *      -------------------------------------------------------
2537789Sahrens  *      |  ACL Denies   | Permit     | Deny      | Deny       |
2538789Sahrens  *      |  DELETE_CHILD |            |           |            |
2539789Sahrens  *      -------------------------------------------------------
2540789Sahrens  *      | ACL specifies |            |           |            |
2541789Sahrens  *      | only allow    | Permit     | Permit    | Permit     |
2542789Sahrens  *      | write and     |            |           |            |
2543789Sahrens  *      | execute       |            |           |            |
2544789Sahrens  *      -------------------------------------------------------
2545789Sahrens  *      | ACL denies    |            |           |            |
2546789Sahrens  *      | write and     | Permit     | Deny      | Deny       |
2547789Sahrens  *      | execute       |            |           |            |
2548789Sahrens  *      -------------------------------------------------------
2549789Sahrens  *         ^
2550789Sahrens  *         |
2551789Sahrens  *         No search privilege, can't even look up file?
2552789Sahrens  *
2553789Sahrens  */
2554789Sahrens int
2555789Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
2556789Sahrens {
25575331Samw 	uint32_t dzp_working_mode = 0;
25585331Samw 	uint32_t zp_working_mode = 0;
2559789Sahrens 	int dzp_error, zp_error;
25606257Smarks 	mode_t missing_perms;
25615331Samw 	boolean_t dzpcheck_privs = B_TRUE;
25625331Samw 	boolean_t zpcheck_privs = B_TRUE;
2563789Sahrens 
2564789Sahrens 	/*
25656257Smarks 	 * We want specific DELETE permissions to
2566789Sahrens 	 * take precedence over WRITE/EXECUTE.  We don't
2567789Sahrens 	 * want an ACL such as this to mess us up.
25682604Smarks 	 * user:joe:write_data:deny,user:joe:delete:allow
2569789Sahrens 	 *
2570789Sahrens 	 * However, deny permissions may ultimately be overridden
2571789Sahrens 	 * by secpolicy_vnode_access().
25726257Smarks 	 *
25736257Smarks 	 * We will ask for all of the necessary permissions and then
25746257Smarks 	 * look at the working modes from the directory and target object
25756257Smarks 	 * to determine what was found.
2576789Sahrens 	 */
2577789Sahrens 
25785331Samw 	if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
25795331Samw 		return (EPERM);
25805331Samw 
25816257Smarks 	/*
25827163Smarks 	 * First row
25836257Smarks 	 * If the directory permissions allow the delete, we are done.
25846257Smarks 	 */
25857163Smarks 	if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
25866257Smarks 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
25876257Smarks 		return (0);
2588789Sahrens 
25896257Smarks 	/*
25906257Smarks 	 * If target object has delete permission then we are done
25916257Smarks 	 */
25926257Smarks 	if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
25936257Smarks 	    &zpcheck_privs, B_FALSE, cr)) == 0)
25946257Smarks 		return (0);
25956257Smarks 
25967163Smarks 	ASSERT(dzp_error && zp_error);
25977163Smarks 
25986257Smarks 	if (!dzpcheck_privs)
2599789Sahrens 		return (dzp_error);
26007163Smarks 	if (!zpcheck_privs)
26016257Smarks 		return (zp_error);
2602789Sahrens 
2603789Sahrens 	/*
2604789Sahrens 	 * Second row
26057163Smarks 	 *
26067163Smarks 	 * If directory returns EACCES then delete_child was denied
26077163Smarks 	 * due to deny delete_child.  In this case send the request through
26087163Smarks 	 * secpolicy_vnode_remove().  We don't use zfs_delete_final_check()
26097163Smarks 	 * since that *could* allow the delete based on write/execute permission
26107163Smarks 	 * and we want delete permissions to override write/execute.
2611789Sahrens 	 */
2612789Sahrens 
26132604Smarks 	if (dzp_error == EACCES)
26147163Smarks 		return (secpolicy_vnode_remove(cr));
26152604Smarks 
26162604Smarks 	/*
2617789Sahrens 	 * Third Row
26186257Smarks 	 * only need to see if we have write/execute on directory.
2619789Sahrens 	 */
2620789Sahrens 
26217163Smarks 	if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
26227163Smarks 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
26232604Smarks 		return (zfs_sticky_remove_access(dzp, zp, cr));
2624789Sahrens 
26257163Smarks 	if (!dzpcheck_privs)
26267163Smarks 		return (dzp_error);
26277163Smarks 
2628789Sahrens 	/*
26297163Smarks 	 * Fourth row
2630789Sahrens 	 */
2631789Sahrens 
26327163Smarks 	missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0;
26337163Smarks 	missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0;
26347163Smarks 
26357163Smarks 	ASSERT(missing_perms);
2636789Sahrens 
26376257Smarks 	return (zfs_delete_final_check(zp, dzp, missing_perms, cr));
26387163Smarks 
2639789Sahrens }
2640789Sahrens 
2641789Sahrens int
2642789Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
2643789Sahrens     znode_t *tzp, cred_t *cr)
2644789Sahrens {
2645789Sahrens 	int add_perm;
2646789Sahrens 	int error;
2647789Sahrens 
26485331Samw 	if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED)
26495331Samw 		return (EACCES);
26505331Samw 
2651789Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
2652789Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
2653789Sahrens 
2654789Sahrens 	/*
2655789Sahrens 	 * Rename permissions are combination of delete permission +
2656789Sahrens 	 * add file/subdir permission.
2657789Sahrens 	 */
2658789Sahrens 
2659789Sahrens 	/*
2660789Sahrens 	 * first make sure we do the delete portion.
2661789Sahrens 	 *
2662789Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
2663789Sahrens 	 */
2664789Sahrens 
2665789Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
2666789Sahrens 		return (error);
2667789Sahrens 
2668789Sahrens 	/*
2669789Sahrens 	 * If we have a tzp, see if we can delete it?
2670789Sahrens 	 */
2671789Sahrens 	if (tzp) {
2672789Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
2673789Sahrens 			return (error);
2674789Sahrens 	}
2675789Sahrens 
2676789Sahrens 	/*
2677789Sahrens 	 * Now check for add permissions
2678789Sahrens 	 */
26795331Samw 	error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
2680789Sahrens 
2681789Sahrens 	return (error);
2682789Sahrens }
2683