xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_acl.c (revision 13089:08bbd228b732)
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 /*
2212164SMark.Shellenbaum@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23789Sahrens  */
24789Sahrens 
25789Sahrens #include <sys/types.h>
26789Sahrens #include <sys/param.h>
27789Sahrens #include <sys/time.h>
28789Sahrens #include <sys/systm.h>
29789Sahrens #include <sys/sysmacros.h>
30789Sahrens #include <sys/resource.h>
31789Sahrens #include <sys/vfs.h>
32789Sahrens #include <sys/vnode.h>
335331Samw #include <sys/sid.h>
34789Sahrens #include <sys/file.h>
35789Sahrens #include <sys/stat.h>
36789Sahrens #include <sys/kmem.h>
37789Sahrens #include <sys/cmn_err.h>
38789Sahrens #include <sys/errno.h>
39789Sahrens #include <sys/unistd.h>
401576Smarks #include <sys/sdt.h>
41789Sahrens #include <sys/fs/zfs.h>
42789Sahrens #include <sys/mode.h>
43789Sahrens #include <sys/policy.h>
44789Sahrens #include <sys/zfs_znode.h>
455331Samw #include <sys/zfs_fuid.h>
46789Sahrens #include <sys/zfs_acl.h>
47789Sahrens #include <sys/zfs_dir.h>
48789Sahrens #include <sys/zfs_vfsops.h>
49789Sahrens #include <sys/dmu.h>
505331Samw #include <sys/dnode.h>
51789Sahrens #include <sys/zap.h>
5211935SMark.Shellenbaum@Sun.COM #include <sys/sa.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 
748952SMark.Shellenbaum@Sun.COM #define	WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
758952SMark.Shellenbaum@Sun.COM #define	WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
768952SMark.Shellenbaum@Sun.COM     ACE_DELETE|ACE_DELETE_CHILD)
778952SMark.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 
9610143STim.Haley@Sun.COM #define	ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH)
9710143STim.Haley@Sun.COM 
985331Samw static uint16_t
zfs_ace_v0_get_type(void * acep)995331Samw zfs_ace_v0_get_type(void *acep)
1005331Samw {
1015331Samw 	return (((zfs_oldace_t *)acep)->z_type);
1025331Samw }
1035331Samw 
1045331Samw static uint16_t
zfs_ace_v0_get_flags(void * acep)1055331Samw zfs_ace_v0_get_flags(void *acep)
1065331Samw {
1075331Samw 	return (((zfs_oldace_t *)acep)->z_flags);
1085331Samw }
1095331Samw 
1105331Samw static uint32_t
zfs_ace_v0_get_mask(void * acep)1115331Samw zfs_ace_v0_get_mask(void *acep)
1125331Samw {
1135331Samw 	return (((zfs_oldace_t *)acep)->z_access_mask);
1145331Samw }
1155331Samw 
1165331Samw static uint64_t
zfs_ace_v0_get_who(void * acep)1175331Samw zfs_ace_v0_get_who(void *acep)
1185331Samw {
1195331Samw 	return (((zfs_oldace_t *)acep)->z_fuid);
1205331Samw }
1215331Samw 
1225331Samw static void
zfs_ace_v0_set_type(void * acep,uint16_t type)1235331Samw zfs_ace_v0_set_type(void *acep, uint16_t type)
1245331Samw {
1255331Samw 	((zfs_oldace_t *)acep)->z_type = type;
1265331Samw }
1275331Samw 
1285331Samw static void
zfs_ace_v0_set_flags(void * acep,uint16_t flags)1295331Samw zfs_ace_v0_set_flags(void *acep, uint16_t flags)
1305331Samw {
1315331Samw 	((zfs_oldace_t *)acep)->z_flags = flags;
1325331Samw }
1335331Samw 
1345331Samw static void
zfs_ace_v0_set_mask(void * acep,uint32_t mask)1355331Samw zfs_ace_v0_set_mask(void *acep, uint32_t mask)
1365331Samw {
1375331Samw 	((zfs_oldace_t *)acep)->z_access_mask = mask;
1385331Samw }
1395331Samw 
1405331Samw static void
zfs_ace_v0_set_who(void * acep,uint64_t who)1415331Samw zfs_ace_v0_set_who(void *acep, uint64_t who)
1425331Samw {
1435331Samw 	((zfs_oldace_t *)acep)->z_fuid = who;
1445331Samw }
1455331Samw 
1465331Samw /*ARGSUSED*/
1475331Samw static size_t
zfs_ace_v0_size(void * acep)1485331Samw zfs_ace_v0_size(void *acep)
1495331Samw {
1505331Samw 	return (sizeof (zfs_oldace_t));
1515331Samw }
1525331Samw 
1535331Samw static size_t
zfs_ace_v0_abstract_size(void)1545331Samw zfs_ace_v0_abstract_size(void)
1555331Samw {
1565331Samw 	return (sizeof (zfs_oldace_t));
1575331Samw }
1585331Samw 
1595331Samw static int
zfs_ace_v0_mask_off(void)1605331Samw zfs_ace_v0_mask_off(void)
1615331Samw {
1625331Samw 	return (offsetof(zfs_oldace_t, z_access_mask));
1635331Samw }
1645331Samw 
1655331Samw /*ARGSUSED*/
1665331Samw static int
zfs_ace_v0_data(void * acep,void ** datap)1675331Samw zfs_ace_v0_data(void *acep, void **datap)
1685331Samw {
1695331Samw 	*datap = NULL;
1705331Samw 	return (0);
1715331Samw }
1725331Samw 
1735331Samw static acl_ops_t zfs_acl_v0_ops = {
1745331Samw 	zfs_ace_v0_get_mask,
1755331Samw 	zfs_ace_v0_set_mask,
1765331Samw 	zfs_ace_v0_get_flags,
1775331Samw 	zfs_ace_v0_set_flags,
1785331Samw 	zfs_ace_v0_get_type,
1795331Samw 	zfs_ace_v0_set_type,
1805331Samw 	zfs_ace_v0_get_who,
1815331Samw 	zfs_ace_v0_set_who,
1825331Samw 	zfs_ace_v0_size,
1835331Samw 	zfs_ace_v0_abstract_size,
1845331Samw 	zfs_ace_v0_mask_off,
1855331Samw 	zfs_ace_v0_data
1865331Samw };
1875331Samw 
1885331Samw static uint16_t
zfs_ace_fuid_get_type(void * acep)1895331Samw zfs_ace_fuid_get_type(void *acep)
1905331Samw {
1915331Samw 	return (((zfs_ace_hdr_t *)acep)->z_type);
1925331Samw }
1935331Samw 
1945331Samw static uint16_t
zfs_ace_fuid_get_flags(void * acep)1955331Samw zfs_ace_fuid_get_flags(void *acep)
1965331Samw {
1975331Samw 	return (((zfs_ace_hdr_t *)acep)->z_flags);
1985331Samw }
1995331Samw 
2005331Samw static uint32_t
zfs_ace_fuid_get_mask(void * acep)2015331Samw zfs_ace_fuid_get_mask(void *acep)
2025331Samw {
2035331Samw 	return (((zfs_ace_hdr_t *)acep)->z_access_mask);
2045331Samw }
2055331Samw 
2065331Samw static uint64_t
zfs_ace_fuid_get_who(void * args)2075331Samw zfs_ace_fuid_get_who(void *args)
2085331Samw {
2095331Samw 	uint16_t entry_type;
2105331Samw 	zfs_ace_t *acep = args;
2115331Samw 
2125331Samw 	entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
213789Sahrens 
2145331Samw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
2155331Samw 	    entry_type == ACE_EVERYONE)
2165331Samw 		return (-1);
2175331Samw 	return (((zfs_ace_t *)acep)->z_fuid);
2185331Samw }
2195331Samw 
2205331Samw static void
zfs_ace_fuid_set_type(void * acep,uint16_t type)2215331Samw zfs_ace_fuid_set_type(void *acep, uint16_t type)
2225331Samw {
2235331Samw 	((zfs_ace_hdr_t *)acep)->z_type = type;
2245331Samw }
2255331Samw 
2265331Samw static void
zfs_ace_fuid_set_flags(void * acep,uint16_t flags)2275331Samw zfs_ace_fuid_set_flags(void *acep, uint16_t flags)
2285331Samw {
2295331Samw 	((zfs_ace_hdr_t *)acep)->z_flags = flags;
2305331Samw }
2315331Samw 
2325331Samw static void
zfs_ace_fuid_set_mask(void * acep,uint32_t mask)2335331Samw zfs_ace_fuid_set_mask(void *acep, uint32_t mask)
2345331Samw {
2355331Samw 	((zfs_ace_hdr_t *)acep)->z_access_mask = mask;
2365331Samw }
2375331Samw 
2385331Samw static void
zfs_ace_fuid_set_who(void * arg,uint64_t who)2395331Samw zfs_ace_fuid_set_who(void *arg, uint64_t who)
2405331Samw {
2415331Samw 	zfs_ace_t *acep = arg;
2425331Samw 
2435331Samw 	uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
2445331Samw 
2455331Samw 	if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
2465331Samw 	    entry_type == ACE_EVERYONE)
2475331Samw 		return;
2485331Samw 	acep->z_fuid = who;
2495331Samw }
2505331Samw 
2515331Samw static size_t
zfs_ace_fuid_size(void * acep)2525331Samw zfs_ace_fuid_size(void *acep)
2535331Samw {
2545331Samw 	zfs_ace_hdr_t *zacep = acep;
2555331Samw 	uint16_t entry_type;
2565331Samw 
2575331Samw 	switch (zacep->z_type) {
2585331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
2595331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
2605331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
2615331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
2625331Samw 		return (sizeof (zfs_object_ace_t));
2635331Samw 	case ALLOW:
2645331Samw 	case DENY:
2655331Samw 		entry_type =
2665331Samw 		    (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS);
2675331Samw 		if (entry_type == ACE_OWNER ||
2687328SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP ||
2695331Samw 		    entry_type == ACE_EVERYONE)
2705331Samw 			return (sizeof (zfs_ace_hdr_t));
2715331Samw 		/*FALLTHROUGH*/
2725331Samw 	default:
2735331Samw 		return (sizeof (zfs_ace_t));
2745331Samw 	}
2755331Samw }
2765331Samw 
2775331Samw static size_t
zfs_ace_fuid_abstract_size(void)2785331Samw zfs_ace_fuid_abstract_size(void)
2795331Samw {
2805331Samw 	return (sizeof (zfs_ace_hdr_t));
2815331Samw }
2825331Samw 
2835331Samw static int
zfs_ace_fuid_mask_off(void)2845331Samw zfs_ace_fuid_mask_off(void)
2855331Samw {
2865331Samw 	return (offsetof(zfs_ace_hdr_t, z_access_mask));
2875331Samw }
2885331Samw 
2895331Samw static int
zfs_ace_fuid_data(void * acep,void ** datap)2905331Samw zfs_ace_fuid_data(void *acep, void **datap)
2915331Samw {
2925331Samw 	zfs_ace_t *zacep = acep;
2935331Samw 	zfs_object_ace_t *zobjp;
2945331Samw 
2955331Samw 	switch (zacep->z_hdr.z_type) {
2965331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
2975331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
2985331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
2995331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
3005331Samw 		zobjp = acep;
3015331Samw 		*datap = (caddr_t)zobjp + sizeof (zfs_ace_t);
3025331Samw 		return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
3035331Samw 	default:
3045331Samw 		*datap = NULL;
3055331Samw 		return (0);
3065331Samw 	}
3075331Samw }
3085331Samw 
3095331Samw static acl_ops_t zfs_acl_fuid_ops = {
3105331Samw 	zfs_ace_fuid_get_mask,
3115331Samw 	zfs_ace_fuid_set_mask,
3125331Samw 	zfs_ace_fuid_get_flags,
3135331Samw 	zfs_ace_fuid_set_flags,
3145331Samw 	zfs_ace_fuid_get_type,
3155331Samw 	zfs_ace_fuid_set_type,
3165331Samw 	zfs_ace_fuid_get_who,
3175331Samw 	zfs_ace_fuid_set_who,
3185331Samw 	zfs_ace_fuid_size,
3195331Samw 	zfs_ace_fuid_abstract_size,
3205331Samw 	zfs_ace_fuid_mask_off,
3215331Samw 	zfs_ace_fuid_data
3225331Samw };
3235331Samw 
32411935SMark.Shellenbaum@Sun.COM /*
32511935SMark.Shellenbaum@Sun.COM  * The following three functions are provided for compatibility with
32611935SMark.Shellenbaum@Sun.COM  * older ZPL version in order to determine if the file use to have
32711935SMark.Shellenbaum@Sun.COM  * an external ACL and what version of ACL previously existed on the
32811935SMark.Shellenbaum@Sun.COM  * file.  Would really be nice to not need this, sigh.
32911935SMark.Shellenbaum@Sun.COM  */
33011935SMark.Shellenbaum@Sun.COM uint64_t
zfs_external_acl(znode_t * zp)33111935SMark.Shellenbaum@Sun.COM zfs_external_acl(znode_t *zp)
33211935SMark.Shellenbaum@Sun.COM {
33311935SMark.Shellenbaum@Sun.COM 	zfs_acl_phys_t acl_phys;
33412620SMark.Shellenbaum@Oracle.COM 	int error;
33511935SMark.Shellenbaum@Sun.COM 
33611935SMark.Shellenbaum@Sun.COM 	if (zp->z_is_sa)
33711935SMark.Shellenbaum@Sun.COM 		return (0);
33811935SMark.Shellenbaum@Sun.COM 
33912620SMark.Shellenbaum@Oracle.COM 	/*
34012620SMark.Shellenbaum@Oracle.COM 	 * Need to deal with a potential
34112620SMark.Shellenbaum@Oracle.COM 	 * race where zfs_sa_upgrade could cause
34212620SMark.Shellenbaum@Oracle.COM 	 * z_isa_sa to change.
34312620SMark.Shellenbaum@Oracle.COM 	 *
34412620SMark.Shellenbaum@Oracle.COM 	 * If the lookup fails then the state of z_is_sa should have
34512620SMark.Shellenbaum@Oracle.COM 	 * changed.
34612620SMark.Shellenbaum@Oracle.COM 	 */
34712620SMark.Shellenbaum@Oracle.COM 
34812620SMark.Shellenbaum@Oracle.COM 	if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
34912620SMark.Shellenbaum@Oracle.COM 	    &acl_phys, sizeof (acl_phys))) == 0)
35012620SMark.Shellenbaum@Oracle.COM 		return (acl_phys.z_acl_extern_obj);
35112620SMark.Shellenbaum@Oracle.COM 	else {
35212620SMark.Shellenbaum@Oracle.COM 		/*
35312620SMark.Shellenbaum@Oracle.COM 		 * after upgrade the SA_ZPL_ZNODE_ACL should have been
35412620SMark.Shellenbaum@Oracle.COM 		 * removed
35512620SMark.Shellenbaum@Oracle.COM 		 */
35612620SMark.Shellenbaum@Oracle.COM 		VERIFY(zp->z_is_sa && error == ENOENT);
35712620SMark.Shellenbaum@Oracle.COM 		return (0);
35812620SMark.Shellenbaum@Oracle.COM 	}
35911935SMark.Shellenbaum@Sun.COM }
36011935SMark.Shellenbaum@Sun.COM 
36111935SMark.Shellenbaum@Sun.COM /*
36211935SMark.Shellenbaum@Sun.COM  * Determine size of ACL in bytes
36311935SMark.Shellenbaum@Sun.COM  *
36411935SMark.Shellenbaum@Sun.COM  * This is more complicated than it should be since we have to deal
36511935SMark.Shellenbaum@Sun.COM  * with old external ACLs.
36611935SMark.Shellenbaum@Sun.COM  */
36711935SMark.Shellenbaum@Sun.COM static int
zfs_acl_znode_info(znode_t * zp,int * aclsize,int * aclcount,zfs_acl_phys_t * aclphys)36811935SMark.Shellenbaum@Sun.COM zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
36911935SMark.Shellenbaum@Sun.COM     zfs_acl_phys_t *aclphys)
37011935SMark.Shellenbaum@Sun.COM {
37111935SMark.Shellenbaum@Sun.COM 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
37211935SMark.Shellenbaum@Sun.COM 	uint64_t acl_count;
37311935SMark.Shellenbaum@Sun.COM 	int size;
37411935SMark.Shellenbaum@Sun.COM 	int error;
37511935SMark.Shellenbaum@Sun.COM 
37612620SMark.Shellenbaum@Oracle.COM 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
37711935SMark.Shellenbaum@Sun.COM 	if (zp->z_is_sa) {
37811935SMark.Shellenbaum@Sun.COM 		if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs),
37911935SMark.Shellenbaum@Sun.COM 		    &size)) != 0)
38011935SMark.Shellenbaum@Sun.COM 			return (error);
38111935SMark.Shellenbaum@Sun.COM 		*aclsize = size;
38211935SMark.Shellenbaum@Sun.COM 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs),
38311935SMark.Shellenbaum@Sun.COM 		    &acl_count, sizeof (acl_count))) != 0)
38411935SMark.Shellenbaum@Sun.COM 			return (error);
38511935SMark.Shellenbaum@Sun.COM 		*aclcount = acl_count;
38611935SMark.Shellenbaum@Sun.COM 	} else {
38711935SMark.Shellenbaum@Sun.COM 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
38811935SMark.Shellenbaum@Sun.COM 		    aclphys, sizeof (*aclphys))) != 0)
38911935SMark.Shellenbaum@Sun.COM 			return (error);
39011935SMark.Shellenbaum@Sun.COM 
39111935SMark.Shellenbaum@Sun.COM 		if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) {
39211935SMark.Shellenbaum@Sun.COM 			*aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size);
39311935SMark.Shellenbaum@Sun.COM 			*aclcount = aclphys->z_acl_size;
39411935SMark.Shellenbaum@Sun.COM 		} else {
39511935SMark.Shellenbaum@Sun.COM 			*aclsize = aclphys->z_acl_size;
39611935SMark.Shellenbaum@Sun.COM 			*aclcount = aclphys->z_acl_count;
39711935SMark.Shellenbaum@Sun.COM 		}
39811935SMark.Shellenbaum@Sun.COM 	}
39911935SMark.Shellenbaum@Sun.COM 	return (0);
40011935SMark.Shellenbaum@Sun.COM }
40111935SMark.Shellenbaum@Sun.COM 
40211935SMark.Shellenbaum@Sun.COM int
zfs_znode_acl_version(znode_t * zp)40311935SMark.Shellenbaum@Sun.COM zfs_znode_acl_version(znode_t *zp)
40411935SMark.Shellenbaum@Sun.COM {
40511935SMark.Shellenbaum@Sun.COM 	zfs_acl_phys_t acl_phys;
40611935SMark.Shellenbaum@Sun.COM 
40712620SMark.Shellenbaum@Oracle.COM 	if (zp->z_is_sa)
40811935SMark.Shellenbaum@Sun.COM 		return (ZFS_ACL_VERSION_FUID);
40912620SMark.Shellenbaum@Oracle.COM 	else {
41012620SMark.Shellenbaum@Oracle.COM 		int error;
41112620SMark.Shellenbaum@Oracle.COM 
41212620SMark.Shellenbaum@Oracle.COM 		/*
41312620SMark.Shellenbaum@Oracle.COM 		 * Need to deal with a potential
41412620SMark.Shellenbaum@Oracle.COM 		 * race where zfs_sa_upgrade could cause
41512620SMark.Shellenbaum@Oracle.COM 		 * z_isa_sa to change.
41612620SMark.Shellenbaum@Oracle.COM 		 *
41712620SMark.Shellenbaum@Oracle.COM 		 * If the lookup fails then the state of z_is_sa should have
41812620SMark.Shellenbaum@Oracle.COM 		 * changed.
41912620SMark.Shellenbaum@Oracle.COM 		 */
42012620SMark.Shellenbaum@Oracle.COM 		if ((error = sa_lookup(zp->z_sa_hdl,
42111935SMark.Shellenbaum@Sun.COM 		    SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
42212620SMark.Shellenbaum@Oracle.COM 		    &acl_phys, sizeof (acl_phys))) == 0)
42312620SMark.Shellenbaum@Oracle.COM 			return (acl_phys.z_acl_version);
42412620SMark.Shellenbaum@Oracle.COM 		else {
42512620SMark.Shellenbaum@Oracle.COM 			/*
42612620SMark.Shellenbaum@Oracle.COM 			 * After upgrade SA_ZPL_ZNODE_ACL should have
42712620SMark.Shellenbaum@Oracle.COM 			 * been removed.
42812620SMark.Shellenbaum@Oracle.COM 			 */
42912620SMark.Shellenbaum@Oracle.COM 			VERIFY(zp->z_is_sa && error == ENOENT);
43012620SMark.Shellenbaum@Oracle.COM 			return (ZFS_ACL_VERSION_FUID);
43112620SMark.Shellenbaum@Oracle.COM 		}
43211935SMark.Shellenbaum@Sun.COM 	}
43311935SMark.Shellenbaum@Sun.COM }
43411935SMark.Shellenbaum@Sun.COM 
4355331Samw static int
zfs_acl_version(int version)4365331Samw zfs_acl_version(int version)
4375331Samw {
4385331Samw 	if (version < ZPL_VERSION_FUID)
4395331Samw 		return (ZFS_ACL_VERSION_INITIAL);
4405331Samw 	else
4415331Samw 		return (ZFS_ACL_VERSION_FUID);
4425331Samw }
4435331Samw 
4445331Samw static int
zfs_acl_version_zp(znode_t * zp)4455331Samw zfs_acl_version_zp(znode_t *zp)
4465331Samw {
4475331Samw 	return (zfs_acl_version(zp->z_zfsvfs->z_version));
4485331Samw }
449789Sahrens 
45011935SMark.Shellenbaum@Sun.COM zfs_acl_t *
zfs_acl_alloc(int vers)4515331Samw zfs_acl_alloc(int vers)
452789Sahrens {
453789Sahrens 	zfs_acl_t *aclp;
454789Sahrens 
455789Sahrens 	aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP);
4565331Samw 	list_create(&aclp->z_acl, sizeof (zfs_acl_node_t),
4575331Samw 	    offsetof(zfs_acl_node_t, z_next));
4585331Samw 	aclp->z_version = vers;
4595331Samw 	if (vers == ZFS_ACL_VERSION_FUID)
4605331Samw 		aclp->z_ops = zfs_acl_fuid_ops;
4615331Samw 	else
4625331Samw 		aclp->z_ops = zfs_acl_v0_ops;
4635331Samw 	return (aclp);
4645331Samw }
4655331Samw 
46611935SMark.Shellenbaum@Sun.COM zfs_acl_node_t *
zfs_acl_node_alloc(size_t bytes)4675331Samw zfs_acl_node_alloc(size_t bytes)
4685331Samw {
4695331Samw 	zfs_acl_node_t *aclnode;
4705331Samw 
4715331Samw 	aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
4725331Samw 	if (bytes) {
4735331Samw 		aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP);
4745331Samw 		aclnode->z_allocdata = aclnode->z_acldata;
4755331Samw 		aclnode->z_allocsize = bytes;
4765331Samw 		aclnode->z_size = bytes;
477789Sahrens 	}
4785331Samw 
4795331Samw 	return (aclnode);
4805331Samw }
4815331Samw 
4825331Samw static void
zfs_acl_node_free(zfs_acl_node_t * aclnode)4835331Samw zfs_acl_node_free(zfs_acl_node_t *aclnode)
4845331Samw {
4855331Samw 	if (aclnode->z_allocsize)
4865331Samw 		kmem_free(aclnode->z_allocdata, aclnode->z_allocsize);
4875331Samw 	kmem_free(aclnode, sizeof (zfs_acl_node_t));
488789Sahrens }
489789Sahrens 
4905489Smarks static void
zfs_acl_release_nodes(zfs_acl_t * aclp)4915489Smarks zfs_acl_release_nodes(zfs_acl_t *aclp)
492789Sahrens {
4935331Samw 	zfs_acl_node_t *aclnode;
4945331Samw 
4955331Samw 	while (aclnode = list_head(&aclp->z_acl)) {
4965331Samw 		list_remove(&aclp->z_acl, aclnode);
4975331Samw 		zfs_acl_node_free(aclnode);
498789Sahrens 	}
4995489Smarks 	aclp->z_acl_count = 0;
5005489Smarks 	aclp->z_acl_bytes = 0;
5015489Smarks }
5025331Samw 
5035489Smarks void
zfs_acl_free(zfs_acl_t * aclp)5045489Smarks zfs_acl_free(zfs_acl_t *aclp)
5055489Smarks {
5065489Smarks 	zfs_acl_release_nodes(aclp);
5075331Samw 	list_destroy(&aclp->z_acl);
508789Sahrens 	kmem_free(aclp, sizeof (zfs_acl_t));
509789Sahrens }
510789Sahrens 
5115331Samw static boolean_t
zfs_acl_valid_ace_type(uint_t type,uint_t flags)5127559SMark.Shellenbaum@Sun.COM zfs_acl_valid_ace_type(uint_t type, uint_t flags)
5137559SMark.Shellenbaum@Sun.COM {
5147559SMark.Shellenbaum@Sun.COM 	uint16_t entry_type;
5157559SMark.Shellenbaum@Sun.COM 
5167559SMark.Shellenbaum@Sun.COM 	switch (type) {
5177559SMark.Shellenbaum@Sun.COM 	case ALLOW:
5187559SMark.Shellenbaum@Sun.COM 	case DENY:
5197559SMark.Shellenbaum@Sun.COM 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
5207559SMark.Shellenbaum@Sun.COM 	case ACE_SYSTEM_ALARM_ACE_TYPE:
5217559SMark.Shellenbaum@Sun.COM 		entry_type = flags & ACE_TYPE_FLAGS;
5227559SMark.Shellenbaum@Sun.COM 		return (entry_type == ACE_OWNER ||
5237559SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP ||
5247559SMark.Shellenbaum@Sun.COM 		    entry_type == ACE_EVERYONE || entry_type == 0 ||
5257559SMark.Shellenbaum@Sun.COM 		    entry_type == ACE_IDENTIFIER_GROUP);
5267559SMark.Shellenbaum@Sun.COM 	default:
5277559SMark.Shellenbaum@Sun.COM 		if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
5287559SMark.Shellenbaum@Sun.COM 			return (B_TRUE);
5297559SMark.Shellenbaum@Sun.COM 	}
5307559SMark.Shellenbaum@Sun.COM 	return (B_FALSE);
5317559SMark.Shellenbaum@Sun.COM }
5327559SMark.Shellenbaum@Sun.COM 
5337559SMark.Shellenbaum@Sun.COM static boolean_t
zfs_ace_valid(vtype_t obj_type,zfs_acl_t * aclp,uint16_t type,uint16_t iflags)5345331Samw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
535789Sahrens {
5365331Samw 	/*
5375331Samw 	 * first check type of entry
5385331Samw 	 */
5395331Samw 
5407559SMark.Shellenbaum@Sun.COM 	if (!zfs_acl_valid_ace_type(type, iflags))
5415331Samw 		return (B_FALSE);
5425331Samw 
5435331Samw 	switch (type) {
5445331Samw 	case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
5455331Samw 	case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
5465331Samw 	case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
5475331Samw 	case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
5485331Samw 		if (aclp->z_version < ZFS_ACL_VERSION_FUID)
5495331Samw 			return (B_FALSE);
5505331Samw 		aclp->z_hints |= ZFS_ACL_OBJ_ACE;
5515331Samw 	}
552789Sahrens 
5537559SMark.Shellenbaum@Sun.COM 	/*
5547559SMark.Shellenbaum@Sun.COM 	 * next check inheritance level flags
5557559SMark.Shellenbaum@Sun.COM 	 */
5567559SMark.Shellenbaum@Sun.COM 
5577057Smarks 	if (obj_type == VDIR &&
5587057Smarks 	    (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
5595331Samw 		aclp->z_hints |= ZFS_INHERIT_ACE;
5605331Samw 
5615331Samw 	if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
5625331Samw 		if ((iflags & (ACE_FILE_INHERIT_ACE|
5635331Samw 		    ACE_DIRECTORY_INHERIT_ACE)) == 0) {
5645331Samw 			return (B_FALSE);
5655331Samw 		}
5665331Samw 	}
5675331Samw 
5685331Samw 	return (B_TRUE);
5695331Samw }
5705331Samw 
5715331Samw static void *
zfs_acl_next_ace(zfs_acl_t * aclp,void * start,uint64_t * who,uint32_t * access_mask,uint16_t * iflags,uint16_t * type)5725331Samw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
5735331Samw     uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
5745331Samw {
5755331Samw 	zfs_acl_node_t *aclnode;
5765331Samw 
57711935SMark.Shellenbaum@Sun.COM 	ASSERT(aclp);
57811935SMark.Shellenbaum@Sun.COM 
5795331Samw 	if (start == NULL) {
5805331Samw 		aclnode = list_head(&aclp->z_acl);
5815331Samw 		if (aclnode == NULL)
5825331Samw 			return (NULL);
5835331Samw 
5845331Samw 		aclp->z_next_ace = aclnode->z_acldata;
5855331Samw 		aclp->z_curr_node = aclnode;
5865331Samw 		aclnode->z_ace_idx = 0;
5875331Samw 	}
5885331Samw 
5895331Samw 	aclnode = aclp->z_curr_node;
5905331Samw 
5915331Samw 	if (aclnode == NULL)
5925331Samw 		return (NULL);
5935331Samw 
5945331Samw 	if (aclnode->z_ace_idx >= aclnode->z_ace_count) {
5955331Samw 		aclnode = list_next(&aclp->z_acl, aclnode);
5965331Samw 		if (aclnode == NULL)
5975331Samw 			return (NULL);
5985331Samw 		else {
5995331Samw 			aclp->z_curr_node = aclnode;
6005331Samw 			aclnode->z_ace_idx = 0;
6015331Samw 			aclp->z_next_ace = aclnode->z_acldata;
6025331Samw 		}
6035331Samw 	}
6045331Samw 
6055331Samw 	if (aclnode->z_ace_idx < aclnode->z_ace_count) {
6065331Samw 		void *acep = aclp->z_next_ace;
6077559SMark.Shellenbaum@Sun.COM 		size_t ace_size;
6087559SMark.Shellenbaum@Sun.COM 
6097559SMark.Shellenbaum@Sun.COM 		/*
6107559SMark.Shellenbaum@Sun.COM 		 * Make sure we don't overstep our bounds
6117559SMark.Shellenbaum@Sun.COM 		 */
6127559SMark.Shellenbaum@Sun.COM 		ace_size = aclp->z_ops.ace_size(acep);
6137559SMark.Shellenbaum@Sun.COM 
6147559SMark.Shellenbaum@Sun.COM 		if (((caddr_t)acep + ace_size) >
6157559SMark.Shellenbaum@Sun.COM 		    ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
6167559SMark.Shellenbaum@Sun.COM 			return (NULL);
6177559SMark.Shellenbaum@Sun.COM 		}
6187559SMark.Shellenbaum@Sun.COM 
6195331Samw 		*iflags = aclp->z_ops.ace_flags_get(acep);
6205331Samw 		*type = aclp->z_ops.ace_type_get(acep);
6215331Samw 		*access_mask = aclp->z_ops.ace_mask_get(acep);
6225331Samw 		*who = aclp->z_ops.ace_who_get(acep);
6237559SMark.Shellenbaum@Sun.COM 		aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size;
6245331Samw 		aclnode->z_ace_idx++;
62511935SMark.Shellenbaum@Sun.COM 
6265331Samw 		return ((void *)acep);
6275331Samw 	}
6285331Samw 	return (NULL);
6295331Samw }
6305331Samw 
6315331Samw /*ARGSUSED*/
6325331Samw static uint64_t
zfs_ace_walk(void * datap,uint64_t cookie,int aclcnt,uint16_t * flags,uint16_t * type,uint32_t * mask)6335331Samw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
6345331Samw     uint16_t *flags, uint16_t *type, uint32_t *mask)
6355331Samw {
6365331Samw 	zfs_acl_t *aclp = datap;
6375331Samw 	zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
6385331Samw 	uint64_t who;
6395331Samw 
6405331Samw 	acep = zfs_acl_next_ace(aclp, acep, &who, mask,
6415331Samw 	    flags, type);
6425331Samw 	return ((uint64_t)(uintptr_t)acep);
6435331Samw }
6445331Samw 
6455331Samw static zfs_acl_node_t *
zfs_acl_curr_node(zfs_acl_t * aclp)6465331Samw zfs_acl_curr_node(zfs_acl_t *aclp)
6475331Samw {
6485331Samw 	ASSERT(aclp->z_curr_node);
6495331Samw 	return (aclp->z_curr_node);
6505331Samw }
6515331Samw 
6525331Samw /*
6535331Samw  * Copy ACE to internal ZFS format.
6545331Samw  * While processing the ACL each ACE will be validated for correctness.
6555331Samw  * ACE FUIDs will be created later.
6565331Samw  */
6575331Samw int
zfs_copy_ace_2_fuid(zfsvfs_t * zfsvfs,vtype_t obj_type,zfs_acl_t * aclp,void * datap,zfs_ace_t * z_acl,uint64_t aclcnt,size_t * size,zfs_fuid_info_t ** fuidp,cred_t * cr)6589179SMark.Shellenbaum@Sun.COM zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp,
65911935SMark.Shellenbaum@Sun.COM     void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size,
6609179SMark.Shellenbaum@Sun.COM     zfs_fuid_info_t **fuidp, cred_t *cr)
6615331Samw {
6625331Samw 	int i;
6635331Samw 	uint16_t entry_type;
6645331Samw 	zfs_ace_t *aceptr = z_acl;
6655331Samw 	ace_t *acep = datap;
6665331Samw 	zfs_object_ace_t *zobjacep;
6675331Samw 	ace_object_t *aceobjp;
6685331Samw 
6695331Samw 	for (i = 0; i != aclcnt; i++) {
6705331Samw 		aceptr->z_hdr.z_access_mask = acep->a_access_mask;
6715331Samw 		aceptr->z_hdr.z_flags = acep->a_flags;
6725331Samw 		aceptr->z_hdr.z_type = acep->a_type;
6735331Samw 		entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS;
6745331Samw 		if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
6755824Smarks 		    entry_type != ACE_EVERYONE) {
6769179SMark.Shellenbaum@Sun.COM 			aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who,
6779179SMark.Shellenbaum@Sun.COM 			    cr, (entry_type == 0) ?
6789179SMark.Shellenbaum@Sun.COM 			    ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp);
6795824Smarks 		}
6805824Smarks 
6815331Samw 		/*
6825331Samw 		 * Make sure ACE is valid
6835331Samw 		 */
6845331Samw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type,
6855331Samw 		    aceptr->z_hdr.z_flags) != B_TRUE)
6865331Samw 			return (EINVAL);
6875331Samw 
6885331Samw 		switch (acep->a_type) {
6895331Samw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
6905331Samw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
6915331Samw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
6925331Samw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
6935331Samw 			zobjacep = (zfs_object_ace_t *)aceptr;
6945331Samw 			aceobjp = (ace_object_t *)acep;
6955331Samw 
6965331Samw 			bcopy(aceobjp->a_obj_type, zobjacep->z_object_type,
6975331Samw 			    sizeof (aceobjp->a_obj_type));
6985331Samw 			bcopy(aceobjp->a_inherit_obj_type,
6995331Samw 			    zobjacep->z_inherit_type,
7005331Samw 			    sizeof (aceobjp->a_inherit_obj_type));
7015331Samw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
7025331Samw 			break;
7035331Samw 		default:
7045331Samw 			acep = (ace_t *)((caddr_t)acep + sizeof (ace_t));
7055331Samw 		}
7065331Samw 
7075331Samw 		aceptr = (zfs_ace_t *)((caddr_t)aceptr +
7085331Samw 		    aclp->z_ops.ace_size(aceptr));
7095331Samw 	}
7105331Samw 
7115331Samw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
712789Sahrens 
7135331Samw 	return (0);
7145331Samw }
7155331Samw 
7165331Samw /*
7175331Samw  * Copy ZFS ACEs to fixed size ace_t layout
7185331Samw  */
7195331Samw static void
zfs_copy_fuid_2_ace(zfsvfs_t * zfsvfs,zfs_acl_t * aclp,cred_t * cr,void * datap,int filter)7205771Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
7215771Sjp151216     void *datap, int filter)
7225331Samw {
7235331Samw 	uint64_t who;
7245331Samw 	uint32_t access_mask;
7255331Samw 	uint16_t iflags, type;
7265331Samw 	zfs_ace_hdr_t *zacep = NULL;
7275331Samw 	ace_t *acep = datap;
7285331Samw 	ace_object_t *objacep;
7295331Samw 	zfs_object_ace_t *zobjacep;
7305331Samw 	size_t ace_size;
7315331Samw 	uint16_t entry_type;
7325331Samw 
7335331Samw 	while (zacep = zfs_acl_next_ace(aclp, zacep,
7345331Samw 	    &who, &access_mask, &iflags, &type)) {
7355331Samw 
7365331Samw 		switch (type) {
7375331Samw 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
7385331Samw 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
7395331Samw 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
7405331Samw 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
7415331Samw 			if (filter) {
7425331Samw 				continue;
7435331Samw 			}
7445331Samw 			zobjacep = (zfs_object_ace_t *)zacep;
7455331Samw 			objacep = (ace_object_t *)acep;
7465331Samw 			bcopy(zobjacep->z_object_type,
7475331Samw 			    objacep->a_obj_type,
7485331Samw 			    sizeof (zobjacep->z_object_type));
7495331Samw 			bcopy(zobjacep->z_inherit_type,
7505331Samw 			    objacep->a_inherit_obj_type,
7515331Samw 			    sizeof (zobjacep->z_inherit_type));
7525331Samw 			ace_size = sizeof (ace_object_t);
7535331Samw 			break;
7545331Samw 		default:
7555331Samw 			ace_size = sizeof (ace_t);
7565331Samw 			break;
7575331Samw 		}
7585331Samw 
7595331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
7605331Samw 		if ((entry_type != ACE_OWNER &&
7617328SMark.Shellenbaum@Sun.COM 		    entry_type != OWNING_GROUP &&
7625959Smarks 		    entry_type != ACE_EVERYONE)) {
7635959Smarks 			acep->a_who = zfs_fuid_map_id(zfsvfs, who,
7645959Smarks 			    cr, (entry_type & ACE_IDENTIFIER_GROUP) ?
7655959Smarks 			    ZFS_ACE_GROUP : ZFS_ACE_USER);
7665959Smarks 		} else {
7675331Samw 			acep->a_who = (uid_t)(int64_t)who;
7685959Smarks 		}
7695331Samw 		acep->a_access_mask = access_mask;
7705331Samw 		acep->a_flags = iflags;
7715331Samw 		acep->a_type = type;
7725331Samw 		acep = (ace_t *)((caddr_t)acep + ace_size);
7735331Samw 	}
7745331Samw }
7755331Samw 
7765331Samw static int
zfs_copy_ace_2_oldace(vtype_t obj_type,zfs_acl_t * aclp,ace_t * acep,zfs_oldace_t * z_acl,int aclcnt,size_t * size)7775331Samw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
7785331Samw     zfs_oldace_t *z_acl, int aclcnt, size_t *size)
7795331Samw {
7805331Samw 	int i;
7815331Samw 	zfs_oldace_t *aceptr = z_acl;
7825331Samw 
7835331Samw 	for (i = 0; i != aclcnt; i++, aceptr++) {
7845331Samw 		aceptr->z_access_mask = acep[i].a_access_mask;
7855331Samw 		aceptr->z_type = acep[i].a_type;
7865331Samw 		aceptr->z_flags = acep[i].a_flags;
7875331Samw 		aceptr->z_fuid = acep[i].a_who;
7885331Samw 		/*
7895331Samw 		 * Make sure ACE is valid
7905331Samw 		 */
7915331Samw 		if (zfs_ace_valid(obj_type, aclp, aceptr->z_type,
7925331Samw 		    aceptr->z_flags) != B_TRUE)
7935331Samw 			return (EINVAL);
7945331Samw 	}
7955331Samw 	*size = (caddr_t)aceptr - (caddr_t)z_acl;
7965331Samw 	return (0);
7975331Samw }
7985331Samw 
7995331Samw /*
8005331Samw  * convert old ACL format to new
8015331Samw  */
8025331Samw void
zfs_acl_xform(znode_t * zp,zfs_acl_t * aclp,cred_t * cr)8039179SMark.Shellenbaum@Sun.COM zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
8045331Samw {
8055331Samw 	zfs_oldace_t *oldaclp;
8065331Samw 	int i;
8075331Samw 	uint16_t type, iflags;
8085331Samw 	uint32_t access_mask;
8095331Samw 	uint64_t who;
8105331Samw 	void *cookie = NULL;
8115489Smarks 	zfs_acl_node_t *newaclnode;
8125331Samw 
8135331Samw 	ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL);
8145331Samw 	/*
8155331Samw 	 * First create the ACE in a contiguous piece of memory
8165331Samw 	 * for zfs_copy_ace_2_fuid().
8175331Samw 	 *
8185331Samw 	 * We only convert an ACL once, so this won't happen
8195331Samw 	 * everytime.
8205331Samw 	 */
8215331Samw 	oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
8225331Samw 	    KM_SLEEP);
8235331Samw 	i = 0;
8245331Samw 	while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
8255331Samw 	    &access_mask, &iflags, &type)) {
8265331Samw 		oldaclp[i].z_flags = iflags;
8275331Samw 		oldaclp[i].z_type = type;
8285331Samw 		oldaclp[i].z_fuid = who;
8295331Samw 		oldaclp[i++].z_access_mask = access_mask;
8305331Samw 	}
8315331Samw 
8325331Samw 	newaclnode = zfs_acl_node_alloc(aclp->z_acl_count *
8335331Samw 	    sizeof (zfs_object_ace_t));
8345331Samw 	aclp->z_ops = zfs_acl_fuid_ops;
8359179SMark.Shellenbaum@Sun.COM 	VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp,
8369179SMark.Shellenbaum@Sun.COM 	    oldaclp, newaclnode->z_acldata, aclp->z_acl_count,
8379179SMark.Shellenbaum@Sun.COM 	    &newaclnode->z_size, NULL, cr) == 0);
8385331Samw 	newaclnode->z_ace_count = aclp->z_acl_count;
8395331Samw 	aclp->z_version = ZFS_ACL_VERSION;
8405331Samw 	kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
8415331Samw 
8425331Samw 	/*
8435331Samw 	 * Release all previous ACL nodes
8445331Samw 	 */
8455331Samw 
8465489Smarks 	zfs_acl_release_nodes(aclp);
8475489Smarks 
8485331Samw 	list_insert_head(&aclp->z_acl, newaclnode);
8495489Smarks 
8505489Smarks 	aclp->z_acl_bytes = newaclnode->z_size;
8515489Smarks 	aclp->z_acl_count = newaclnode->z_ace_count;
8525489Smarks 
853789Sahrens }
854789Sahrens 
855789Sahrens /*
856789Sahrens  * Convert unix access mask to v4 access mask
857789Sahrens  */
858789Sahrens static uint32_t
zfs_unix_to_v4(uint32_t access_mask)859789Sahrens zfs_unix_to_v4(uint32_t access_mask)
860789Sahrens {
861789Sahrens 	uint32_t new_mask = 0;
862789Sahrens 
8635331Samw 	if (access_mask & S_IXOTH)
8645331Samw 		new_mask |= ACE_EXECUTE;
8655331Samw 	if (access_mask & S_IWOTH)
8665331Samw 		new_mask |= ACE_WRITE_DATA;
8675331Samw 	if (access_mask & S_IROTH)
868789Sahrens 		new_mask |= ACE_READ_DATA;
869789Sahrens 	return (new_mask);
870789Sahrens }
871789Sahrens 
872789Sahrens static void
zfs_set_ace(zfs_acl_t * aclp,void * acep,uint32_t access_mask,uint16_t access_type,uint64_t fuid,uint16_t entry_type)8735331Samw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
8745331Samw     uint16_t access_type, uint64_t fuid, uint16_t entry_type)
875789Sahrens {
8765331Samw 	uint16_t type = entry_type & ACE_TYPE_FLAGS;
8775331Samw 
8785331Samw 	aclp->z_ops.ace_mask_set(acep, access_mask);
8795331Samw 	aclp->z_ops.ace_type_set(acep, access_type);
8805331Samw 	aclp->z_ops.ace_flags_set(acep, entry_type);
8817328SMark.Shellenbaum@Sun.COM 	if ((type != ACE_OWNER && type != OWNING_GROUP &&
8825331Samw 	    type != ACE_EVERYONE))
8835331Samw 		aclp->z_ops.ace_who_set(acep, fuid);
884789Sahrens }
885789Sahrens 
8865331Samw /*
8875331Samw  * Determine mode of file based on ACL.
8885331Samw  * Also, create FUIDs for any User/Group ACEs
8895331Samw  */
89011935SMark.Shellenbaum@Sun.COM uint64_t
zfs_mode_compute(uint64_t fmode,zfs_acl_t * aclp,uint64_t * pflags,uint64_t fuid,uint64_t fgid)89112164SMark.Shellenbaum@Sun.COM zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
89212164SMark.Shellenbaum@Sun.COM     uint64_t *pflags, uint64_t fuid, uint64_t fgid)
893789Sahrens {
8945331Samw 	int		entry_type;
8955331Samw 	mode_t		mode;
8965331Samw 	mode_t		seen = 0;
8975331Samw 	zfs_ace_hdr_t 	*acep = NULL;
8985331Samw 	uint64_t	who;
8995331Samw 	uint16_t	iflags, type;
9005331Samw 	uint32_t	access_mask;
9019981STim.Haley@Sun.COM 	boolean_t	an_exec_denied = B_FALSE;
902789Sahrens 
90311935SMark.Shellenbaum@Sun.COM 	mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
9045331Samw 
9055331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who,
9065331Samw 	    &access_mask, &iflags, &type)) {
9074869Smarks 
9087559SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
9097559SMark.Shellenbaum@Sun.COM 			continue;
9107559SMark.Shellenbaum@Sun.COM 
9117328SMark.Shellenbaum@Sun.COM 		entry_type = (iflags & ACE_TYPE_FLAGS);
9127328SMark.Shellenbaum@Sun.COM 
9134869Smarks 		/*
9147328SMark.Shellenbaum@Sun.COM 		 * Skip over owner@, group@ or everyone@ inherit only ACEs
9154869Smarks 		 */
9167328SMark.Shellenbaum@Sun.COM 		if ((iflags & ACE_INHERIT_ONLY_ACE) &&
9177328SMark.Shellenbaum@Sun.COM 		    (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
9187328SMark.Shellenbaum@Sun.COM 		    entry_type == OWNING_GROUP))
9194869Smarks 			continue;
9204869Smarks 
92112164SMark.Shellenbaum@Sun.COM 		if (entry_type == ACE_OWNER || (entry_type == 0 &&
92212164SMark.Shellenbaum@Sun.COM 		    who == fuid)) {
9235331Samw 			if ((access_mask & ACE_READ_DATA) &&
924789Sahrens 			    (!(seen & S_IRUSR))) {
925789Sahrens 				seen |= S_IRUSR;
9265331Samw 				if (type == ALLOW) {
927789Sahrens 					mode |= S_IRUSR;
928789Sahrens 				}
929789Sahrens 			}
9305331Samw 			if ((access_mask & ACE_WRITE_DATA) &&
931789Sahrens 			    (!(seen & S_IWUSR))) {
932789Sahrens 				seen |= S_IWUSR;
9335331Samw 				if (type == ALLOW) {
934789Sahrens 					mode |= S_IWUSR;
935789Sahrens 				}
936789Sahrens 			}
9375331Samw 			if ((access_mask & ACE_EXECUTE) &&
938789Sahrens 			    (!(seen & S_IXUSR))) {
939789Sahrens 				seen |= S_IXUSR;
9405331Samw 				if (type == ALLOW) {
941789Sahrens 					mode |= S_IXUSR;
942789Sahrens 				}
943789Sahrens 			}
94412164SMark.Shellenbaum@Sun.COM 		} else if (entry_type == OWNING_GROUP ||
94512164SMark.Shellenbaum@Sun.COM 		    (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) {
9465331Samw 			if ((access_mask & ACE_READ_DATA) &&
947789Sahrens 			    (!(seen & S_IRGRP))) {
948789Sahrens 				seen |= S_IRGRP;
9495331Samw 				if (type == ALLOW) {
950789Sahrens 					mode |= S_IRGRP;
951789Sahrens 				}
952789Sahrens 			}
9535331Samw 			if ((access_mask & ACE_WRITE_DATA) &&
954789Sahrens 			    (!(seen & S_IWGRP))) {
955789Sahrens 				seen |= S_IWGRP;
9565331Samw 				if (type == ALLOW) {
957789Sahrens 					mode |= S_IWGRP;
958789Sahrens 				}
959789Sahrens 			}
9605331Samw 			if ((access_mask & ACE_EXECUTE) &&
961789Sahrens 			    (!(seen & S_IXGRP))) {
962789Sahrens 				seen |= S_IXGRP;
9635331Samw 				if (type == ALLOW) {
964789Sahrens 					mode |= S_IXGRP;
965789Sahrens 				}
966789Sahrens 			}
967789Sahrens 		} else if (entry_type == ACE_EVERYONE) {
9685331Samw 			if ((access_mask & ACE_READ_DATA)) {
969789Sahrens 				if (!(seen & S_IRUSR)) {
970789Sahrens 					seen |= S_IRUSR;
9715331Samw 					if (type == ALLOW) {
972789Sahrens 						mode |= S_IRUSR;
973789Sahrens 					}
974789Sahrens 				}
975789Sahrens 				if (!(seen & S_IRGRP)) {
976789Sahrens 					seen |= S_IRGRP;
9775331Samw 					if (type == ALLOW) {
978789Sahrens 						mode |= S_IRGRP;
979789Sahrens 					}
980789Sahrens 				}
981789Sahrens 				if (!(seen & S_IROTH)) {
982789Sahrens 					seen |= S_IROTH;
9835331Samw 					if (type == ALLOW) {
984789Sahrens 						mode |= S_IROTH;
985789Sahrens 					}
986789Sahrens 				}
987789Sahrens 			}
9885331Samw 			if ((access_mask & ACE_WRITE_DATA)) {
989789Sahrens 				if (!(seen & S_IWUSR)) {
990789Sahrens 					seen |= S_IWUSR;
9915331Samw 					if (type == ALLOW) {
992789Sahrens 						mode |= S_IWUSR;
993789Sahrens 					}
994789Sahrens 				}
995789Sahrens 				if (!(seen & S_IWGRP)) {
996789Sahrens 					seen |= S_IWGRP;
9975331Samw 					if (type == ALLOW) {
998789Sahrens 						mode |= S_IWGRP;
999789Sahrens 					}
1000789Sahrens 				}
1001789Sahrens 				if (!(seen & S_IWOTH)) {
1002789Sahrens 					seen |= S_IWOTH;
10035331Samw 					if (type == ALLOW) {
1004789Sahrens 						mode |= S_IWOTH;
1005789Sahrens 					}
1006789Sahrens 				}
1007789Sahrens 			}
10085331Samw 			if ((access_mask & ACE_EXECUTE)) {
1009789Sahrens 				if (!(seen & S_IXUSR)) {
1010789Sahrens 					seen |= S_IXUSR;
10115331Samw 					if (type == ALLOW) {
1012789Sahrens 						mode |= S_IXUSR;
1013789Sahrens 					}
1014789Sahrens 				}
1015789Sahrens 				if (!(seen & S_IXGRP)) {
1016789Sahrens 					seen |= S_IXGRP;
10175331Samw 					if (type == ALLOW) {
1018789Sahrens 						mode |= S_IXGRP;
1019789Sahrens 					}
1020789Sahrens 				}
1021789Sahrens 				if (!(seen & S_IXOTH)) {
1022789Sahrens 					seen |= S_IXOTH;
10235331Samw 					if (type == ALLOW) {
1024789Sahrens 						mode |= S_IXOTH;
1025789Sahrens 					}
1026789Sahrens 				}
1027789Sahrens 			}
10289981STim.Haley@Sun.COM 		} else {
10299981STim.Haley@Sun.COM 			/*
10309981STim.Haley@Sun.COM 			 * Only care if this IDENTIFIER_GROUP or
10319981STim.Haley@Sun.COM 			 * USER ACE denies execute access to someone,
10329981STim.Haley@Sun.COM 			 * mode is not affected
10339981STim.Haley@Sun.COM 			 */
10349981STim.Haley@Sun.COM 			if ((access_mask & ACE_EXECUTE) && type == DENY)
10359981STim.Haley@Sun.COM 				an_exec_denied = B_TRUE;
1036789Sahrens 		}
1037789Sahrens 	}
10389981STim.Haley@Sun.COM 
103910143STim.Haley@Sun.COM 	/*
104010143STim.Haley@Sun.COM 	 * Failure to allow is effectively a deny, so execute permission
104110143STim.Haley@Sun.COM 	 * is denied if it was never mentioned or if we explicitly
104210143STim.Haley@Sun.COM 	 * weren't allowed it.
104310143STim.Haley@Sun.COM 	 */
104410143STim.Haley@Sun.COM 	if (!an_exec_denied &&
104510143STim.Haley@Sun.COM 	    ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS ||
104610143STim.Haley@Sun.COM 	    (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS))
10479981STim.Haley@Sun.COM 		an_exec_denied = B_TRUE;
10489981STim.Haley@Sun.COM 
10499981STim.Haley@Sun.COM 	if (an_exec_denied)
105011935SMark.Shellenbaum@Sun.COM 		*pflags &= ~ZFS_NO_EXECS_DENIED;
10519981STim.Haley@Sun.COM 	else
105211935SMark.Shellenbaum@Sun.COM 		*pflags |= ZFS_NO_EXECS_DENIED;
10539981STim.Haley@Sun.COM 
1054789Sahrens 	return (mode);
1055789Sahrens }
1056789Sahrens 
1057789Sahrens /*
105810143STim.Haley@Sun.COM  * Read an external acl object.  If the intent is to modify, always
105910143STim.Haley@Sun.COM  * create a new acl and leave any cached acl in place.
1060789Sahrens  */
10611544Seschrock static int
zfs_acl_node_read(znode_t * zp,boolean_t have_lock,zfs_acl_t ** aclpp,boolean_t will_modify)106212620SMark.Shellenbaum@Oracle.COM zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp,
106312620SMark.Shellenbaum@Oracle.COM     boolean_t will_modify)
1064789Sahrens {
1065789Sahrens 	zfs_acl_t	*aclp;
106611935SMark.Shellenbaum@Sun.COM 	int		aclsize;
106711935SMark.Shellenbaum@Sun.COM 	int		acl_count;
10685331Samw 	zfs_acl_node_t	*aclnode;
106911935SMark.Shellenbaum@Sun.COM 	zfs_acl_phys_t	znode_acl;
107011935SMark.Shellenbaum@Sun.COM 	int		version;
107111935SMark.Shellenbaum@Sun.COM 	int		error;
107212620SMark.Shellenbaum@Oracle.COM 	boolean_t	drop_lock = B_FALSE;
1073789Sahrens 
1074789Sahrens 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
1075789Sahrens 
107610143STim.Haley@Sun.COM 	if (zp->z_acl_cached && !will_modify) {
10779981STim.Haley@Sun.COM 		*aclpp = zp->z_acl_cached;
10789981STim.Haley@Sun.COM 		return (0);
10799981STim.Haley@Sun.COM 	}
10809981STim.Haley@Sun.COM 
108112620SMark.Shellenbaum@Oracle.COM 	/*
108212620SMark.Shellenbaum@Oracle.COM 	 * close race where znode could be upgrade while trying to
108312620SMark.Shellenbaum@Oracle.COM 	 * read the znode attributes.
108412620SMark.Shellenbaum@Oracle.COM 	 *
108512620SMark.Shellenbaum@Oracle.COM 	 * But this could only happen if the file isn't already an SA
108612620SMark.Shellenbaum@Oracle.COM 	 * znode
108712620SMark.Shellenbaum@Oracle.COM 	 */
108812620SMark.Shellenbaum@Oracle.COM 	if (!zp->z_is_sa && !have_lock) {
108912620SMark.Shellenbaum@Oracle.COM 		mutex_enter(&zp->z_lock);
109012620SMark.Shellenbaum@Oracle.COM 		drop_lock = B_TRUE;
109112620SMark.Shellenbaum@Oracle.COM 	}
109212620SMark.Shellenbaum@Oracle.COM 	version = zfs_znode_acl_version(zp);
109311935SMark.Shellenbaum@Sun.COM 
109411935SMark.Shellenbaum@Sun.COM 	if ((error = zfs_acl_znode_info(zp, &aclsize,
109512620SMark.Shellenbaum@Oracle.COM 	    &acl_count, &znode_acl)) != 0) {
109612620SMark.Shellenbaum@Oracle.COM 		goto done;
109712620SMark.Shellenbaum@Oracle.COM 	}
109811935SMark.Shellenbaum@Sun.COM 
109911935SMark.Shellenbaum@Sun.COM 	aclp = zfs_acl_alloc(version);
110011935SMark.Shellenbaum@Sun.COM 
11015331Samw 	aclp->z_acl_count = acl_count;
11025331Samw 	aclp->z_acl_bytes = aclsize;
11035331Samw 
110411935SMark.Shellenbaum@Sun.COM 	aclnode = zfs_acl_node_alloc(aclsize);
110511935SMark.Shellenbaum@Sun.COM 	aclnode->z_ace_count = aclp->z_acl_count;
110611935SMark.Shellenbaum@Sun.COM 	aclnode->z_size = aclsize;
110711935SMark.Shellenbaum@Sun.COM 
110811935SMark.Shellenbaum@Sun.COM 	if (!zp->z_is_sa) {
110911935SMark.Shellenbaum@Sun.COM 		if (znode_acl.z_acl_extern_obj) {
111011935SMark.Shellenbaum@Sun.COM 			error = dmu_read(zp->z_zfsvfs->z_os,
111111935SMark.Shellenbaum@Sun.COM 			    znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
111211935SMark.Shellenbaum@Sun.COM 			    aclnode->z_acldata, DMU_READ_PREFETCH);
111311935SMark.Shellenbaum@Sun.COM 		} else {
111411935SMark.Shellenbaum@Sun.COM 			bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
111511935SMark.Shellenbaum@Sun.COM 			    aclnode->z_size);
111611935SMark.Shellenbaum@Sun.COM 		}
111711935SMark.Shellenbaum@Sun.COM 	} else {
111811935SMark.Shellenbaum@Sun.COM 		error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs),
111911935SMark.Shellenbaum@Sun.COM 		    aclnode->z_acldata, aclnode->z_size);
112011935SMark.Shellenbaum@Sun.COM 	}
112111935SMark.Shellenbaum@Sun.COM 
11221544Seschrock 	if (error != 0) {
11231544Seschrock 		zfs_acl_free(aclp);
112411935SMark.Shellenbaum@Sun.COM 		zfs_acl_node_free(aclnode);
11257294Sperrin 		/* convert checksum errors into IO errors */
11267294Sperrin 		if (error == ECKSUM)
11277294Sperrin 			error = EIO;
112812620SMark.Shellenbaum@Oracle.COM 		goto done;
11291544Seschrock 	}
1130789Sahrens 
113111935SMark.Shellenbaum@Sun.COM 	list_insert_head(&aclp->z_acl, aclnode);
113211935SMark.Shellenbaum@Sun.COM 
113310143STim.Haley@Sun.COM 	*aclpp = aclp;
113410143STim.Haley@Sun.COM 	if (!will_modify)
113510143STim.Haley@Sun.COM 		zp->z_acl_cached = aclp;
113612620SMark.Shellenbaum@Oracle.COM done:
113712620SMark.Shellenbaum@Oracle.COM 	if (drop_lock)
113812620SMark.Shellenbaum@Oracle.COM 		mutex_exit(&zp->z_lock);
113912620SMark.Shellenbaum@Oracle.COM 	return (error);
1140789Sahrens }
1141789Sahrens 
114211935SMark.Shellenbaum@Sun.COM /*ARGSUSED*/
114311935SMark.Shellenbaum@Sun.COM void
zfs_acl_data_locator(void ** dataptr,uint32_t * length,uint32_t buflen,boolean_t start,void * userdata)114411935SMark.Shellenbaum@Sun.COM zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
114511935SMark.Shellenbaum@Sun.COM     boolean_t start, void *userdata)
114611935SMark.Shellenbaum@Sun.COM {
114711935SMark.Shellenbaum@Sun.COM 	zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
114811935SMark.Shellenbaum@Sun.COM 
114911935SMark.Shellenbaum@Sun.COM 	if (start) {
115011935SMark.Shellenbaum@Sun.COM 		cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl);
115111935SMark.Shellenbaum@Sun.COM 	} else {
115211935SMark.Shellenbaum@Sun.COM 		cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
115311935SMark.Shellenbaum@Sun.COM 		    cb->cb_acl_node);
115411935SMark.Shellenbaum@Sun.COM 	}
115511935SMark.Shellenbaum@Sun.COM 	*dataptr = cb->cb_acl_node->z_acldata;
115611935SMark.Shellenbaum@Sun.COM 	*length = cb->cb_acl_node->z_size;
115711935SMark.Shellenbaum@Sun.COM }
115811935SMark.Shellenbaum@Sun.COM 
115912164SMark.Shellenbaum@Sun.COM int
zfs_acl_chown_setattr(znode_t * zp)116012164SMark.Shellenbaum@Sun.COM zfs_acl_chown_setattr(znode_t *zp)
116112164SMark.Shellenbaum@Sun.COM {
116212164SMark.Shellenbaum@Sun.COM 	int error;
116312164SMark.Shellenbaum@Sun.COM 	zfs_acl_t *aclp;
116412164SMark.Shellenbaum@Sun.COM 
116512620SMark.Shellenbaum@Oracle.COM 	ASSERT(MUTEX_HELD(&zp->z_lock));
116612620SMark.Shellenbaum@Oracle.COM 	ASSERT(MUTEX_HELD(&zp->z_acl_lock));
116712164SMark.Shellenbaum@Sun.COM 
116812620SMark.Shellenbaum@Oracle.COM 	if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0)
116912164SMark.Shellenbaum@Sun.COM 		zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
117013069SMark.Shellenbaum@Oracle.COM 		    &zp->z_pflags, zp->z_uid, zp->z_gid);
117112164SMark.Shellenbaum@Sun.COM 	return (error);
117212164SMark.Shellenbaum@Sun.COM }
117312164SMark.Shellenbaum@Sun.COM 
1174789Sahrens /*
11755331Samw  * common code for setting ACLs.
1176789Sahrens  *
1177789Sahrens  * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
1178789Sahrens  * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
1179789Sahrens  * already checked the acl and knows whether to inherit.
1180789Sahrens  */
1181789Sahrens int
zfs_aclset_common(znode_t * zp,zfs_acl_t * aclp,cred_t * cr,dmu_tx_t * tx)11829179SMark.Shellenbaum@Sun.COM zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
1183789Sahrens {
118411935SMark.Shellenbaum@Sun.COM 	int			error;
118511935SMark.Shellenbaum@Sun.COM 	zfsvfs_t		*zfsvfs = zp->z_zfsvfs;
118611935SMark.Shellenbaum@Sun.COM 	dmu_object_type_t	otype;
118711935SMark.Shellenbaum@Sun.COM 	zfs_acl_locator_cb_t	locate = { 0 };
118811935SMark.Shellenbaum@Sun.COM 	uint64_t		mode;
118911935SMark.Shellenbaum@Sun.COM 	sa_bulk_attr_t		bulk[5];
119011935SMark.Shellenbaum@Sun.COM 	uint64_t		ctime[2];
119111935SMark.Shellenbaum@Sun.COM 	int			count = 0;
119211935SMark.Shellenbaum@Sun.COM 
119311935SMark.Shellenbaum@Sun.COM 	mode = zp->z_mode;
119412164SMark.Shellenbaum@Sun.COM 
119513069SMark.Shellenbaum@Oracle.COM 	mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
119613069SMark.Shellenbaum@Oracle.COM 	    zp->z_uid, zp->z_gid);
119711935SMark.Shellenbaum@Sun.COM 
119811935SMark.Shellenbaum@Sun.COM 	zp->z_mode = mode;
119911935SMark.Shellenbaum@Sun.COM 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
120011935SMark.Shellenbaum@Sun.COM 	    &mode, sizeof (mode));
120111935SMark.Shellenbaum@Sun.COM 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
120211935SMark.Shellenbaum@Sun.COM 	    &zp->z_pflags, sizeof (zp->z_pflags));
120311935SMark.Shellenbaum@Sun.COM 	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
120411935SMark.Shellenbaum@Sun.COM 	    &ctime, sizeof (ctime));
1205789Sahrens 
120610143STim.Haley@Sun.COM 	if (zp->z_acl_cached) {
12079981STim.Haley@Sun.COM 		zfs_acl_free(zp->z_acl_cached);
12089981STim.Haley@Sun.COM 		zp->z_acl_cached = NULL;
12099981STim.Haley@Sun.COM 	}
12109981STim.Haley@Sun.COM 
1211789Sahrens 	/*
121211935SMark.Shellenbaum@Sun.COM 	 * Upgrade needed?
1213789Sahrens 	 */
12145331Samw 	if (!zfsvfs->z_use_fuids) {
12155331Samw 		otype = DMU_OT_OLDACL;
12165331Samw 	} else {
12175331Samw 		if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) &&
12185331Samw 		    (zfsvfs->z_version >= ZPL_VERSION_FUID))
12199179SMark.Shellenbaum@Sun.COM 			zfs_acl_xform(zp, aclp, cr);
12205331Samw 		ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID);
12215331Samw 		otype = DMU_OT_ACL;
12225331Samw 	}
12235331Samw 
122411935SMark.Shellenbaum@Sun.COM 	/*
122511935SMark.Shellenbaum@Sun.COM 	 * Arrgh, we have to handle old on disk format
122611935SMark.Shellenbaum@Sun.COM 	 * as well as newer (preferred) SA format.
122711935SMark.Shellenbaum@Sun.COM 	 */
122811935SMark.Shellenbaum@Sun.COM 
122911935SMark.Shellenbaum@Sun.COM 	if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */
123011935SMark.Shellenbaum@Sun.COM 		locate.cb_aclp = aclp;
123111935SMark.Shellenbaum@Sun.COM 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs),
123211935SMark.Shellenbaum@Sun.COM 		    zfs_acl_data_locator, &locate, aclp->z_acl_bytes);
123311935SMark.Shellenbaum@Sun.COM 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs),
123411935SMark.Shellenbaum@Sun.COM 		    NULL, &aclp->z_acl_count, sizeof (uint64_t));
123511935SMark.Shellenbaum@Sun.COM 	} else { /* Painful legacy way */
123611935SMark.Shellenbaum@Sun.COM 		zfs_acl_node_t *aclnode;
123711935SMark.Shellenbaum@Sun.COM 		uint64_t off = 0;
123811935SMark.Shellenbaum@Sun.COM 		zfs_acl_phys_t acl_phys;
123911935SMark.Shellenbaum@Sun.COM 		uint64_t aoid;
124011935SMark.Shellenbaum@Sun.COM 
124111935SMark.Shellenbaum@Sun.COM 		if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
124211935SMark.Shellenbaum@Sun.COM 		    &acl_phys, sizeof (acl_phys))) != 0)
124311935SMark.Shellenbaum@Sun.COM 			return (error);
124411935SMark.Shellenbaum@Sun.COM 
124511935SMark.Shellenbaum@Sun.COM 		aoid = acl_phys.z_acl_extern_obj;
124611935SMark.Shellenbaum@Sun.COM 
124711935SMark.Shellenbaum@Sun.COM 		if (aclp->z_acl_bytes > ZFS_ACE_SPACE) {
124811935SMark.Shellenbaum@Sun.COM 			/*
124911935SMark.Shellenbaum@Sun.COM 			 * If ACL was previously external and we are now
125011935SMark.Shellenbaum@Sun.COM 			 * converting to new ACL format then release old
125111935SMark.Shellenbaum@Sun.COM 			 * ACL object and create a new one.
125211935SMark.Shellenbaum@Sun.COM 			 */
125311935SMark.Shellenbaum@Sun.COM 			if (aoid &&
125411935SMark.Shellenbaum@Sun.COM 			    aclp->z_version != acl_phys.z_acl_version) {
125511935SMark.Shellenbaum@Sun.COM 				error = dmu_object_free(zfsvfs->z_os, aoid, tx);
125611935SMark.Shellenbaum@Sun.COM 				if (error)
125711935SMark.Shellenbaum@Sun.COM 					return (error);
125811935SMark.Shellenbaum@Sun.COM 				aoid = 0;
125911935SMark.Shellenbaum@Sun.COM 			}
126011935SMark.Shellenbaum@Sun.COM 			if (aoid == 0) {
126111935SMark.Shellenbaum@Sun.COM 				aoid = dmu_object_alloc(zfsvfs->z_os,
126211935SMark.Shellenbaum@Sun.COM 				    otype, aclp->z_acl_bytes,
126311935SMark.Shellenbaum@Sun.COM 				    otype == DMU_OT_ACL ?
126411935SMark.Shellenbaum@Sun.COM 				    DMU_OT_SYSACL : DMU_OT_NONE,
126511935SMark.Shellenbaum@Sun.COM 				    otype == DMU_OT_ACL ?
126611935SMark.Shellenbaum@Sun.COM 				    DN_MAX_BONUSLEN : 0, tx);
126711935SMark.Shellenbaum@Sun.COM 			} else {
126811935SMark.Shellenbaum@Sun.COM 				(void) dmu_object_set_blocksize(zfsvfs->z_os,
126911935SMark.Shellenbaum@Sun.COM 				    aoid, aclp->z_acl_bytes, 0, tx);
127011935SMark.Shellenbaum@Sun.COM 			}
127111935SMark.Shellenbaum@Sun.COM 			acl_phys.z_acl_extern_obj = aoid;
127211935SMark.Shellenbaum@Sun.COM 			for (aclnode = list_head(&aclp->z_acl); aclnode;
127311935SMark.Shellenbaum@Sun.COM 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
127411935SMark.Shellenbaum@Sun.COM 				if (aclnode->z_ace_count == 0)
127511935SMark.Shellenbaum@Sun.COM 					continue;
127611935SMark.Shellenbaum@Sun.COM 				dmu_write(zfsvfs->z_os, aoid, off,
127711935SMark.Shellenbaum@Sun.COM 				    aclnode->z_size, aclnode->z_acldata, tx);
127811935SMark.Shellenbaum@Sun.COM 				off += aclnode->z_size;
127911935SMark.Shellenbaum@Sun.COM 			}
1280789Sahrens 		} else {
128111935SMark.Shellenbaum@Sun.COM 			void *start = acl_phys.z_ace_data;
128211935SMark.Shellenbaum@Sun.COM 			/*
128311935SMark.Shellenbaum@Sun.COM 			 * Migrating back embedded?
128411935SMark.Shellenbaum@Sun.COM 			 */
128511935SMark.Shellenbaum@Sun.COM 			if (acl_phys.z_acl_extern_obj) {
128611935SMark.Shellenbaum@Sun.COM 				error = dmu_object_free(zfsvfs->z_os,
128711935SMark.Shellenbaum@Sun.COM 				    acl_phys.z_acl_extern_obj, tx);
128811935SMark.Shellenbaum@Sun.COM 				if (error)
128911935SMark.Shellenbaum@Sun.COM 					return (error);
129011935SMark.Shellenbaum@Sun.COM 				acl_phys.z_acl_extern_obj = 0;
129111935SMark.Shellenbaum@Sun.COM 			}
129211935SMark.Shellenbaum@Sun.COM 
129311935SMark.Shellenbaum@Sun.COM 			for (aclnode = list_head(&aclp->z_acl); aclnode;
129411935SMark.Shellenbaum@Sun.COM 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
129511935SMark.Shellenbaum@Sun.COM 				if (aclnode->z_ace_count == 0)
129611935SMark.Shellenbaum@Sun.COM 					continue;
129711935SMark.Shellenbaum@Sun.COM 				bcopy(aclnode->z_acldata, start,
129811935SMark.Shellenbaum@Sun.COM 				    aclnode->z_size);
129911935SMark.Shellenbaum@Sun.COM 				start = (caddr_t)start + aclnode->z_size;
130011935SMark.Shellenbaum@Sun.COM 			}
13015331Samw 		}
1302789Sahrens 		/*
130311935SMark.Shellenbaum@Sun.COM 		 * If Old version then swap count/bytes to match old
130411935SMark.Shellenbaum@Sun.COM 		 * layout of znode_acl_phys_t.
1305789Sahrens 		 */
130611935SMark.Shellenbaum@Sun.COM 		if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
130711935SMark.Shellenbaum@Sun.COM 			acl_phys.z_acl_size = aclp->z_acl_count;
130811935SMark.Shellenbaum@Sun.COM 			acl_phys.z_acl_count = aclp->z_acl_bytes;
130911935SMark.Shellenbaum@Sun.COM 		} else {
131011935SMark.Shellenbaum@Sun.COM 			acl_phys.z_acl_size = aclp->z_acl_bytes;
131111935SMark.Shellenbaum@Sun.COM 			acl_phys.z_acl_count = aclp->z_acl_count;
1312789Sahrens 		}
131311935SMark.Shellenbaum@Sun.COM 		acl_phys.z_acl_version = aclp->z_version;
131411935SMark.Shellenbaum@Sun.COM 
131511935SMark.Shellenbaum@Sun.COM 		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
131611935SMark.Shellenbaum@Sun.COM 		    &acl_phys, sizeof (acl_phys));
1317789Sahrens 	}
1318905Smarks 
13195331Samw 	/*
13205331Samw 	 * Replace ACL wide bits, but first clear them.
13215331Samw 	 */
132211935SMark.Shellenbaum@Sun.COM 	zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS;
132311935SMark.Shellenbaum@Sun.COM 
132411935SMark.Shellenbaum@Sun.COM 	zp->z_pflags |= aclp->z_hints;
13255331Samw 
13265331Samw 	if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
132711935SMark.Shellenbaum@Sun.COM 		zp->z_pflags |= ZFS_ACL_TRIVIAL;
132811935SMark.Shellenbaum@Sun.COM 
132911935SMark.Shellenbaum@Sun.COM 	zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE);
133011935SMark.Shellenbaum@Sun.COM 	return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
1331789Sahrens }
1332789Sahrens 
1333789Sahrens /*
1334789Sahrens  * Update access mask for prepended ACE
1335789Sahrens  *
1336789Sahrens  * This applies the "groupmask" value for aclmode property.
1337789Sahrens  */
1338789Sahrens static void
zfs_acl_prepend_fixup(zfs_acl_t * aclp,void * acep,void * origacep,mode_t mode,uint64_t owner)13395331Samw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void  *acep, void  *origacep,
13405331Samw     mode_t mode, uint64_t owner)
1341789Sahrens {
1342789Sahrens 	int	rmask, wmask, xmask;
1343789Sahrens 	int	user_ace;
13445331Samw 	uint16_t aceflags;
13455331Samw 	uint32_t origmask, acepmask;
13465331Samw 	uint64_t fuid;
1347789Sahrens 
13485331Samw 	aceflags = aclp->z_ops.ace_flags_get(acep);
13495331Samw 	fuid = aclp->z_ops.ace_who_get(acep);
13505331Samw 	origmask = aclp->z_ops.ace_mask_get(origacep);
13515331Samw 	acepmask = aclp->z_ops.ace_mask_get(acep);
13525331Samw 
13535331Samw 	user_ace = (!(aceflags &
1354789Sahrens 	    (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
1355789Sahrens 
13565331Samw 	if (user_ace && (fuid == owner)) {
1357789Sahrens 		rmask = S_IRUSR;
1358789Sahrens 		wmask = S_IWUSR;
1359789Sahrens 		xmask = S_IXUSR;
1360789Sahrens 	} else {
1361789Sahrens 		rmask = S_IRGRP;
1362789Sahrens 		wmask = S_IWGRP;
1363789Sahrens 		xmask = S_IXGRP;
1364789Sahrens 	}
1365789Sahrens 
13665331Samw 	if (origmask & ACE_READ_DATA) {
13675331Samw 		if (mode & rmask) {
13685331Samw 			acepmask &= ~ACE_READ_DATA;
13695331Samw 		} else {
13705331Samw 			acepmask |= ACE_READ_DATA;
13715331Samw 		}
1372789Sahrens 	}
1373789Sahrens 
13745331Samw 	if (origmask & ACE_WRITE_DATA) {
13755331Samw 		if (mode & wmask) {
13765331Samw 			acepmask &= ~ACE_WRITE_DATA;
13775331Samw 		} else {
13785331Samw 			acepmask |= ACE_WRITE_DATA;
13795331Samw 		}
1380789Sahrens 	}
1381789Sahrens 
13825331Samw 	if (origmask & ACE_APPEND_DATA) {
13835331Samw 		if (mode & wmask) {
13845331Samw 			acepmask &= ~ACE_APPEND_DATA;
13855331Samw 		} else {
13865331Samw 			acepmask |= ACE_APPEND_DATA;
13875331Samw 		}
1388789Sahrens 	}
1389789Sahrens 
13905331Samw 	if (origmask & ACE_EXECUTE) {
13915331Samw 		if (mode & xmask) {
13925331Samw 			acepmask &= ~ACE_EXECUTE;
13935331Samw 		} else {
13945331Samw 			acepmask |= ACE_EXECUTE;
13955331Samw 		}
1396789Sahrens 	}
13975331Samw 	aclp->z_ops.ace_mask_set(acep, acepmask);
1398789Sahrens }
1399789Sahrens 
1400789Sahrens static void
zfs_acl_chmod(zfsvfs_t * zfsvfs,uint64_t mode,zfs_acl_t * aclp)140112164SMark.Shellenbaum@Sun.COM zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
1402789Sahrens {
140312164SMark.Shellenbaum@Sun.COM 	void		*acep = NULL;
14045331Samw 	uint64_t	who;
140512164SMark.Shellenbaum@Sun.COM 	int		new_count, new_bytes;
140612164SMark.Shellenbaum@Sun.COM 	int		ace_size;
1407789Sahrens 	int 		entry_type;
14085331Samw 	uint16_t	iflags, type;
14095331Samw 	uint32_t	access_mask;
141012164SMark.Shellenbaum@Sun.COM 	zfs_acl_node_t	*newnode;
141112164SMark.Shellenbaum@Sun.COM 	size_t 		abstract_size = aclp->z_ops.ace_abstract_size();
141212164SMark.Shellenbaum@Sun.COM 	void 		*zacep;
141312164SMark.Shellenbaum@Sun.COM 	uint32_t 	owner, group, everyone;
141412164SMark.Shellenbaum@Sun.COM 	uint32_t	deny1, deny2, allow0;
1415789Sahrens 
141612164SMark.Shellenbaum@Sun.COM 	new_count = new_bytes = 0;
141712164SMark.Shellenbaum@Sun.COM 
141812164SMark.Shellenbaum@Sun.COM 	acl_trivial_access_masks((mode_t)mode, &allow0, &deny1, &deny2,
141912164SMark.Shellenbaum@Sun.COM 	    &owner, &group, &everyone);
142012164SMark.Shellenbaum@Sun.COM 
142112164SMark.Shellenbaum@Sun.COM 	newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
142212164SMark.Shellenbaum@Sun.COM 
142312164SMark.Shellenbaum@Sun.COM 	zacep = newnode->z_acldata;
142412164SMark.Shellenbaum@Sun.COM 	if (allow0) {
142512164SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, zacep, allow0, ALLOW, -1, ACE_OWNER);
142612164SMark.Shellenbaum@Sun.COM 		zacep = (void *)((uintptr_t)zacep + abstract_size);
142712164SMark.Shellenbaum@Sun.COM 		new_count++;
142812164SMark.Shellenbaum@Sun.COM 		new_bytes += abstract_size;
142912164SMark.Shellenbaum@Sun.COM 	} if (deny1) {
143012164SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, zacep, deny1, DENY, -1, ACE_OWNER);
143112164SMark.Shellenbaum@Sun.COM 		zacep = (void *)((uintptr_t)zacep + abstract_size);
143212164SMark.Shellenbaum@Sun.COM 		new_count++;
143312164SMark.Shellenbaum@Sun.COM 		new_bytes += abstract_size;
143412164SMark.Shellenbaum@Sun.COM 	}
143512164SMark.Shellenbaum@Sun.COM 	if (deny2) {
143612164SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, zacep, deny2, DENY, -1, OWNING_GROUP);
143712164SMark.Shellenbaum@Sun.COM 		zacep = (void *)((uintptr_t)zacep + abstract_size);
143812164SMark.Shellenbaum@Sun.COM 		new_count++;
143912164SMark.Shellenbaum@Sun.COM 		new_bytes += abstract_size;
144012164SMark.Shellenbaum@Sun.COM 	}
14415489Smarks 
14425331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
14435331Samw 	    &iflags, &type)) {
144412164SMark.Shellenbaum@Sun.COM 		uint16_t inherit_flags;
14455331Samw 
14465331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
144712164SMark.Shellenbaum@Sun.COM 		inherit_flags = (iflags & ALL_INHERIT);
144812164SMark.Shellenbaum@Sun.COM 
144912164SMark.Shellenbaum@Sun.COM 		if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
145012164SMark.Shellenbaum@Sun.COM 		    (entry_type == OWNING_GROUP)) &&
145112164SMark.Shellenbaum@Sun.COM 		    ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) {
145212164SMark.Shellenbaum@Sun.COM 			continue;
145312164SMark.Shellenbaum@Sun.COM 		}
1454789Sahrens 
14555331Samw 		if ((type != ALLOW && type != DENY) ||
145612164SMark.Shellenbaum@Sun.COM 		    (inherit_flags & ACE_INHERIT_ONLY_ACE)) {
145712164SMark.Shellenbaum@Sun.COM 			if (inherit_flags)
14585331Samw 				aclp->z_hints |= ZFS_INHERIT_ACE;
14595331Samw 			switch (type) {
14605331Samw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
14615331Samw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
14625331Samw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
14635331Samw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
14645331Samw 				aclp->z_hints |= ZFS_ACL_OBJ_ACE;
14655331Samw 				break;
14665331Samw 			}
1467789Sahrens 		} else {
1468789Sahrens 
146912164SMark.Shellenbaum@Sun.COM 			/*
147012164SMark.Shellenbaum@Sun.COM 			 * Limit permissions to be no greater than
147112164SMark.Shellenbaum@Sun.COM 			 * group permissions
147212164SMark.Shellenbaum@Sun.COM 			 */
147312164SMark.Shellenbaum@Sun.COM 			if (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) {
147412164SMark.Shellenbaum@Sun.COM 				if (!(mode & S_IRGRP))
147512164SMark.Shellenbaum@Sun.COM 					access_mask &= ~ACE_READ_DATA;
147612164SMark.Shellenbaum@Sun.COM 				if (!(mode & S_IWGRP))
147712164SMark.Shellenbaum@Sun.COM 					access_mask &=
147812164SMark.Shellenbaum@Sun.COM 					    ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
147912164SMark.Shellenbaum@Sun.COM 				if (!(mode & S_IXGRP))
148012164SMark.Shellenbaum@Sun.COM 					access_mask &= ~ACE_EXECUTE;
148112164SMark.Shellenbaum@Sun.COM 				access_mask &=
148212164SMark.Shellenbaum@Sun.COM 				    ~(ACE_WRITE_OWNER|ACE_WRITE_ACL|
148312164SMark.Shellenbaum@Sun.COM 				    ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS);
1484789Sahrens 			}
1485789Sahrens 		}
148612164SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
148712164SMark.Shellenbaum@Sun.COM 		ace_size = aclp->z_ops.ace_size(acep);
148812164SMark.Shellenbaum@Sun.COM 		zacep = (void *)((uintptr_t)zacep + ace_size);
148912164SMark.Shellenbaum@Sun.COM 		new_count++;
149012164SMark.Shellenbaum@Sun.COM 		new_bytes += ace_size;
1491789Sahrens 	}
149212164SMark.Shellenbaum@Sun.COM 	zfs_set_ace(aclp, zacep, owner, 0, -1, ACE_OWNER);
149312164SMark.Shellenbaum@Sun.COM 	zacep = (void *)((uintptr_t)zacep + abstract_size);
149412164SMark.Shellenbaum@Sun.COM 	zfs_set_ace(aclp, zacep, group, 0, -1, OWNING_GROUP);
149512164SMark.Shellenbaum@Sun.COM 	zacep = (void *)((uintptr_t)zacep + abstract_size);
149612164SMark.Shellenbaum@Sun.COM 	zfs_set_ace(aclp, zacep, everyone, 0, -1, ACE_EVERYONE);
1497789Sahrens 
149812164SMark.Shellenbaum@Sun.COM 	new_count += 3;
149912164SMark.Shellenbaum@Sun.COM 	new_bytes += abstract_size * 3;
150012164SMark.Shellenbaum@Sun.COM 	zfs_acl_release_nodes(aclp);
150112164SMark.Shellenbaum@Sun.COM 	aclp->z_acl_count = new_count;
150212164SMark.Shellenbaum@Sun.COM 	aclp->z_acl_bytes = new_bytes;
150312164SMark.Shellenbaum@Sun.COM 	newnode->z_ace_count = new_count;
150412164SMark.Shellenbaum@Sun.COM 	newnode->z_size = new_bytes;
150512164SMark.Shellenbaum@Sun.COM 	list_insert_tail(&aclp->z_acl, newnode);
1506789Sahrens }
1507789Sahrens 
1508*13089SMark.Shellenbaum@Oracle.COM void
zfs_acl_chmod_setattr(znode_t * zp,zfs_acl_t ** aclp,uint64_t mode)15095824Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
1510789Sahrens {
151112620SMark.Shellenbaum@Oracle.COM 	mutex_enter(&zp->z_acl_lock);
15125824Smarks 	mutex_enter(&zp->z_lock);
151312164SMark.Shellenbaum@Sun.COM 	*aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
151412164SMark.Shellenbaum@Sun.COM 	(*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
151512164SMark.Shellenbaum@Sun.COM 	zfs_acl_chmod(zp->z_zfsvfs, mode, *aclp);
151612620SMark.Shellenbaum@Oracle.COM 	mutex_exit(&zp->z_lock);
1517789Sahrens 	mutex_exit(&zp->z_acl_lock);
151812164SMark.Shellenbaum@Sun.COM 	ASSERT(*aclp);
1519789Sahrens }
1520789Sahrens 
1521789Sahrens /*
1522789Sahrens  * strip off write_owner and write_acl
1523789Sahrens  */
1524789Sahrens static void
zfs_restricted_update(zfsvfs_t * zfsvfs,zfs_acl_t * aclp,void * acep)15256385Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
1526789Sahrens {
15275331Samw 	uint32_t mask = aclp->z_ops.ace_mask_get(acep);
15285331Samw 
15296385Smarks 	if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) &&
15305331Samw 	    (aclp->z_ops.ace_type_get(acep) == ALLOW)) {
15316385Smarks 		mask &= ~RESTRICTED_CLEAR;
15325331Samw 		aclp->z_ops.ace_mask_set(acep, mask);
15335331Samw 	}
15345331Samw }
15355331Samw 
15365331Samw /*
15375331Samw  * Should ACE be inherited?
15385331Samw  */
15395331Samw static int
zfs_ace_can_use(vtype_t vtype,uint16_t acep_flags)15409179SMark.Shellenbaum@Sun.COM zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags)
15415331Samw {
15425331Samw 	int	iflags = (acep_flags & 0xf);
15435331Samw 
15445331Samw 	if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
15455331Samw 		return (1);
15465331Samw 	else if (iflags & ACE_FILE_INHERIT_ACE)
15475331Samw 		return (!((vtype == VDIR) &&
15485331Samw 		    (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)));
15495331Samw 	return (0);
1550789Sahrens }
1551789Sahrens 
1552789Sahrens /*
1553789Sahrens  * inherit inheritable ACEs from parent
1554789Sahrens  */
1555789Sahrens static zfs_acl_t *
zfs_acl_inherit(zfsvfs_t * zfsvfs,vtype_t vtype,zfs_acl_t * paclp,uint64_t mode,boolean_t * need_chmod)15569179SMark.Shellenbaum@Sun.COM zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
15579179SMark.Shellenbaum@Sun.COM     uint64_t mode, boolean_t *need_chmod)
1558789Sahrens {
15595331Samw 	void		*pacep;
156012164SMark.Shellenbaum@Sun.COM 	void		*acep;
156112164SMark.Shellenbaum@Sun.COM 	zfs_acl_node_t  *aclnode;
1562789Sahrens 	zfs_acl_t	*aclp = NULL;
15635331Samw 	uint64_t	who;
15645331Samw 	uint32_t	access_mask;
15655331Samw 	uint16_t	iflags, newflags, type;
15665331Samw 	size_t		ace_size;
15675331Samw 	void		*data1, *data2;
15685331Samw 	size_t		data1sz, data2sz;
15699179SMark.Shellenbaum@Sun.COM 	boolean_t	vdir = vtype == VDIR;
15709179SMark.Shellenbaum@Sun.COM 	boolean_t	vreg = vtype == VREG;
15718053SMark.Shellenbaum@Sun.COM 	boolean_t	passthrough, passthrough_x, noallow;
15728053SMark.Shellenbaum@Sun.COM 
15738053SMark.Shellenbaum@Sun.COM 	passthrough_x =
15748053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X;
15758053SMark.Shellenbaum@Sun.COM 	passthrough = passthrough_x ||
15768053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH;
15778053SMark.Shellenbaum@Sun.COM 	noallow =
15788053SMark.Shellenbaum@Sun.COM 	    zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW;
1579789Sahrens 
15806385Smarks 	*need_chmod = B_TRUE;
15815331Samw 	pacep = NULL;
15827559SMark.Shellenbaum@Sun.COM 	aclp = zfs_acl_alloc(paclp->z_version);
158311935SMark.Shellenbaum@Sun.COM 	if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK)
15848053SMark.Shellenbaum@Sun.COM 		return (aclp);
15858053SMark.Shellenbaum@Sun.COM 	while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
15868053SMark.Shellenbaum@Sun.COM 	    &access_mask, &iflags, &type)) {
15878053SMark.Shellenbaum@Sun.COM 
15888053SMark.Shellenbaum@Sun.COM 		/*
15898053SMark.Shellenbaum@Sun.COM 		 * don't inherit bogus ACEs
15908053SMark.Shellenbaum@Sun.COM 		 */
15918053SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
15928053SMark.Shellenbaum@Sun.COM 			continue;
15938053SMark.Shellenbaum@Sun.COM 
15948053SMark.Shellenbaum@Sun.COM 		if (noallow && type == ALLOW)
15958053SMark.Shellenbaum@Sun.COM 			continue;
15968053SMark.Shellenbaum@Sun.COM 
15978053SMark.Shellenbaum@Sun.COM 		ace_size = aclp->z_ops.ace_size(pacep);
15988053SMark.Shellenbaum@Sun.COM 
15999179SMark.Shellenbaum@Sun.COM 		if (!zfs_ace_can_use(vtype, iflags))
16008053SMark.Shellenbaum@Sun.COM 			continue;
1601789Sahrens 
16028053SMark.Shellenbaum@Sun.COM 		/*
16038053SMark.Shellenbaum@Sun.COM 		 * If owner@, group@, or everyone@ inheritable
16048053SMark.Shellenbaum@Sun.COM 		 * then zfs_acl_chmod() isn't needed.
16058053SMark.Shellenbaum@Sun.COM 		 */
16068053SMark.Shellenbaum@Sun.COM 		if (passthrough &&
16078053SMark.Shellenbaum@Sun.COM 		    ((iflags & (ACE_OWNER|ACE_EVERYONE)) ||
16088053SMark.Shellenbaum@Sun.COM 		    ((iflags & OWNING_GROUP) ==
16098053SMark.Shellenbaum@Sun.COM 		    OWNING_GROUP)) && (vreg || (vdir && (iflags &
16108053SMark.Shellenbaum@Sun.COM 		    ACE_DIRECTORY_INHERIT_ACE)))) {
16118053SMark.Shellenbaum@Sun.COM 			*need_chmod = B_FALSE;
161211969SMark.Shellenbaum@Sun.COM 		}
161311969SMark.Shellenbaum@Sun.COM 
161411969SMark.Shellenbaum@Sun.COM 		if (!vdir && passthrough_x &&
161511969SMark.Shellenbaum@Sun.COM 		    ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) {
161611969SMark.Shellenbaum@Sun.COM 			access_mask &= ~ACE_EXECUTE;
16178053SMark.Shellenbaum@Sun.COM 		}
1618789Sahrens 
16198053SMark.Shellenbaum@Sun.COM 		aclnode = zfs_acl_node_alloc(ace_size);
16208053SMark.Shellenbaum@Sun.COM 		list_insert_tail(&aclp->z_acl, aclnode);
16218053SMark.Shellenbaum@Sun.COM 		acep = aclnode->z_acldata;
16226385Smarks 
16238053SMark.Shellenbaum@Sun.COM 		zfs_set_ace(aclp, acep, access_mask, type,
16248053SMark.Shellenbaum@Sun.COM 		    who, iflags|ACE_INHERITED_ACE);
16258053SMark.Shellenbaum@Sun.COM 
16268053SMark.Shellenbaum@Sun.COM 		/*
16278053SMark.Shellenbaum@Sun.COM 		 * Copy special opaque data if any
16288053SMark.Shellenbaum@Sun.COM 		 */
16298053SMark.Shellenbaum@Sun.COM 		if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) {
16308053SMark.Shellenbaum@Sun.COM 			VERIFY((data2sz = aclp->z_ops.ace_data(acep,
16318053SMark.Shellenbaum@Sun.COM 			    &data2)) == data1sz);
16328053SMark.Shellenbaum@Sun.COM 			bcopy(data1, data2, data2sz);
16338053SMark.Shellenbaum@Sun.COM 		}
163412164SMark.Shellenbaum@Sun.COM 
16358053SMark.Shellenbaum@Sun.COM 		aclp->z_acl_count++;
16368053SMark.Shellenbaum@Sun.COM 		aclnode->z_ace_count++;
16378053SMark.Shellenbaum@Sun.COM 		aclp->z_acl_bytes += aclnode->z_size;
16388053SMark.Shellenbaum@Sun.COM 		newflags = aclp->z_ops.ace_flags_get(acep);
16398053SMark.Shellenbaum@Sun.COM 
16408053SMark.Shellenbaum@Sun.COM 		if (vdir)
16418053SMark.Shellenbaum@Sun.COM 			aclp->z_hints |= ZFS_INHERIT_ACE;
16426385Smarks 
16438053SMark.Shellenbaum@Sun.COM 		if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) {
16448053SMark.Shellenbaum@Sun.COM 			newflags &= ~ALL_INHERIT;
16458053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep,
16468053SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
16478053SMark.Shellenbaum@Sun.COM 			zfs_restricted_update(zfsvfs, aclp, acep);
16488053SMark.Shellenbaum@Sun.COM 			continue;
16498053SMark.Shellenbaum@Sun.COM 		}
16508053SMark.Shellenbaum@Sun.COM 
16518053SMark.Shellenbaum@Sun.COM 		ASSERT(vdir);
16528053SMark.Shellenbaum@Sun.COM 
165312164SMark.Shellenbaum@Sun.COM 		/*
165412164SMark.Shellenbaum@Sun.COM 		 * If only FILE_INHERIT is set then turn on
165512164SMark.Shellenbaum@Sun.COM 		 * inherit_only
165612164SMark.Shellenbaum@Sun.COM 		 */
16578053SMark.Shellenbaum@Sun.COM 		if ((iflags & (ACE_FILE_INHERIT_ACE |
165812322SMark.Shellenbaum@Sun.COM 		    ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) {
16598053SMark.Shellenbaum@Sun.COM 			newflags |= ACE_INHERIT_ONLY_ACE;
16608053SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep,
16618053SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
166212322SMark.Shellenbaum@Sun.COM 		} else {
166312322SMark.Shellenbaum@Sun.COM 			newflags &= ~ACE_INHERIT_ONLY_ACE;
166412322SMark.Shellenbaum@Sun.COM 			aclp->z_ops.ace_flags_set(acep,
166512322SMark.Shellenbaum@Sun.COM 			    newflags|ACE_INHERITED_ACE);
1666789Sahrens 		}
1667789Sahrens 	}
1668789Sahrens 	return (aclp);
1669789Sahrens }
1670789Sahrens 
1671789Sahrens /*
1672789Sahrens  * Create file system object initial permissions
1673789Sahrens  * including inheritable ACEs.
1674789Sahrens  */
16759179SMark.Shellenbaum@Sun.COM int
zfs_acl_ids_create(znode_t * dzp,int flag,vattr_t * vap,cred_t * cr,vsecattr_t * vsecp,zfs_acl_ids_t * acl_ids)16769179SMark.Shellenbaum@Sun.COM zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
16779179SMark.Shellenbaum@Sun.COM     vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
1678789Sahrens {
1679789Sahrens 	int		error;
16809179SMark.Shellenbaum@Sun.COM 	zfsvfs_t	*zfsvfs = dzp->z_zfsvfs;
16815331Samw 	zfs_acl_t	*paclp;
16825959Smarks 	gid_t		gid;
16836385Smarks 	boolean_t	need_chmod = B_TRUE;
168411935SMark.Shellenbaum@Sun.COM 	boolean_t	inherited = B_FALSE;
16855331Samw 
16869179SMark.Shellenbaum@Sun.COM 	bzero(acl_ids, sizeof (zfs_acl_ids_t));
16879179SMark.Shellenbaum@Sun.COM 	acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);
1688789Sahrens 
16899179SMark.Shellenbaum@Sun.COM 	if (vsecp)
16909179SMark.Shellenbaum@Sun.COM 		if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr,
16919179SMark.Shellenbaum@Sun.COM 		    &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
16929179SMark.Shellenbaum@Sun.COM 			return (error);
1693789Sahrens 	/*
1694789Sahrens 	 * Determine uid and gid.
1695789Sahrens 	 */
169611249SMark.Shellenbaum@Sun.COM 	if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
1697789Sahrens 	    ((flag & IS_XATTR) && (vap->va_type == VDIR))) {
16989179SMark.Shellenbaum@Sun.COM 		acl_ids->z_fuid = zfs_fuid_create(zfsvfs,
16999179SMark.Shellenbaum@Sun.COM 		    (uint64_t)vap->va_uid, cr,
17009179SMark.Shellenbaum@Sun.COM 		    ZFS_OWNER, &acl_ids->z_fuidp);
17019179SMark.Shellenbaum@Sun.COM 		acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
17029179SMark.Shellenbaum@Sun.COM 		    (uint64_t)vap->va_gid, cr,
17039179SMark.Shellenbaum@Sun.COM 		    ZFS_GROUP, &acl_ids->z_fuidp);
17045959Smarks 		gid = vap->va_gid;
1705789Sahrens 	} else {
17069179SMark.Shellenbaum@Sun.COM 		acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
17079179SMark.Shellenbaum@Sun.COM 		    cr, &acl_ids->z_fuidp);
17089179SMark.Shellenbaum@Sun.COM 		acl_ids->z_fgid = 0;
17095959Smarks 		if (vap->va_mask & AT_GID)  {
17109179SMark.Shellenbaum@Sun.COM 			acl_ids->z_fgid = zfs_fuid_create(zfsvfs,
17119179SMark.Shellenbaum@Sun.COM 			    (uint64_t)vap->va_gid,
17129179SMark.Shellenbaum@Sun.COM 			    cr, ZFS_GROUP, &acl_ids->z_fuidp);
17135959Smarks 			gid = vap->va_gid;
171413069SMark.Shellenbaum@Oracle.COM 			if (acl_ids->z_fgid != dzp->z_gid &&
17155959Smarks 			    !groupmember(vap->va_gid, cr) &&
17165959Smarks 			    secpolicy_vnode_create_gid(cr) != 0)
17179179SMark.Shellenbaum@Sun.COM 				acl_ids->z_fgid = 0;
17185959Smarks 		}
17199179SMark.Shellenbaum@Sun.COM 		if (acl_ids->z_fgid == 0) {
172011935SMark.Shellenbaum@Sun.COM 			if (dzp->z_mode & S_ISGID) {
172111574SJohn.Harres@Sun.COM 				char		*domain;
172211574SJohn.Harres@Sun.COM 				uint32_t	rid;
172311574SJohn.Harres@Sun.COM 
172413069SMark.Shellenbaum@Oracle.COM 				acl_ids->z_fgid = dzp->z_gid;
17259179SMark.Shellenbaum@Sun.COM 				gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
17265959Smarks 				    cr, ZFS_GROUP);
172711574SJohn.Harres@Sun.COM 
172811574SJohn.Harres@Sun.COM 				if (zfsvfs->z_use_fuids &&
172911574SJohn.Harres@Sun.COM 				    IS_EPHEMERAL(acl_ids->z_fgid)) {
173011574SJohn.Harres@Sun.COM 					domain = zfs_fuid_idx_domain(
173111574SJohn.Harres@Sun.COM 					    &zfsvfs->z_fuid_idx,
173211574SJohn.Harres@Sun.COM 					    FUID_INDEX(acl_ids->z_fgid));
173311574SJohn.Harres@Sun.COM 					rid = FUID_RID(acl_ids->z_fgid);
173411574SJohn.Harres@Sun.COM 					zfs_fuid_node_add(&acl_ids->z_fuidp,
173511574SJohn.Harres@Sun.COM 					    domain, rid,
173611574SJohn.Harres@Sun.COM 					    FUID_INDEX(acl_ids->z_fgid),
173711574SJohn.Harres@Sun.COM 					    acl_ids->z_fgid, ZFS_GROUP);
173811574SJohn.Harres@Sun.COM 				}
17395959Smarks 			} else {
17409179SMark.Shellenbaum@Sun.COM 				acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs,
17419179SMark.Shellenbaum@Sun.COM 				    ZFS_GROUP, cr, &acl_ids->z_fuidp);
17425959Smarks 				gid = crgetgid(cr);
17435959Smarks 			}
17445331Samw 		}
1745789Sahrens 	}
1746789Sahrens 
1747789Sahrens 	/*
1748789Sahrens 	 * If we're creating a directory, and the parent directory has the
1749789Sahrens 	 * set-GID bit set, set in on the new directory.
1750789Sahrens 	 * Otherwise, if the user is neither privileged nor a member of the
1751789Sahrens 	 * file's new group, clear the file's set-GID bit.
1752789Sahrens 	 */
1753789Sahrens 
175411935SMark.Shellenbaum@Sun.COM 	if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
17559179SMark.Shellenbaum@Sun.COM 	    (vap->va_type == VDIR)) {
17569179SMark.Shellenbaum@Sun.COM 		acl_ids->z_mode |= S_ISGID;
17575959Smarks 	} else {
17589179SMark.Shellenbaum@Sun.COM 		if ((acl_ids->z_mode & S_ISGID) &&
1759789Sahrens 		    secpolicy_vnode_setids_setgids(cr, gid) != 0)
17609179SMark.Shellenbaum@Sun.COM 			acl_ids->z_mode &= ~S_ISGID;
1761789Sahrens 	}
1762789Sahrens 
17639179SMark.Shellenbaum@Sun.COM 	if (acl_ids->z_aclp == NULL) {
176412620SMark.Shellenbaum@Oracle.COM 		mutex_enter(&dzp->z_acl_lock);
17659179SMark.Shellenbaum@Sun.COM 		mutex_enter(&dzp->z_lock);
17669179SMark.Shellenbaum@Sun.COM 		if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR &&
176711935SMark.Shellenbaum@Sun.COM 		    (dzp->z_pflags & ZFS_INHERIT_ACE)) &&
176811935SMark.Shellenbaum@Sun.COM 		    !(dzp->z_pflags & ZFS_XATTR)) {
176912620SMark.Shellenbaum@Oracle.COM 			VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE,
177012620SMark.Shellenbaum@Oracle.COM 			    &paclp, B_FALSE));
17719179SMark.Shellenbaum@Sun.COM 			acl_ids->z_aclp = zfs_acl_inherit(zfsvfs,
17729179SMark.Shellenbaum@Sun.COM 			    vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
177311935SMark.Shellenbaum@Sun.COM 			inherited = B_TRUE;
17745331Samw 		} else {
17759179SMark.Shellenbaum@Sun.COM 			acl_ids->z_aclp =
17769179SMark.Shellenbaum@Sun.COM 			    zfs_acl_alloc(zfs_acl_version_zp(dzp));
177711935SMark.Shellenbaum@Sun.COM 			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
17785331Samw 		}
17799179SMark.Shellenbaum@Sun.COM 		mutex_exit(&dzp->z_lock);
178012620SMark.Shellenbaum@Oracle.COM 		mutex_exit(&dzp->z_acl_lock);
17819179SMark.Shellenbaum@Sun.COM 		if (need_chmod) {
178211935SMark.Shellenbaum@Sun.COM 			acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ?
17839179SMark.Shellenbaum@Sun.COM 			    ZFS_ACL_AUTO_INHERIT : 0;
178412164SMark.Shellenbaum@Sun.COM 			zfs_acl_chmod(zfsvfs, acl_ids->z_mode, acl_ids->z_aclp);
17859179SMark.Shellenbaum@Sun.COM 		}
1786789Sahrens 	}
17875331Samw 
178811935SMark.Shellenbaum@Sun.COM 	if (inherited || vsecp) {
178911935SMark.Shellenbaum@Sun.COM 		acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
179012164SMark.Shellenbaum@Sun.COM 		    acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
179112164SMark.Shellenbaum@Sun.COM 		    acl_ids->z_fuid, acl_ids->z_fgid);
179211935SMark.Shellenbaum@Sun.COM 		if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0)
179311935SMark.Shellenbaum@Sun.COM 			acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
179411935SMark.Shellenbaum@Sun.COM 	}
179511935SMark.Shellenbaum@Sun.COM 
17969179SMark.Shellenbaum@Sun.COM 	return (0);
17979179SMark.Shellenbaum@Sun.COM }
17985331Samw 
17999179SMark.Shellenbaum@Sun.COM /*
18009179SMark.Shellenbaum@Sun.COM  * Free ACL and fuid_infop, but not the acl_ids structure
18019179SMark.Shellenbaum@Sun.COM  */
18029179SMark.Shellenbaum@Sun.COM void
zfs_acl_ids_free(zfs_acl_ids_t * acl_ids)18039179SMark.Shellenbaum@Sun.COM zfs_acl_ids_free(zfs_acl_ids_t *acl_ids)
18049179SMark.Shellenbaum@Sun.COM {
18059179SMark.Shellenbaum@Sun.COM 	if (acl_ids->z_aclp)
18069179SMark.Shellenbaum@Sun.COM 		zfs_acl_free(acl_ids->z_aclp);
18079179SMark.Shellenbaum@Sun.COM 	if (acl_ids->z_fuidp)
18089179SMark.Shellenbaum@Sun.COM 		zfs_fuid_info_free(acl_ids->z_fuidp);
18099179SMark.Shellenbaum@Sun.COM 	acl_ids->z_aclp = NULL;
18109179SMark.Shellenbaum@Sun.COM 	acl_ids->z_fuidp = NULL;
18119179SMark.Shellenbaum@Sun.COM }
18125331Samw 
18139396SMatthew.Ahrens@Sun.COM boolean_t
zfs_acl_ids_overquota(zfsvfs_t * zfsvfs,zfs_acl_ids_t * acl_ids)18149396SMatthew.Ahrens@Sun.COM zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids)
18159396SMatthew.Ahrens@Sun.COM {
181611935SMark.Shellenbaum@Sun.COM 	return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) ||
181711935SMark.Shellenbaum@Sun.COM 	    zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid));
18189396SMatthew.Ahrens@Sun.COM }
1819789Sahrens 
1820789Sahrens /*
1821789Sahrens  * Retrieve a files ACL
1822789Sahrens  */
1823789Sahrens int
zfs_getacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)18245331Samw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1825789Sahrens {
1826789Sahrens 	zfs_acl_t	*aclp;
18275331Samw 	ulong_t		mask;
1828789Sahrens 	int		error;
18295331Samw 	int 		count = 0;
18305331Samw 	int		largeace = 0;
1831789Sahrens 
18325331Samw 	mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT |
18335331Samw 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
18345331Samw 
183511935SMark.Shellenbaum@Sun.COM 	if (mask == 0)
183611935SMark.Shellenbaum@Sun.COM 		return (ENOSYS);
183711935SMark.Shellenbaum@Sun.COM 
18385331Samw 	if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
18395331Samw 		return (error);
1840789Sahrens 
1841789Sahrens 	mutex_enter(&zp->z_acl_lock);
1842789Sahrens 
184312620SMark.Shellenbaum@Oracle.COM 	error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
18441544Seschrock 	if (error != 0) {
18451544Seschrock 		mutex_exit(&zp->z_acl_lock);
18461544Seschrock 		return (error);
18471544Seschrock 	}
18481544Seschrock 
18495331Samw 	/*
18505331Samw 	 * Scan ACL to determine number of ACEs
18515331Samw 	 */
185211935SMark.Shellenbaum@Sun.COM 	if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) {
18535331Samw 		void *zacep = NULL;
18545331Samw 		uint64_t who;
18555331Samw 		uint32_t access_mask;
18565331Samw 		uint16_t type, iflags;
18575331Samw 
18585331Samw 		while (zacep = zfs_acl_next_ace(aclp, zacep,
18595331Samw 		    &who, &access_mask, &iflags, &type)) {
18605331Samw 			switch (type) {
18615331Samw 			case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
18625331Samw 			case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
18635331Samw 			case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
18645331Samw 			case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
18655331Samw 				largeace++;
18665331Samw 				continue;
18675331Samw 			default:
18685331Samw 				count++;
18695331Samw 			}
18705331Samw 		}
18715331Samw 		vsecp->vsa_aclcnt = count;
18725331Samw 	} else
187311935SMark.Shellenbaum@Sun.COM 		count = (int)aclp->z_acl_count;
1874789Sahrens 
1875789Sahrens 	if (mask & VSA_ACECNT) {
18765331Samw 		vsecp->vsa_aclcnt = count;
1877789Sahrens 	}
1878789Sahrens 
1879789Sahrens 	if (mask & VSA_ACE) {
18805331Samw 		size_t aclsz;
18815331Samw 
18825331Samw 		aclsz = count * sizeof (ace_t) +
18835331Samw 		    sizeof (ace_object_t) * largeace;
18845331Samw 
18855331Samw 		vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP);
18865331Samw 		vsecp->vsa_aclentsz = aclsz;
18875331Samw 
18885331Samw 		if (aclp->z_version == ZFS_ACL_VERSION_FUID)
18895771Sjp151216 			zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr,
18905331Samw 			    vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES));
18915331Samw 		else {
189210295SMark.Shellenbaum@Sun.COM 			zfs_acl_node_t *aclnode;
189310295SMark.Shellenbaum@Sun.COM 			void *start = vsecp->vsa_aclentp;
189410295SMark.Shellenbaum@Sun.COM 
189510295SMark.Shellenbaum@Sun.COM 			for (aclnode = list_head(&aclp->z_acl); aclnode;
189610295SMark.Shellenbaum@Sun.COM 			    aclnode = list_next(&aclp->z_acl, aclnode)) {
189710295SMark.Shellenbaum@Sun.COM 				bcopy(aclnode->z_acldata, start,
189810295SMark.Shellenbaum@Sun.COM 				    aclnode->z_size);
189910295SMark.Shellenbaum@Sun.COM 				start = (caddr_t)start + aclnode->z_size;
190010295SMark.Shellenbaum@Sun.COM 			}
190110295SMark.Shellenbaum@Sun.COM 			ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp ==
190210295SMark.Shellenbaum@Sun.COM 			    aclp->z_acl_bytes);
19035331Samw 		}
19045331Samw 	}
19055331Samw 	if (mask & VSA_ACE_ACLFLAGS) {
19065331Samw 		vsecp->vsa_aclflags = 0;
190711935SMark.Shellenbaum@Sun.COM 		if (zp->z_pflags & ZFS_ACL_DEFAULTED)
19085331Samw 			vsecp->vsa_aclflags |= ACL_DEFAULTED;
190911935SMark.Shellenbaum@Sun.COM 		if (zp->z_pflags & ZFS_ACL_PROTECTED)
19105331Samw 			vsecp->vsa_aclflags |= ACL_PROTECTED;
191111935SMark.Shellenbaum@Sun.COM 		if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT)
19125331Samw 			vsecp->vsa_aclflags |= ACL_AUTO_INHERIT;
1913789Sahrens 	}
1914789Sahrens 
1915789Sahrens 	mutex_exit(&zp->z_acl_lock);
1916789Sahrens 
1917789Sahrens 	return (0);
1918789Sahrens }
1919789Sahrens 
19205331Samw int
zfs_vsec_2_aclp(zfsvfs_t * zfsvfs,vtype_t obj_type,vsecattr_t * vsecp,cred_t * cr,zfs_fuid_info_t ** fuidp,zfs_acl_t ** zaclp)19215331Samw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type,
19229179SMark.Shellenbaum@Sun.COM     vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp)
19235331Samw {
19245331Samw 	zfs_acl_t *aclp;
19255331Samw 	zfs_acl_node_t *aclnode;
19265331Samw 	int aclcnt = vsecp->vsa_aclcnt;
19275331Samw 	int error;
19285331Samw 
19295331Samw 	if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
19305331Samw 		return (EINVAL);
19315331Samw 
19325331Samw 	aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
19335331Samw 
19345331Samw 	aclp->z_hints = 0;
19355331Samw 	aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
19365331Samw 	if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
19375331Samw 		if ((error = zfs_copy_ace_2_oldace(obj_type, aclp,
19385331Samw 		    (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata,
19395331Samw 		    aclcnt, &aclnode->z_size)) != 0) {
19405331Samw 			zfs_acl_free(aclp);
19415331Samw 			zfs_acl_node_free(aclnode);
19425331Samw 			return (error);
19435331Samw 		}
19445331Samw 	} else {
19459179SMark.Shellenbaum@Sun.COM 		if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp,
19465331Samw 		    vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt,
19479179SMark.Shellenbaum@Sun.COM 		    &aclnode->z_size, fuidp, cr)) != 0) {
19485331Samw 			zfs_acl_free(aclp);
19495331Samw 			zfs_acl_node_free(aclnode);
19505331Samw 			return (error);
19515331Samw 		}
19525331Samw 	}
19535331Samw 	aclp->z_acl_bytes = aclnode->z_size;
19545331Samw 	aclnode->z_ace_count = aclcnt;
19555331Samw 	aclp->z_acl_count = aclcnt;
19565331Samw 	list_insert_head(&aclp->z_acl, aclnode);
19575331Samw 
19585331Samw 	/*
19595331Samw 	 * If flags are being set then add them to z_hints
19605331Samw 	 */
19615331Samw 	if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) {
19625331Samw 		if (vsecp->vsa_aclflags & ACL_PROTECTED)
19635331Samw 			aclp->z_hints |= ZFS_ACL_PROTECTED;
19645331Samw 		if (vsecp->vsa_aclflags & ACL_DEFAULTED)
19655331Samw 			aclp->z_hints |= ZFS_ACL_DEFAULTED;
19665331Samw 		if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT)
19675331Samw 			aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
19685331Samw 	}
19695331Samw 
19705331Samw 	*zaclp = aclp;
19715331Samw 
19725331Samw 	return (0);
19735331Samw }
19745331Samw 
1975789Sahrens /*
1976789Sahrens  * Set a files ACL
1977789Sahrens  */
1978789Sahrens int
zfs_setacl(znode_t * zp,vsecattr_t * vsecp,boolean_t skipaclchk,cred_t * cr)19795331Samw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
1980789Sahrens {
1981789Sahrens 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
1982789Sahrens 	zilog_t		*zilog = zfsvfs->z_log;
1983789Sahrens 	ulong_t		mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
1984789Sahrens 	dmu_tx_t	*tx;
1985789Sahrens 	int		error;
1986789Sahrens 	zfs_acl_t	*aclp;
19875331Samw 	zfs_fuid_info_t	*fuidp = NULL;
19889179SMark.Shellenbaum@Sun.COM 	boolean_t	fuid_dirtied;
198912620SMark.Shellenbaum@Oracle.COM 	uint64_t	acl_obj;
1990789Sahrens 
1991789Sahrens 	if (mask == 0)
19924300Smarks 		return (ENOSYS);
1993789Sahrens 
199411935SMark.Shellenbaum@Sun.COM 	if (zp->z_pflags & ZFS_IMMUTABLE)
19955331Samw 		return (EPERM);
19965331Samw 
19975331Samw 	if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
19985331Samw 		return (error);
19995331Samw 
20009179SMark.Shellenbaum@Sun.COM 	error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
20019179SMark.Shellenbaum@Sun.COM 	    &aclp);
20025331Samw 	if (error)
20035331Samw 		return (error);
20045331Samw 
20055331Samw 	/*
20065331Samw 	 * If ACL wide flags aren't being set then preserve any
20075331Samw 	 * existing flags.
20085331Samw 	 */
20095331Samw 	if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) {
201011935SMark.Shellenbaum@Sun.COM 		aclp->z_hints |=
201111935SMark.Shellenbaum@Sun.COM 		    (zp->z_pflags & V4_ACL_WIDE_FLAGS);
20125331Samw 	}
2013789Sahrens top:
201412620SMark.Shellenbaum@Oracle.COM 	mutex_enter(&zp->z_acl_lock);
2015789Sahrens 	mutex_enter(&zp->z_lock);
2016789Sahrens 
2017789Sahrens 	tx = dmu_tx_create(zfsvfs->z_os);
201811935SMark.Shellenbaum@Sun.COM 
201911935SMark.Shellenbaum@Sun.COM 	dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
202011935SMark.Shellenbaum@Sun.COM 
20219179SMark.Shellenbaum@Sun.COM 	fuid_dirtied = zfsvfs->z_fuid_dirty;
20229396SMatthew.Ahrens@Sun.COM 	if (fuid_dirtied)
20239396SMatthew.Ahrens@Sun.COM 		zfs_fuid_txhold(zfsvfs, tx);
2024789Sahrens 
202511935SMark.Shellenbaum@Sun.COM 	/*
202611935SMark.Shellenbaum@Sun.COM 	 * If old version and ACL won't fit in bonus and we aren't
202711935SMark.Shellenbaum@Sun.COM 	 * upgrading then take out necessary DMU holds
202811935SMark.Shellenbaum@Sun.COM 	 */
202911935SMark.Shellenbaum@Sun.COM 
203012620SMark.Shellenbaum@Oracle.COM 	if ((acl_obj = zfs_external_acl(zp)) != 0) {
203113046SMark.Shellenbaum@Oracle.COM 		if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
203212620SMark.Shellenbaum@Oracle.COM 		    zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
203312620SMark.Shellenbaum@Oracle.COM 			dmu_tx_hold_free(tx, acl_obj, 0,
203411935SMark.Shellenbaum@Sun.COM 			    DMU_OBJECT_END);
203513046SMark.Shellenbaum@Oracle.COM 			dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
203613046SMark.Shellenbaum@Oracle.COM 			    aclp->z_acl_bytes);
203711935SMark.Shellenbaum@Sun.COM 		} else {
203812620SMark.Shellenbaum@Oracle.COM 			dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
203911935SMark.Shellenbaum@Sun.COM 		}
204011935SMark.Shellenbaum@Sun.COM 	} else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
204111935SMark.Shellenbaum@Sun.COM 		dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
204211935SMark.Shellenbaum@Sun.COM 	}
204311935SMark.Shellenbaum@Sun.COM 
204411935SMark.Shellenbaum@Sun.COM 	zfs_sa_upgrade_txholds(tx, zp);
20458227SNeil.Perrin@Sun.COM 	error = dmu_tx_assign(tx, TXG_NOWAIT);
2046789Sahrens 	if (error) {
2047789Sahrens 		mutex_exit(&zp->z_acl_lock);
2048789Sahrens 		mutex_exit(&zp->z_lock);
2049789Sahrens 
20508227SNeil.Perrin@Sun.COM 		if (error == ERESTART) {
20512113Sahrens 			dmu_tx_wait(tx);
20522113Sahrens 			dmu_tx_abort(tx);
2053789Sahrens 			goto top;
2054789Sahrens 		}
20552113Sahrens 		dmu_tx_abort(tx);
20565331Samw 		zfs_acl_free(aclp);
2057789Sahrens 		return (error);
2058789Sahrens 	}
2059789Sahrens 
20609179SMark.Shellenbaum@Sun.COM 	error = zfs_aclset_common(zp, aclp, cr, tx);
2061789Sahrens 	ASSERT(error == 0);
2062*13089SMark.Shellenbaum@Oracle.COM 	ASSERT(zp->z_acl_cached == NULL);
206310143STim.Haley@Sun.COM 	zp->z_acl_cached = aclp;
2064789Sahrens 
20659179SMark.Shellenbaum@Sun.COM 	if (fuid_dirtied)
20669179SMark.Shellenbaum@Sun.COM 		zfs_fuid_sync(zfsvfs, tx);
20679179SMark.Shellenbaum@Sun.COM 
20685331Samw 	zfs_log_acl(zilog, tx, zp, vsecp, fuidp);
20695331Samw 
20705331Samw 	if (fuidp)
20715331Samw 		zfs_fuid_info_free(fuidp);
2072789Sahrens 	dmu_tx_commit(tx);
2073789Sahrens done:
207412620SMark.Shellenbaum@Oracle.COM 	mutex_exit(&zp->z_lock);
2075789Sahrens 	mutex_exit(&zp->z_acl_lock);
2076789Sahrens 
2077789Sahrens 	return (error);
2078789Sahrens }
2079789Sahrens 
20805331Samw /*
20819749STim.Haley@Sun.COM  * Check accesses of interest (AoI) against attributes of the dataset
20829749STim.Haley@Sun.COM  * such as read-only.  Returns zero if no AoI conflict with dataset
20839749STim.Haley@Sun.COM  * attributes, otherwise an appropriate errno is returned.
20845331Samw  */
2085789Sahrens static int
zfs_zaccess_dataset_check(znode_t * zp,uint32_t v4_mode)20869749STim.Haley@Sun.COM zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
2087789Sahrens {
20889749STim.Haley@Sun.COM 	if ((v4_mode & WRITE_MASK) &&
20899749STim.Haley@Sun.COM 	    (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) &&
20909749STim.Haley@Sun.COM 	    (!IS_DEVVP(ZTOV(zp)) ||
20919749STim.Haley@Sun.COM 	    (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
20929749STim.Haley@Sun.COM 		return (EROFS);
20939749STim.Haley@Sun.COM 	}
20949749STim.Haley@Sun.COM 
20959749STim.Haley@Sun.COM 	/*
20969749STim.Haley@Sun.COM 	 * Only check for READONLY on non-directories.
20979749STim.Haley@Sun.COM 	 */
20989749STim.Haley@Sun.COM 	if ((v4_mode & WRITE_MASK_DATA) &&
20999749STim.Haley@Sun.COM 	    (((ZTOV(zp)->v_type != VDIR) &&
210011935SMark.Shellenbaum@Sun.COM 	    (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
21019749STim.Haley@Sun.COM 	    (ZTOV(zp)->v_type == VDIR &&
210211935SMark.Shellenbaum@Sun.COM 	    (zp->z_pflags & ZFS_IMMUTABLE)))) {
21039749STim.Haley@Sun.COM 		return (EPERM);
21049749STim.Haley@Sun.COM 	}
21059749STim.Haley@Sun.COM 
21069749STim.Haley@Sun.COM 	if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) &&
210711935SMark.Shellenbaum@Sun.COM 	    (zp->z_pflags & ZFS_NOUNLINK)) {
21089749STim.Haley@Sun.COM 		return (EPERM);
21099749STim.Haley@Sun.COM 	}
21109749STim.Haley@Sun.COM 
21119749STim.Haley@Sun.COM 	if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) &&
211211935SMark.Shellenbaum@Sun.COM 	    (zp->z_pflags & ZFS_AV_QUARANTINED))) {
21139749STim.Haley@Sun.COM 		return (EACCES);
21149749STim.Haley@Sun.COM 	}
21159749STim.Haley@Sun.COM 
21169749STim.Haley@Sun.COM 	return (0);
21179749STim.Haley@Sun.COM }
21189749STim.Haley@Sun.COM 
21199749STim.Haley@Sun.COM /*
21209749STim.Haley@Sun.COM  * The primary usage of this function is to loop through all of the
21219749STim.Haley@Sun.COM  * ACEs in the znode, determining what accesses of interest (AoI) to
21229749STim.Haley@Sun.COM  * the caller are allowed or denied.  The AoI are expressed as bits in
21239749STim.Haley@Sun.COM  * the working_mode parameter.  As each ACE is processed, bits covered
21249749STim.Haley@Sun.COM  * by that ACE are removed from the working_mode.  This removal
21259749STim.Haley@Sun.COM  * facilitates two things.  The first is that when the working mode is
21269749STim.Haley@Sun.COM  * empty (= 0), we know we've looked at all the AoI. The second is
21279749STim.Haley@Sun.COM  * that the ACE interpretation rules don't allow a later ACE to undo
21289749STim.Haley@Sun.COM  * something granted or denied by an earlier ACE.  Removing the
21299749STim.Haley@Sun.COM  * discovered access or denial enforces this rule.  At the end of
21309749STim.Haley@Sun.COM  * processing the ACEs, all AoI that were found to be denied are
21319749STim.Haley@Sun.COM  * placed into the working_mode, giving the caller a mask of denied
21329749STim.Haley@Sun.COM  * accesses.  Returns:
21339749STim.Haley@Sun.COM  *	0		if all AoI granted
21349749STim.Haley@Sun.COM  *	EACCESS 	if the denied mask is non-zero
21359749STim.Haley@Sun.COM  *	other error	if abnormal failure (e.g., IO error)
21369749STim.Haley@Sun.COM  *
21379749STim.Haley@Sun.COM  * A secondary usage of the function is to determine if any of the
21389749STim.Haley@Sun.COM  * AoI are granted.  If an ACE grants any access in
21399749STim.Haley@Sun.COM  * the working_mode, we immediately short circuit out of the function.
21409749STim.Haley@Sun.COM  * This mode is chosen by setting anyaccess to B_TRUE.  The
21419749STim.Haley@Sun.COM  * working_mode is not a denied access mask upon exit if the function
21429749STim.Haley@Sun.COM  * is used in this manner.
21439749STim.Haley@Sun.COM  */
21449749STim.Haley@Sun.COM static int
zfs_zaccess_aces_check(znode_t * zp,uint32_t * working_mode,boolean_t anyaccess,cred_t * cr)21459749STim.Haley@Sun.COM zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
21469749STim.Haley@Sun.COM     boolean_t anyaccess, cred_t *cr)
21479749STim.Haley@Sun.COM {
21489749STim.Haley@Sun.COM 	zfsvfs_t	*zfsvfs = zp->z_zfsvfs;
2149789Sahrens 	zfs_acl_t	*aclp;
21501544Seschrock 	int		error;
2151789Sahrens 	uid_t		uid = crgetuid(cr);
21525331Samw 	uint64_t 	who;
21535331Samw 	uint16_t	type, iflags;
21545331Samw 	uint16_t	entry_type;
21555331Samw 	uint32_t	access_mask;
21566056Smarks 	uint32_t	deny_mask = 0;
21575331Samw 	zfs_ace_hdr_t	*acep = NULL;
21585331Samw 	boolean_t	checkit;
215913069SMark.Shellenbaum@Oracle.COM 	uid_t		gowner;
216013069SMark.Shellenbaum@Oracle.COM 	uid_t		fowner;
216113069SMark.Shellenbaum@Oracle.COM 
216213069SMark.Shellenbaum@Oracle.COM 	zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
21635331Samw 
2164789Sahrens 	mutex_enter(&zp->z_acl_lock);
2165789Sahrens 
216612620SMark.Shellenbaum@Oracle.COM 	error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
21671544Seschrock 	if (error != 0) {
21681544Seschrock 		mutex_exit(&zp->z_acl_lock);
21691544Seschrock 		return (error);
21701544Seschrock 	}
21711544Seschrock 
217211935SMark.Shellenbaum@Sun.COM 	ASSERT(zp->z_acl_cached);
217311935SMark.Shellenbaum@Sun.COM 
21745331Samw 	while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
21755331Samw 	    &iflags, &type)) {
21769749STim.Haley@Sun.COM 		uint32_t mask_matched;
2177789Sahrens 
21787559SMark.Shellenbaum@Sun.COM 		if (!zfs_acl_valid_ace_type(type, iflags))
21797559SMark.Shellenbaum@Sun.COM 			continue;
21807559SMark.Shellenbaum@Sun.COM 
21817057Smarks 		if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
2182789Sahrens 			continue;
2183789Sahrens 
21849749STim.Haley@Sun.COM 		/* Skip ACE if it does not affect any AoI */
21859749STim.Haley@Sun.COM 		mask_matched = (access_mask & *working_mode);
21869749STim.Haley@Sun.COM 		if (!mask_matched)
21879749STim.Haley@Sun.COM 			continue;
21889749STim.Haley@Sun.COM 
21895331Samw 		entry_type = (iflags & ACE_TYPE_FLAGS);
21905331Samw 
21915331Samw 		checkit = B_FALSE;
21925331Samw 
2193789Sahrens 		switch (entry_type) {
2194789Sahrens 		case ACE_OWNER:
219513069SMark.Shellenbaum@Oracle.COM 			if (uid == fowner)
21965331Samw 				checkit = B_TRUE;
2197789Sahrens 			break;
21985331Samw 		case OWNING_GROUP:
21995331Samw 			who = gowner;
22005331Samw 			/*FALLTHROUGH*/
2201789Sahrens 		case ACE_IDENTIFIER_GROUP:
22025331Samw 			checkit = zfs_groupmember(zfsvfs, who, cr);
2203789Sahrens 			break;
2204789Sahrens 		case ACE_EVERYONE:
22055331Samw 			checkit = B_TRUE;
2206789Sahrens 			break;
2207789Sahrens 
2208789Sahrens 		/* USER Entry */
2209789Sahrens 		default:
2210789Sahrens 			if (entry_type == 0) {
22115331Samw 				uid_t newid;
22125331Samw 
22135959Smarks 				newid = zfs_fuid_map_id(zfsvfs, who, cr,
22145959Smarks 				    ZFS_ACE_USER);
22155331Samw 				if (newid != IDMAP_WK_CREATOR_OWNER_UID &&
22165331Samw 				    uid == newid)
22175331Samw 					checkit = B_TRUE;
2218789Sahrens 				break;
22195331Samw 			} else {
22205331Samw 				mutex_exit(&zp->z_acl_lock);
22215331Samw 				return (EIO);
2222789Sahrens 			}
22235331Samw 		}
22245331Samw 
22255331Samw 		if (checkit) {
22269749STim.Haley@Sun.COM 			if (type == DENY) {
22279749STim.Haley@Sun.COM 				DTRACE_PROBE3(zfs__ace__denies,
22289749STim.Haley@Sun.COM 				    znode_t *, zp,
22299749STim.Haley@Sun.COM 				    zfs_ace_hdr_t *, acep,
22309749STim.Haley@Sun.COM 				    uint32_t, mask_matched);
22319749STim.Haley@Sun.COM 				deny_mask |= mask_matched;
22329749STim.Haley@Sun.COM 			} else {
22339749STim.Haley@Sun.COM 				DTRACE_PROBE3(zfs__ace__allows,
22349749STim.Haley@Sun.COM 				    znode_t *, zp,
22359749STim.Haley@Sun.COM 				    zfs_ace_hdr_t *, acep,
22369749STim.Haley@Sun.COM 				    uint32_t, mask_matched);
22379749STim.Haley@Sun.COM 				if (anyaccess) {
22389749STim.Haley@Sun.COM 					mutex_exit(&zp->z_acl_lock);
22399749STim.Haley@Sun.COM 					return (0);
22409749STim.Haley@Sun.COM 				}
22415331Samw 			}
22429749STim.Haley@Sun.COM 			*working_mode &= ~mask_matched;
2243789Sahrens 		}
2244789Sahrens 
22456056Smarks 		/* Are we done? */
22466056Smarks 		if (*working_mode == 0)
2247789Sahrens 			break;
2248789Sahrens 	}
2249789Sahrens 
2250789Sahrens 	mutex_exit(&zp->z_acl_lock);
22516056Smarks 
22526056Smarks 	/* Put the found 'denies' back on the working mode */
22537163Smarks 	if (deny_mask) {
22547163Smarks 		*working_mode |= deny_mask;
22556056Smarks 		return (EACCES);
22567163Smarks 	} else if (*working_mode) {
22577163Smarks 		return (-1);
22587163Smarks 	}
22596056Smarks 
22606056Smarks 	return (0);
2261789Sahrens }
2262789Sahrens 
22639749STim.Haley@Sun.COM /*
22649749STim.Haley@Sun.COM  * Return true if any access whatsoever granted, we don't actually
22659749STim.Haley@Sun.COM  * care what access is granted.
22669749STim.Haley@Sun.COM  */
22679749STim.Haley@Sun.COM boolean_t
zfs_has_access(znode_t * zp,cred_t * cr)22689749STim.Haley@Sun.COM zfs_has_access(znode_t *zp, cred_t *cr)
22699749STim.Haley@Sun.COM {
22709749STim.Haley@Sun.COM 	uint32_t have = ACE_ALL_PERMS;
22719749STim.Haley@Sun.COM 
22729749STim.Haley@Sun.COM 	if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
227313069SMark.Shellenbaum@Oracle.COM 		uid_t owner;
227413069SMark.Shellenbaum@Oracle.COM 
227513069SMark.Shellenbaum@Oracle.COM 		owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
227613069SMark.Shellenbaum@Oracle.COM 		return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0);
22779749STim.Haley@Sun.COM 	}
22789749STim.Haley@Sun.COM 	return (B_TRUE);
22799749STim.Haley@Sun.COM }
22809749STim.Haley@Sun.COM 
22819749STim.Haley@Sun.COM static int
zfs_zaccess_common(znode_t * zp,uint32_t v4_mode,uint32_t * working_mode,boolean_t * check_privs,boolean_t skipaclchk,cred_t * cr)22829749STim.Haley@Sun.COM zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
22839749STim.Haley@Sun.COM     boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
22849749STim.Haley@Sun.COM {
22859749STim.Haley@Sun.COM 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
22869749STim.Haley@Sun.COM 	int err;
22879749STim.Haley@Sun.COM 
22889749STim.Haley@Sun.COM 	*working_mode = v4_mode;
22899749STim.Haley@Sun.COM 	*check_privs = B_TRUE;
22909749STim.Haley@Sun.COM 
22919749STim.Haley@Sun.COM 	/*
22929749STim.Haley@Sun.COM 	 * Short circuit empty requests
22939749STim.Haley@Sun.COM 	 */
22949749STim.Haley@Sun.COM 	if (v4_mode == 0 || zfsvfs->z_replay) {
22959749STim.Haley@Sun.COM 		*working_mode = 0;
22969749STim.Haley@Sun.COM 		return (0);
22979749STim.Haley@Sun.COM 	}
22989749STim.Haley@Sun.COM 
22999749STim.Haley@Sun.COM 	if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) {
23009749STim.Haley@Sun.COM 		*check_privs = B_FALSE;
23019749STim.Haley@Sun.COM 		return (err);
23029749STim.Haley@Sun.COM 	}
23039749STim.Haley@Sun.COM 
23049749STim.Haley@Sun.COM 	/*
23059749STim.Haley@Sun.COM 	 * The caller requested that the ACL check be skipped.  This
23069749STim.Haley@Sun.COM 	 * would only happen if the caller checked VOP_ACCESS() with a
23079749STim.Haley@Sun.COM 	 * 32 bit ACE mask and already had the appropriate permissions.
23089749STim.Haley@Sun.COM 	 */
23099749STim.Haley@Sun.COM 	if (skipaclchk) {
23109749STim.Haley@Sun.COM 		*working_mode = 0;
23119749STim.Haley@Sun.COM 		return (0);
23129749STim.Haley@Sun.COM 	}
23139749STim.Haley@Sun.COM 
23149749STim.Haley@Sun.COM 	return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
23159749STim.Haley@Sun.COM }
23169749STim.Haley@Sun.COM 
23175331Samw static int
zfs_zaccess_append(znode_t * zp,uint32_t * working_mode,boolean_t * check_privs,cred_t * cr)23185331Samw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
23195331Samw     cred_t *cr)
23205331Samw {
23215331Samw 	if (*working_mode != ACE_WRITE_DATA)
23225331Samw 		return (EACCES);
23235331Samw 
23245331Samw 	return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
23255331Samw 	    check_privs, B_FALSE, cr));
23265331Samw }
2327789Sahrens 
23289981STim.Haley@Sun.COM int
zfs_fastaccesschk_execute(znode_t * zdp,cred_t * cr)23299981STim.Haley@Sun.COM zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
23309981STim.Haley@Sun.COM {
23319981STim.Haley@Sun.COM 	boolean_t owner = B_FALSE;
23329981STim.Haley@Sun.COM 	boolean_t groupmbr = B_FALSE;
23339981STim.Haley@Sun.COM 	boolean_t is_attr;
23349981STim.Haley@Sun.COM 	uid_t uid = crgetuid(cr);
23359981STim.Haley@Sun.COM 	int error;
23369981STim.Haley@Sun.COM 
233711935SMark.Shellenbaum@Sun.COM 	if (zdp->z_pflags & ZFS_AV_QUARANTINED)
23389981STim.Haley@Sun.COM 		return (EACCES);
23399981STim.Haley@Sun.COM 
234011935SMark.Shellenbaum@Sun.COM 	is_attr = ((zdp->z_pflags & ZFS_XATTR) &&
23419981STim.Haley@Sun.COM 	    (ZTOV(zdp)->v_type == VDIR));
23429981STim.Haley@Sun.COM 	if (is_attr)
23439981STim.Haley@Sun.COM 		goto slow;
23449981STim.Haley@Sun.COM 
234511935SMark.Shellenbaum@Sun.COM 
23469981STim.Haley@Sun.COM 	mutex_enter(&zdp->z_acl_lock);
23479981STim.Haley@Sun.COM 
234811935SMark.Shellenbaum@Sun.COM 	if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) {
23499981STim.Haley@Sun.COM 		mutex_exit(&zdp->z_acl_lock);
23509981STim.Haley@Sun.COM 		return (0);
23519981STim.Haley@Sun.COM 	}
23529981STim.Haley@Sun.COM 
235313069SMark.Shellenbaum@Oracle.COM 	if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
23549981STim.Haley@Sun.COM 		mutex_exit(&zdp->z_acl_lock);
23559981STim.Haley@Sun.COM 		goto slow;
23569981STim.Haley@Sun.COM 	}
23579981STim.Haley@Sun.COM 
235811935SMark.Shellenbaum@Sun.COM 	if (uid == zdp->z_uid) {
23599981STim.Haley@Sun.COM 		owner = B_TRUE;
236011935SMark.Shellenbaum@Sun.COM 		if (zdp->z_mode & S_IXUSR) {
23619981STim.Haley@Sun.COM 			mutex_exit(&zdp->z_acl_lock);
23629981STim.Haley@Sun.COM 			return (0);
236310232STim.Haley@Sun.COM 		} else {
236410232STim.Haley@Sun.COM 			mutex_exit(&zdp->z_acl_lock);
236510232STim.Haley@Sun.COM 			goto slow;
23669981STim.Haley@Sun.COM 		}
23679981STim.Haley@Sun.COM 	}
236811935SMark.Shellenbaum@Sun.COM 	if (groupmember(zdp->z_gid, cr)) {
23699981STim.Haley@Sun.COM 		groupmbr = B_TRUE;
237011935SMark.Shellenbaum@Sun.COM 		if (zdp->z_mode & S_IXGRP) {
23719981STim.Haley@Sun.COM 			mutex_exit(&zdp->z_acl_lock);
23729981STim.Haley@Sun.COM 			return (0);
237310232STim.Haley@Sun.COM 		} else {
237410232STim.Haley@Sun.COM 			mutex_exit(&zdp->z_acl_lock);
237510232STim.Haley@Sun.COM 			goto slow;
23769981STim.Haley@Sun.COM 		}
23779981STim.Haley@Sun.COM 	}
23789981STim.Haley@Sun.COM 	if (!owner && !groupmbr) {
237911935SMark.Shellenbaum@Sun.COM 		if (zdp->z_mode & S_IXOTH) {
23809981STim.Haley@Sun.COM 			mutex_exit(&zdp->z_acl_lock);
23819981STim.Haley@Sun.COM 			return (0);
23829981STim.Haley@Sun.COM 		}
23839981STim.Haley@Sun.COM 	}
23849981STim.Haley@Sun.COM 
23859981STim.Haley@Sun.COM 	mutex_exit(&zdp->z_acl_lock);
23869981STim.Haley@Sun.COM 
23879981STim.Haley@Sun.COM slow:
23889981STim.Haley@Sun.COM 	DTRACE_PROBE(zfs__fastpath__execute__access__miss);
23899981STim.Haley@Sun.COM 	ZFS_ENTER(zdp->z_zfsvfs);
23909981STim.Haley@Sun.COM 	error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
23919981STim.Haley@Sun.COM 	ZFS_EXIT(zdp->z_zfsvfs);
23929981STim.Haley@Sun.COM 	return (error);
23939981STim.Haley@Sun.COM }
23949981STim.Haley@Sun.COM 
2395789Sahrens /*
239612273SCasper.Dik@Sun.COM  * Determine whether Access should be granted/denied.
239712273SCasper.Dik@Sun.COM  * The least priv subsytem is always consulted as a basic privilege
239812273SCasper.Dik@Sun.COM  * can define any form of access.
2399789Sahrens  */
2400789Sahrens int
zfs_zaccess(znode_t * zp,int mode,int flags,boolean_t skipaclchk,cred_t * cr)24015331Samw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
2402789Sahrens {
24035331Samw 	uint32_t	working_mode;
24045331Samw 	int		error;
24055331Samw 	int		is_attr;
24065331Samw 	boolean_t 	check_privs;
24075331Samw 	znode_t		*xzp;
24085331Samw 	znode_t 	*check_zp = zp;
240912273SCasper.Dik@Sun.COM 	mode_t		needed_bits;
241013069SMark.Shellenbaum@Oracle.COM 	uid_t		owner;
2411789Sahrens 
241211935SMark.Shellenbaum@Sun.COM 	is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
2413789Sahrens 
2414789Sahrens 	/*
2415789Sahrens 	 * If attribute then validate against base file
2416789Sahrens 	 */
2417789Sahrens 	if (is_attr) {
241811935SMark.Shellenbaum@Sun.COM 		uint64_t	parent;
241911935SMark.Shellenbaum@Sun.COM 
242011935SMark.Shellenbaum@Sun.COM 		if ((error = sa_lookup(zp->z_sa_hdl,
242111935SMark.Shellenbaum@Sun.COM 		    SA_ZPL_PARENT(zp->z_zfsvfs), &parent,
242211935SMark.Shellenbaum@Sun.COM 		    sizeof (parent))) != 0)
242311935SMark.Shellenbaum@Sun.COM 			return (error);
242411935SMark.Shellenbaum@Sun.COM 
2425789Sahrens 		if ((error = zfs_zget(zp->z_zfsvfs,
242611935SMark.Shellenbaum@Sun.COM 		    parent, &xzp)) != 0)	{
2427789Sahrens 			return (error);
2428789Sahrens 		}
24295331Samw 
2430789Sahrens 		check_zp = xzp;
24315331Samw 
2432789Sahrens 		/*
2433789Sahrens 		 * fixup mode to map to xattr perms
2434789Sahrens 		 */
2435789Sahrens 
2436789Sahrens 		if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
2437789Sahrens 			mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
2438789Sahrens 			mode |= ACE_WRITE_NAMED_ATTRS;
2439789Sahrens 		}
2440789Sahrens 
2441789Sahrens 		if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
2442789Sahrens 			mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
2443789Sahrens 			mode |= ACE_READ_NAMED_ATTRS;
2444789Sahrens 		}
2445789Sahrens 	}
2446789Sahrens 
244713069SMark.Shellenbaum@Oracle.COM 	owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
244812273SCasper.Dik@Sun.COM 	/*
244912273SCasper.Dik@Sun.COM 	 * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
245012273SCasper.Dik@Sun.COM 	 * in needed_bits.  Map the bits mapped by working_mode (currently
245112273SCasper.Dik@Sun.COM 	 * missing) in missing_bits.
245212273SCasper.Dik@Sun.COM 	 * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
245312273SCasper.Dik@Sun.COM 	 * needed_bits.
245412273SCasper.Dik@Sun.COM 	 */
245512273SCasper.Dik@Sun.COM 	needed_bits = 0;
245612273SCasper.Dik@Sun.COM 
245712273SCasper.Dik@Sun.COM 	working_mode = mode;
245812273SCasper.Dik@Sun.COM 	if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
245913069SMark.Shellenbaum@Oracle.COM 	    owner == crgetuid(cr))
246012273SCasper.Dik@Sun.COM 		working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
246112273SCasper.Dik@Sun.COM 
246212273SCasper.Dik@Sun.COM 	if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
246312273SCasper.Dik@Sun.COM 	    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
246412273SCasper.Dik@Sun.COM 		needed_bits |= VREAD;
246512273SCasper.Dik@Sun.COM 	if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
246612273SCasper.Dik@Sun.COM 	    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
246712273SCasper.Dik@Sun.COM 		needed_bits |= VWRITE;
246812273SCasper.Dik@Sun.COM 	if (working_mode & ACE_EXECUTE)
246912273SCasper.Dik@Sun.COM 		needed_bits |= VEXEC;
247012273SCasper.Dik@Sun.COM 
24715331Samw 	if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
24725331Samw 	    &check_privs, skipaclchk, cr)) == 0) {
24735331Samw 		if (is_attr)
24745331Samw 			VN_RELE(ZTOV(xzp));
247513069SMark.Shellenbaum@Oracle.COM 		return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
247612273SCasper.Dik@Sun.COM 		    needed_bits, needed_bits));
24775331Samw 	}
2478789Sahrens 
24795959Smarks 	if (error && !check_privs) {
2480789Sahrens 		if (is_attr)
2481789Sahrens 			VN_RELE(ZTOV(xzp));
2482789Sahrens 		return (error);
2483789Sahrens 	}
2484789Sahrens 
24855331Samw 	if (error && (flags & V_APPEND)) {
24865331Samw 		error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
24875331Samw 	}
24885331Samw 
24895331Samw 	if (error && check_privs) {
24905331Samw 		mode_t		checkmode = 0;
24915331Samw 
24925331Samw 		/*
24935331Samw 		 * First check for implicit owner permission on
24945331Samw 		 * read_acl/read_attributes
24955331Samw 		 */
24965331Samw 
24975331Samw 		error = 0;
24985331Samw 		ASSERT(working_mode != 0);
24995331Samw 
25005331Samw 		if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
250113069SMark.Shellenbaum@Oracle.COM 		    owner == crgetuid(cr)))
25025331Samw 			working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
25035331Samw 
25045331Samw 		if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
25057624SMark.Shellenbaum@Sun.COM 		    ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
25065331Samw 			checkmode |= VREAD;
25075331Samw 		if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
25087624SMark.Shellenbaum@Sun.COM 		    ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
25095331Samw 			checkmode |= VWRITE;
25105331Samw 		if (working_mode & ACE_EXECUTE)
25115331Samw 			checkmode |= VEXEC;
25125331Samw 
251313069SMark.Shellenbaum@Oracle.COM 		error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
251412273SCasper.Dik@Sun.COM 		    needed_bits & ~checkmode, needed_bits);
25155331Samw 
25165331Samw 		if (error == 0 && (working_mode & ACE_WRITE_OWNER))
251713069SMark.Shellenbaum@Oracle.COM 			error = secpolicy_vnode_chown(cr, owner);
25185331Samw 		if (error == 0 && (working_mode & ACE_WRITE_ACL))
251913069SMark.Shellenbaum@Oracle.COM 			error = secpolicy_vnode_setdac(cr, owner);
25205331Samw 
25215331Samw 		if (error == 0 && (working_mode &
25225331Samw 		    (ACE_DELETE|ACE_DELETE_CHILD)))
25235331Samw 			error = secpolicy_vnode_remove(cr);
25245331Samw 
25257624SMark.Shellenbaum@Sun.COM 		if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
252613069SMark.Shellenbaum@Oracle.COM 			error = secpolicy_vnode_chown(cr, owner);
25277624SMark.Shellenbaum@Sun.COM 		}
25285331Samw 		if (error == 0) {
25295331Samw 			/*
25305331Samw 			 * See if any bits other than those already checked
25315331Samw 			 * for are still present.  If so then return EACCES
25325331Samw 			 */
25335331Samw 			if (working_mode & ~(ZFS_CHECKED_MASKS)) {
25345331Samw 				error = EACCES;
25355331Samw 			}
25365331Samw 		}
253712273SCasper.Dik@Sun.COM 	} else if (error == 0) {
253813069SMark.Shellenbaum@Oracle.COM 		error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
253912273SCasper.Dik@Sun.COM 		    needed_bits, needed_bits);
2540789Sahrens 	}
2541789Sahrens 
254212273SCasper.Dik@Sun.COM 
2543789Sahrens 	if (is_attr)
2544789Sahrens 		VN_RELE(ZTOV(xzp));
2545789Sahrens 
2546789Sahrens 	return (error);
2547789Sahrens }
2548789Sahrens 
2549789Sahrens /*
25505331Samw  * Translate traditional unix VREAD/VWRITE/VEXEC mode into
25515331Samw  * native ACL format and call zfs_zaccess()
2552789Sahrens  */
2553789Sahrens int
zfs_zaccess_rwx(znode_t * zp,mode_t mode,int flags,cred_t * cr)25545331Samw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
2555789Sahrens {
25565331Samw 	return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
2557789Sahrens }
2558789Sahrens 
2559789Sahrens /*
25605331Samw  * Access function for secpolicy_vnode_setattr
2561789Sahrens  */
2562789Sahrens int
zfs_zaccess_unix(znode_t * zp,mode_t mode,cred_t * cr)25635331Samw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
2564789Sahrens {
2565789Sahrens 	int v4_mode = zfs_unix_to_v4(mode >> 6);
2566789Sahrens 
25675331Samw 	return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr));
2568789Sahrens }
2569789Sahrens 
25702604Smarks static int
zfs_delete_final_check(znode_t * zp,znode_t * dzp,mode_t available_perms,cred_t * cr)25716257Smarks zfs_delete_final_check(znode_t *zp, znode_t *dzp,
257212273SCasper.Dik@Sun.COM     mode_t available_perms, cred_t *cr)
25732604Smarks {
25742604Smarks 	int error;
257513069SMark.Shellenbaum@Oracle.COM 	uid_t downer;
257613069SMark.Shellenbaum@Oracle.COM 
257713069SMark.Shellenbaum@Oracle.COM 	downer = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, ZFS_OWNER);
257811935SMark.Shellenbaum@Sun.COM 
257912273SCasper.Dik@Sun.COM 	error = secpolicy_vnode_access2(cr, ZTOV(dzp),
258013069SMark.Shellenbaum@Oracle.COM 	    downer, available_perms, VWRITE|VEXEC);
25812604Smarks 
25822604Smarks 	if (error == 0)
25832604Smarks 		error = zfs_sticky_remove_access(dzp, zp, cr);
25842604Smarks 
25852604Smarks 	return (error);
25862604Smarks }
25872604Smarks 
2588789Sahrens /*
2589789Sahrens  * Determine whether Access should be granted/deny, without
2590789Sahrens  * consulting least priv subsystem.
2591789Sahrens  *
2592789Sahrens  *
2593789Sahrens  * The following chart is the recommended NFSv4 enforcement for
2594789Sahrens  * ability to delete an object.
2595789Sahrens  *
2596789Sahrens  *      -------------------------------------------------------
2597789Sahrens  *      |   Parent Dir  |           Target Object Permissions |
2598789Sahrens  *      |  permissions  |                                     |
2599789Sahrens  *      -------------------------------------------------------
2600789Sahrens  *      |               | ACL Allows | ACL Denies| Delete     |
2601789Sahrens  *      |               |  Delete    |  Delete   | unspecified|
2602789Sahrens  *      -------------------------------------------------------
2603789Sahrens  *      |  ACL Allows   | Permit     | Permit    | Permit     |
2604789Sahrens  *      |  DELETE_CHILD |                                     |
2605789Sahrens  *      -------------------------------------------------------
2606789Sahrens  *      |  ACL Denies   | Permit     | Deny      | Deny       |
2607789Sahrens  *      |  DELETE_CHILD |            |           |            |
2608789Sahrens  *      -------------------------------------------------------
2609789Sahrens  *      | ACL specifies |            |           |            |
2610789Sahrens  *      | only allow    | Permit     | Permit    | Permit     |
2611789Sahrens  *      | write and     |            |           |            |
2612789Sahrens  *      | execute       |            |           |            |
2613789Sahrens  *      -------------------------------------------------------
2614789Sahrens  *      | ACL denies    |            |           |            |
2615789Sahrens  *      | write and     | Permit     | Deny      | Deny       |
2616789Sahrens  *      | execute       |            |           |            |
2617789Sahrens  *      -------------------------------------------------------
2618789Sahrens  *         ^
2619789Sahrens  *         |
2620789Sahrens  *         No search privilege, can't even look up file?
2621789Sahrens  *
2622789Sahrens  */
2623789Sahrens int
zfs_zaccess_delete(znode_t * dzp,znode_t * zp,cred_t * cr)2624789Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
2625789Sahrens {
26265331Samw 	uint32_t dzp_working_mode = 0;
26275331Samw 	uint32_t zp_working_mode = 0;
2628789Sahrens 	int dzp_error, zp_error;
262912273SCasper.Dik@Sun.COM 	mode_t available_perms;
26305331Samw 	boolean_t dzpcheck_privs = B_TRUE;
26315331Samw 	boolean_t zpcheck_privs = B_TRUE;
2632789Sahrens 
2633789Sahrens 	/*
26346257Smarks 	 * We want specific DELETE permissions to
2635789Sahrens 	 * take precedence over WRITE/EXECUTE.  We don't
2636789Sahrens 	 * want an ACL such as this to mess us up.
26372604Smarks 	 * user:joe:write_data:deny,user:joe:delete:allow
2638789Sahrens 	 *
2639789Sahrens 	 * However, deny permissions may ultimately be overridden
2640789Sahrens 	 * by secpolicy_vnode_access().
26416257Smarks 	 *
26426257Smarks 	 * We will ask for all of the necessary permissions and then
26436257Smarks 	 * look at the working modes from the directory and target object
26446257Smarks 	 * to determine what was found.
2645789Sahrens 	 */
2646789Sahrens 
264711935SMark.Shellenbaum@Sun.COM 	if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
26485331Samw 		return (EPERM);
26495331Samw 
26506257Smarks 	/*
26517163Smarks 	 * First row
26526257Smarks 	 * If the directory permissions allow the delete, we are done.
26536257Smarks 	 */
26547163Smarks 	if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
26556257Smarks 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
26566257Smarks 		return (0);
2657789Sahrens 
26586257Smarks 	/*
26596257Smarks 	 * If target object has delete permission then we are done
26606257Smarks 	 */
26616257Smarks 	if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
26626257Smarks 	    &zpcheck_privs, B_FALSE, cr)) == 0)
26636257Smarks 		return (0);
26646257Smarks 
26657163Smarks 	ASSERT(dzp_error && zp_error);
26667163Smarks 
26676257Smarks 	if (!dzpcheck_privs)
2668789Sahrens 		return (dzp_error);
26697163Smarks 	if (!zpcheck_privs)
26706257Smarks 		return (zp_error);
2671789Sahrens 
2672789Sahrens 	/*
2673789Sahrens 	 * Second row
26747163Smarks 	 *
26757163Smarks 	 * If directory returns EACCES then delete_child was denied
26767163Smarks 	 * due to deny delete_child.  In this case send the request through
26777163Smarks 	 * secpolicy_vnode_remove().  We don't use zfs_delete_final_check()
26787163Smarks 	 * since that *could* allow the delete based on write/execute permission
26797163Smarks 	 * and we want delete permissions to override write/execute.
2680789Sahrens 	 */
2681789Sahrens 
26822604Smarks 	if (dzp_error == EACCES)
26837163Smarks 		return (secpolicy_vnode_remove(cr));
26842604Smarks 
26852604Smarks 	/*
2686789Sahrens 	 * Third Row
26876257Smarks 	 * only need to see if we have write/execute on directory.
2688789Sahrens 	 */
2689789Sahrens 
269012273SCasper.Dik@Sun.COM 	dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
269112273SCasper.Dik@Sun.COM 	    &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
2692789Sahrens 
269312273SCasper.Dik@Sun.COM 	if (dzp_error != 0 && !dzpcheck_privs)
26947163Smarks 		return (dzp_error);
26957163Smarks 
2696789Sahrens 	/*
26977163Smarks 	 * Fourth row
2698789Sahrens 	 */
2699789Sahrens 
270012273SCasper.Dik@Sun.COM 	available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE;
270112273SCasper.Dik@Sun.COM 	available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC;
27027163Smarks 
270312273SCasper.Dik@Sun.COM 	return (zfs_delete_final_check(zp, dzp, available_perms, cr));
27047163Smarks 
2705789Sahrens }
2706789Sahrens 
2707789Sahrens int
zfs_zaccess_rename(znode_t * sdzp,znode_t * szp,znode_t * tdzp,znode_t * tzp,cred_t * cr)2708789Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
2709789Sahrens     znode_t *tzp, cred_t *cr)
2710789Sahrens {
2711789Sahrens 	int add_perm;
2712789Sahrens 	int error;
2713789Sahrens 
271411935SMark.Shellenbaum@Sun.COM 	if (szp->z_pflags & ZFS_AV_QUARANTINED)
27155331Samw 		return (EACCES);
27165331Samw 
2717789Sahrens 	add_perm = (ZTOV(szp)->v_type == VDIR) ?
2718789Sahrens 	    ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE;
2719789Sahrens 
2720789Sahrens 	/*
2721789Sahrens 	 * Rename permissions are combination of delete permission +
2722789Sahrens 	 * add file/subdir permission.
2723789Sahrens 	 */
2724789Sahrens 
2725789Sahrens 	/*
2726789Sahrens 	 * first make sure we do the delete portion.
2727789Sahrens 	 *
2728789Sahrens 	 * If that succeeds then check for add_file/add_subdir permissions
2729789Sahrens 	 */
2730789Sahrens 
2731789Sahrens 	if (error = zfs_zaccess_delete(sdzp, szp, cr))
2732789Sahrens 		return (error);
2733789Sahrens 
2734789Sahrens 	/*
2735789Sahrens 	 * If we have a tzp, see if we can delete it?
2736789Sahrens 	 */
2737789Sahrens 	if (tzp) {
2738789Sahrens 		if (error = zfs_zaccess_delete(tdzp, tzp, cr))
2739789Sahrens 			return (error);
2740789Sahrens 	}
2741789Sahrens 
2742789Sahrens 	/*
2743789Sahrens 	 * Now check for add permissions
2744789Sahrens 	 */
27455331Samw 	error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
2746789Sahrens 
2747789Sahrens 	return (error);
2748789Sahrens }
2749