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