1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 22*11574SJohn.Harres@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <sys/types.h> 27789Sahrens #include <sys/param.h> 28789Sahrens #include <sys/time.h> 29789Sahrens #include <sys/systm.h> 30789Sahrens #include <sys/sysmacros.h> 31789Sahrens #include <sys/resource.h> 32789Sahrens #include <sys/vfs.h> 33789Sahrens #include <sys/vnode.h> 345331Samw #include <sys/sid.h> 35789Sahrens #include <sys/file.h> 36789Sahrens #include <sys/stat.h> 37789Sahrens #include <sys/kmem.h> 38789Sahrens #include <sys/cmn_err.h> 39789Sahrens #include <sys/errno.h> 40789Sahrens #include <sys/unistd.h> 411576Smarks #include <sys/sdt.h> 42789Sahrens #include <sys/fs/zfs.h> 43789Sahrens #include <sys/mode.h> 44789Sahrens #include <sys/policy.h> 45789Sahrens #include <sys/zfs_znode.h> 465331Samw #include <sys/zfs_fuid.h> 47789Sahrens #include <sys/zfs_acl.h> 48789Sahrens #include <sys/zfs_dir.h> 49789Sahrens #include <sys/zfs_vfsops.h> 50789Sahrens #include <sys/dmu.h> 515331Samw #include <sys/dnode.h> 52789Sahrens #include <sys/zap.h> 53789Sahrens #include "fs/fs_subr.h" 54789Sahrens #include <acl/acl_common.h> 55789Sahrens 56789Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 57789Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 585331Samw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 597559SMark.Shellenbaum@Sun.COM #define MIN_ACE_TYPE ALLOW 60789Sahrens 61789Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 62789Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 63789Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 64789Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 65789Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 66789Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 67789Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 685331Samw 695331Samw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 705331Samw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 715331Samw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 725331Samw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 735331Samw 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 995331Samw zfs_ace_v0_get_type(void *acep) 1005331Samw { 1015331Samw return (((zfs_oldace_t *)acep)->z_type); 1025331Samw } 1035331Samw 1045331Samw static uint16_t 1055331Samw zfs_ace_v0_get_flags(void *acep) 1065331Samw { 1075331Samw return (((zfs_oldace_t *)acep)->z_flags); 1085331Samw } 1095331Samw 1105331Samw static uint32_t 1115331Samw zfs_ace_v0_get_mask(void *acep) 1125331Samw { 1135331Samw return (((zfs_oldace_t *)acep)->z_access_mask); 1145331Samw } 1155331Samw 1165331Samw static uint64_t 1175331Samw zfs_ace_v0_get_who(void *acep) 1185331Samw { 1195331Samw return (((zfs_oldace_t *)acep)->z_fuid); 1205331Samw } 1215331Samw 1225331Samw static void 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 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 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 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 1485331Samw zfs_ace_v0_size(void *acep) 1495331Samw { 1505331Samw return (sizeof (zfs_oldace_t)); 1515331Samw } 1525331Samw 1535331Samw static size_t 1545331Samw zfs_ace_v0_abstract_size(void) 1555331Samw { 1565331Samw return (sizeof (zfs_oldace_t)); 1575331Samw } 1585331Samw 1595331Samw static int 1605331Samw zfs_ace_v0_mask_off(void) 1615331Samw { 1625331Samw return (offsetof(zfs_oldace_t, z_access_mask)); 1635331Samw } 1645331Samw 1655331Samw /*ARGSUSED*/ 1665331Samw static int 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 1895331Samw zfs_ace_fuid_get_type(void *acep) 1905331Samw { 1915331Samw return (((zfs_ace_hdr_t *)acep)->z_type); 1925331Samw } 1935331Samw 1945331Samw static uint16_t 1955331Samw zfs_ace_fuid_get_flags(void *acep) 1965331Samw { 1975331Samw return (((zfs_ace_hdr_t *)acep)->z_flags); 1985331Samw } 1995331Samw 2005331Samw static uint32_t 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 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 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 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 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 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 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 2785331Samw zfs_ace_fuid_abstract_size(void) 2795331Samw { 2805331Samw return (sizeof (zfs_ace_hdr_t)); 2815331Samw } 2825331Samw 2835331Samw static int 2845331Samw zfs_ace_fuid_mask_off(void) 2855331Samw { 2865331Samw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 2875331Samw } 2885331Samw 2895331Samw static int 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 3245331Samw static int 3255331Samw zfs_acl_version(int version) 3265331Samw { 3275331Samw if (version < ZPL_VERSION_FUID) 3285331Samw return (ZFS_ACL_VERSION_INITIAL); 3295331Samw else 3305331Samw return (ZFS_ACL_VERSION_FUID); 3315331Samw } 3325331Samw 3335331Samw static int 3345331Samw zfs_acl_version_zp(znode_t *zp) 3355331Samw { 3365331Samw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 3375331Samw } 338789Sahrens 339789Sahrens static zfs_acl_t * 3405331Samw zfs_acl_alloc(int vers) 341789Sahrens { 342789Sahrens zfs_acl_t *aclp; 343789Sahrens 344789Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 3455331Samw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 3465331Samw offsetof(zfs_acl_node_t, z_next)); 3475331Samw aclp->z_version = vers; 3485331Samw if (vers == ZFS_ACL_VERSION_FUID) 3495331Samw aclp->z_ops = zfs_acl_fuid_ops; 3505331Samw else 3515331Samw aclp->z_ops = zfs_acl_v0_ops; 3525331Samw return (aclp); 3535331Samw } 3545331Samw 3555331Samw static zfs_acl_node_t * 3565331Samw zfs_acl_node_alloc(size_t bytes) 3575331Samw { 3585331Samw zfs_acl_node_t *aclnode; 3595331Samw 3605331Samw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 3615331Samw if (bytes) { 3625331Samw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 3635331Samw aclnode->z_allocdata = aclnode->z_acldata; 3645331Samw aclnode->z_allocsize = bytes; 3655331Samw aclnode->z_size = bytes; 366789Sahrens } 3675331Samw 3685331Samw return (aclnode); 3695331Samw } 3705331Samw 3715331Samw static void 3725331Samw zfs_acl_node_free(zfs_acl_node_t *aclnode) 3735331Samw { 3745331Samw if (aclnode->z_allocsize) 3755331Samw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 3765331Samw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 377789Sahrens } 378789Sahrens 3795489Smarks static void 3805489Smarks zfs_acl_release_nodes(zfs_acl_t *aclp) 381789Sahrens { 3825331Samw zfs_acl_node_t *aclnode; 3835331Samw 3845331Samw while (aclnode = list_head(&aclp->z_acl)) { 3855331Samw list_remove(&aclp->z_acl, aclnode); 3865331Samw zfs_acl_node_free(aclnode); 387789Sahrens } 3885489Smarks aclp->z_acl_count = 0; 3895489Smarks aclp->z_acl_bytes = 0; 3905489Smarks } 3915331Samw 3925489Smarks void 3935489Smarks zfs_acl_free(zfs_acl_t *aclp) 3945489Smarks { 3955489Smarks zfs_acl_release_nodes(aclp); 3965331Samw list_destroy(&aclp->z_acl); 397789Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 398789Sahrens } 399789Sahrens 4005331Samw static boolean_t 4017559SMark.Shellenbaum@Sun.COM zfs_acl_valid_ace_type(uint_t type, uint_t flags) 4027559SMark.Shellenbaum@Sun.COM { 4037559SMark.Shellenbaum@Sun.COM uint16_t entry_type; 4047559SMark.Shellenbaum@Sun.COM 4057559SMark.Shellenbaum@Sun.COM switch (type) { 4067559SMark.Shellenbaum@Sun.COM case ALLOW: 4077559SMark.Shellenbaum@Sun.COM case DENY: 4087559SMark.Shellenbaum@Sun.COM case ACE_SYSTEM_AUDIT_ACE_TYPE: 4097559SMark.Shellenbaum@Sun.COM case ACE_SYSTEM_ALARM_ACE_TYPE: 4107559SMark.Shellenbaum@Sun.COM entry_type = flags & ACE_TYPE_FLAGS; 4117559SMark.Shellenbaum@Sun.COM return (entry_type == ACE_OWNER || 4127559SMark.Shellenbaum@Sun.COM entry_type == OWNING_GROUP || 4137559SMark.Shellenbaum@Sun.COM entry_type == ACE_EVERYONE || entry_type == 0 || 4147559SMark.Shellenbaum@Sun.COM entry_type == ACE_IDENTIFIER_GROUP); 4157559SMark.Shellenbaum@Sun.COM default: 4167559SMark.Shellenbaum@Sun.COM if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 4177559SMark.Shellenbaum@Sun.COM return (B_TRUE); 4187559SMark.Shellenbaum@Sun.COM } 4197559SMark.Shellenbaum@Sun.COM return (B_FALSE); 4207559SMark.Shellenbaum@Sun.COM } 4217559SMark.Shellenbaum@Sun.COM 4227559SMark.Shellenbaum@Sun.COM static boolean_t 4235331Samw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 424789Sahrens { 4255331Samw /* 4265331Samw * first check type of entry 4275331Samw */ 4285331Samw 4297559SMark.Shellenbaum@Sun.COM if (!zfs_acl_valid_ace_type(type, iflags)) 4305331Samw return (B_FALSE); 4315331Samw 4325331Samw switch (type) { 4335331Samw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 4345331Samw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 4355331Samw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 4365331Samw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 4375331Samw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 4385331Samw return (B_FALSE); 4395331Samw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 4405331Samw } 441789Sahrens 4427559SMark.Shellenbaum@Sun.COM /* 4437559SMark.Shellenbaum@Sun.COM * next check inheritance level flags 4447559SMark.Shellenbaum@Sun.COM */ 4457559SMark.Shellenbaum@Sun.COM 4467057Smarks if (obj_type == VDIR && 4477057Smarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 4485331Samw aclp->z_hints |= ZFS_INHERIT_ACE; 4495331Samw 4505331Samw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 4515331Samw if ((iflags & (ACE_FILE_INHERIT_ACE| 4525331Samw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 4535331Samw return (B_FALSE); 4545331Samw } 4555331Samw } 4565331Samw 4575331Samw return (B_TRUE); 4585331Samw } 4595331Samw 4605331Samw static void * 4615331Samw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 4625331Samw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 4635331Samw { 4645331Samw zfs_acl_node_t *aclnode; 4655331Samw 4665331Samw if (start == NULL) { 4675331Samw aclnode = list_head(&aclp->z_acl); 4685331Samw if (aclnode == NULL) 4695331Samw return (NULL); 4705331Samw 4715331Samw aclp->z_next_ace = aclnode->z_acldata; 4725331Samw aclp->z_curr_node = aclnode; 4735331Samw aclnode->z_ace_idx = 0; 4745331Samw } 4755331Samw 4765331Samw aclnode = aclp->z_curr_node; 4775331Samw 4785331Samw if (aclnode == NULL) 4795331Samw return (NULL); 4805331Samw 4815331Samw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 4825331Samw aclnode = list_next(&aclp->z_acl, aclnode); 4835331Samw if (aclnode == NULL) 4845331Samw return (NULL); 4855331Samw else { 4865331Samw aclp->z_curr_node = aclnode; 4875331Samw aclnode->z_ace_idx = 0; 4885331Samw aclp->z_next_ace = aclnode->z_acldata; 4895331Samw } 4905331Samw } 4915331Samw 4925331Samw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 4935331Samw void *acep = aclp->z_next_ace; 4947559SMark.Shellenbaum@Sun.COM size_t ace_size; 4957559SMark.Shellenbaum@Sun.COM 4967559SMark.Shellenbaum@Sun.COM /* 4977559SMark.Shellenbaum@Sun.COM * Make sure we don't overstep our bounds 4987559SMark.Shellenbaum@Sun.COM */ 4997559SMark.Shellenbaum@Sun.COM ace_size = aclp->z_ops.ace_size(acep); 5007559SMark.Shellenbaum@Sun.COM 5017559SMark.Shellenbaum@Sun.COM if (((caddr_t)acep + ace_size) > 5027559SMark.Shellenbaum@Sun.COM ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 5037559SMark.Shellenbaum@Sun.COM return (NULL); 5047559SMark.Shellenbaum@Sun.COM } 5057559SMark.Shellenbaum@Sun.COM 5065331Samw *iflags = aclp->z_ops.ace_flags_get(acep); 5075331Samw *type = aclp->z_ops.ace_type_get(acep); 5085331Samw *access_mask = aclp->z_ops.ace_mask_get(acep); 5095331Samw *who = aclp->z_ops.ace_who_get(acep); 5107559SMark.Shellenbaum@Sun.COM aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 5115331Samw aclnode->z_ace_idx++; 5125331Samw return ((void *)acep); 5135331Samw } 5145331Samw return (NULL); 5155331Samw } 5165331Samw 5175331Samw /*ARGSUSED*/ 5185331Samw static uint64_t 5195331Samw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 5205331Samw uint16_t *flags, uint16_t *type, uint32_t *mask) 5215331Samw { 5225331Samw zfs_acl_t *aclp = datap; 5235331Samw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 5245331Samw uint64_t who; 5255331Samw 5265331Samw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 5275331Samw flags, type); 5285331Samw return ((uint64_t)(uintptr_t)acep); 5295331Samw } 5305331Samw 5315331Samw static zfs_acl_node_t * 5325331Samw zfs_acl_curr_node(zfs_acl_t *aclp) 5335331Samw { 5345331Samw ASSERT(aclp->z_curr_node); 5355331Samw return (aclp->z_curr_node); 5365331Samw } 5375331Samw 5385331Samw /* 5395331Samw * Copy ACE to internal ZFS format. 5405331Samw * While processing the ACL each ACE will be validated for correctness. 5415331Samw * ACE FUIDs will be created later. 5425331Samw */ 5435331Samw int 5449179SMark.Shellenbaum@Sun.COM zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 5459179SMark.Shellenbaum@Sun.COM void *datap, zfs_ace_t *z_acl, int aclcnt, size_t *size, 5469179SMark.Shellenbaum@Sun.COM zfs_fuid_info_t **fuidp, cred_t *cr) 5475331Samw { 5485331Samw int i; 5495331Samw uint16_t entry_type; 5505331Samw zfs_ace_t *aceptr = z_acl; 5515331Samw ace_t *acep = datap; 5525331Samw zfs_object_ace_t *zobjacep; 5535331Samw ace_object_t *aceobjp; 5545331Samw 5555331Samw for (i = 0; i != aclcnt; i++) { 5565331Samw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 5575331Samw aceptr->z_hdr.z_flags = acep->a_flags; 5585331Samw aceptr->z_hdr.z_type = acep->a_type; 5595331Samw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 5605331Samw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 5615824Smarks entry_type != ACE_EVERYONE) { 5629179SMark.Shellenbaum@Sun.COM aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 5639179SMark.Shellenbaum@Sun.COM cr, (entry_type == 0) ? 5649179SMark.Shellenbaum@Sun.COM ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 5655824Smarks } 5665824Smarks 5675331Samw /* 5685331Samw * Make sure ACE is valid 5695331Samw */ 5705331Samw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 5715331Samw aceptr->z_hdr.z_flags) != B_TRUE) 5725331Samw return (EINVAL); 5735331Samw 5745331Samw switch (acep->a_type) { 5755331Samw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 5765331Samw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 5775331Samw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 5785331Samw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 5795331Samw zobjacep = (zfs_object_ace_t *)aceptr; 5805331Samw aceobjp = (ace_object_t *)acep; 5815331Samw 5825331Samw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 5835331Samw sizeof (aceobjp->a_obj_type)); 5845331Samw bcopy(aceobjp->a_inherit_obj_type, 5855331Samw zobjacep->z_inherit_type, 5865331Samw sizeof (aceobjp->a_inherit_obj_type)); 5875331Samw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 5885331Samw break; 5895331Samw default: 5905331Samw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 5915331Samw } 5925331Samw 5935331Samw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 5945331Samw aclp->z_ops.ace_size(aceptr)); 5955331Samw } 5965331Samw 5975331Samw *size = (caddr_t)aceptr - (caddr_t)z_acl; 598789Sahrens 5995331Samw return (0); 6005331Samw } 6015331Samw 6025331Samw /* 6035331Samw * Copy ZFS ACEs to fixed size ace_t layout 6045331Samw */ 6055331Samw static void 6065771Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 6075771Sjp151216 void *datap, int filter) 6085331Samw { 6095331Samw uint64_t who; 6105331Samw uint32_t access_mask; 6115331Samw uint16_t iflags, type; 6125331Samw zfs_ace_hdr_t *zacep = NULL; 6135331Samw ace_t *acep = datap; 6145331Samw ace_object_t *objacep; 6155331Samw zfs_object_ace_t *zobjacep; 6165331Samw size_t ace_size; 6175331Samw uint16_t entry_type; 6185331Samw 6195331Samw while (zacep = zfs_acl_next_ace(aclp, zacep, 6205331Samw &who, &access_mask, &iflags, &type)) { 6215331Samw 6225331Samw switch (type) { 6235331Samw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 6245331Samw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 6255331Samw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 6265331Samw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 6275331Samw if (filter) { 6285331Samw continue; 6295331Samw } 6305331Samw zobjacep = (zfs_object_ace_t *)zacep; 6315331Samw objacep = (ace_object_t *)acep; 6325331Samw bcopy(zobjacep->z_object_type, 6335331Samw objacep->a_obj_type, 6345331Samw sizeof (zobjacep->z_object_type)); 6355331Samw bcopy(zobjacep->z_inherit_type, 6365331Samw objacep->a_inherit_obj_type, 6375331Samw sizeof (zobjacep->z_inherit_type)); 6385331Samw ace_size = sizeof (ace_object_t); 6395331Samw break; 6405331Samw default: 6415331Samw ace_size = sizeof (ace_t); 6425331Samw break; 6435331Samw } 6445331Samw 6455331Samw entry_type = (iflags & ACE_TYPE_FLAGS); 6465331Samw if ((entry_type != ACE_OWNER && 6477328SMark.Shellenbaum@Sun.COM entry_type != OWNING_GROUP && 6485959Smarks entry_type != ACE_EVERYONE)) { 6495959Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 6505959Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 6515959Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 6525959Smarks } else { 6535331Samw acep->a_who = (uid_t)(int64_t)who; 6545959Smarks } 6555331Samw acep->a_access_mask = access_mask; 6565331Samw acep->a_flags = iflags; 6575331Samw acep->a_type = type; 6585331Samw acep = (ace_t *)((caddr_t)acep + ace_size); 6595331Samw } 6605331Samw } 6615331Samw 6625331Samw static int 6635331Samw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 6645331Samw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 6655331Samw { 6665331Samw int i; 6675331Samw zfs_oldace_t *aceptr = z_acl; 6685331Samw 6695331Samw for (i = 0; i != aclcnt; i++, aceptr++) { 6705331Samw aceptr->z_access_mask = acep[i].a_access_mask; 6715331Samw aceptr->z_type = acep[i].a_type; 6725331Samw aceptr->z_flags = acep[i].a_flags; 6735331Samw aceptr->z_fuid = acep[i].a_who; 6745331Samw /* 6755331Samw * Make sure ACE is valid 6765331Samw */ 6775331Samw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 6785331Samw aceptr->z_flags) != B_TRUE) 6795331Samw return (EINVAL); 6805331Samw } 6815331Samw *size = (caddr_t)aceptr - (caddr_t)z_acl; 6825331Samw return (0); 6835331Samw } 6845331Samw 6855331Samw /* 6865331Samw * convert old ACL format to new 6875331Samw */ 6885331Samw void 6899179SMark.Shellenbaum@Sun.COM zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 6905331Samw { 6915331Samw zfs_oldace_t *oldaclp; 6925331Samw int i; 6935331Samw uint16_t type, iflags; 6945331Samw uint32_t access_mask; 6955331Samw uint64_t who; 6965331Samw void *cookie = NULL; 6975489Smarks zfs_acl_node_t *newaclnode; 6985331Samw 6995331Samw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 7005331Samw /* 7015331Samw * First create the ACE in a contiguous piece of memory 7025331Samw * for zfs_copy_ace_2_fuid(). 7035331Samw * 7045331Samw * We only convert an ACL once, so this won't happen 7055331Samw * everytime. 7065331Samw */ 7075331Samw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 7085331Samw KM_SLEEP); 7095331Samw i = 0; 7105331Samw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 7115331Samw &access_mask, &iflags, &type)) { 7125331Samw oldaclp[i].z_flags = iflags; 7135331Samw oldaclp[i].z_type = type; 7145331Samw oldaclp[i].z_fuid = who; 7155331Samw oldaclp[i++].z_access_mask = access_mask; 7165331Samw } 7175331Samw 7185331Samw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 7195331Samw sizeof (zfs_object_ace_t)); 7205331Samw aclp->z_ops = zfs_acl_fuid_ops; 7219179SMark.Shellenbaum@Sun.COM VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 7229179SMark.Shellenbaum@Sun.COM oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 7239179SMark.Shellenbaum@Sun.COM &newaclnode->z_size, NULL, cr) == 0); 7245331Samw newaclnode->z_ace_count = aclp->z_acl_count; 7255331Samw aclp->z_version = ZFS_ACL_VERSION; 7265331Samw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 7275331Samw 7285331Samw /* 7295331Samw * Release all previous ACL nodes 7305331Samw */ 7315331Samw 7325489Smarks zfs_acl_release_nodes(aclp); 7335489Smarks 7345331Samw list_insert_head(&aclp->z_acl, newaclnode); 7355489Smarks 7365489Smarks aclp->z_acl_bytes = newaclnode->z_size; 7375489Smarks aclp->z_acl_count = newaclnode->z_ace_count; 7385489Smarks 739789Sahrens } 740789Sahrens 741789Sahrens /* 742789Sahrens * Convert unix access mask to v4 access mask 743789Sahrens */ 744789Sahrens static uint32_t 745789Sahrens zfs_unix_to_v4(uint32_t access_mask) 746789Sahrens { 747789Sahrens uint32_t new_mask = 0; 748789Sahrens 7495331Samw if (access_mask & S_IXOTH) 7505331Samw new_mask |= ACE_EXECUTE; 7515331Samw if (access_mask & S_IWOTH) 7525331Samw new_mask |= ACE_WRITE_DATA; 7535331Samw if (access_mask & S_IROTH) 754789Sahrens new_mask |= ACE_READ_DATA; 755789Sahrens return (new_mask); 756789Sahrens } 757789Sahrens 758789Sahrens static void 7595331Samw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 7605331Samw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 761789Sahrens { 7625331Samw uint16_t type = entry_type & ACE_TYPE_FLAGS; 7635331Samw 7645331Samw aclp->z_ops.ace_mask_set(acep, access_mask); 7655331Samw aclp->z_ops.ace_type_set(acep, access_type); 7665331Samw aclp->z_ops.ace_flags_set(acep, entry_type); 7677328SMark.Shellenbaum@Sun.COM if ((type != ACE_OWNER && type != OWNING_GROUP && 7685331Samw type != ACE_EVERYONE)) 7695331Samw aclp->z_ops.ace_who_set(acep, fuid); 770789Sahrens } 771789Sahrens 7725331Samw /* 7735331Samw * Determine mode of file based on ACL. 7745331Samw * Also, create FUIDs for any User/Group ACEs 7755331Samw */ 776789Sahrens static uint64_t 7779179SMark.Shellenbaum@Sun.COM zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp) 778789Sahrens { 7795331Samw int entry_type; 7805331Samw mode_t mode; 7815331Samw mode_t seen = 0; 7825331Samw zfs_ace_hdr_t *acep = NULL; 7835331Samw uint64_t who; 7845331Samw uint16_t iflags, type; 7855331Samw uint32_t access_mask; 7869981STim.Haley@Sun.COM boolean_t an_exec_denied = B_FALSE; 787789Sahrens 7885331Samw mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 7895331Samw 7905331Samw while (acep = zfs_acl_next_ace(aclp, acep, &who, 7915331Samw &access_mask, &iflags, &type)) { 7924869Smarks 7937559SMark.Shellenbaum@Sun.COM if (!zfs_acl_valid_ace_type(type, iflags)) 7947559SMark.Shellenbaum@Sun.COM continue; 7957559SMark.Shellenbaum@Sun.COM 7967328SMark.Shellenbaum@Sun.COM entry_type = (iflags & ACE_TYPE_FLAGS); 7977328SMark.Shellenbaum@Sun.COM 7984869Smarks /* 7997328SMark.Shellenbaum@Sun.COM * Skip over owner@, group@ or everyone@ inherit only ACEs 8004869Smarks */ 8017328SMark.Shellenbaum@Sun.COM if ((iflags & ACE_INHERIT_ONLY_ACE) && 8027328SMark.Shellenbaum@Sun.COM (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 8037328SMark.Shellenbaum@Sun.COM entry_type == OWNING_GROUP)) 8044869Smarks continue; 8054869Smarks 806789Sahrens if (entry_type == ACE_OWNER) { 8075331Samw if ((access_mask & ACE_READ_DATA) && 808789Sahrens (!(seen & S_IRUSR))) { 809789Sahrens seen |= S_IRUSR; 8105331Samw if (type == ALLOW) { 811789Sahrens mode |= S_IRUSR; 812789Sahrens } 813789Sahrens } 8145331Samw if ((access_mask & ACE_WRITE_DATA) && 815789Sahrens (!(seen & S_IWUSR))) { 816789Sahrens seen |= S_IWUSR; 8175331Samw if (type == ALLOW) { 818789Sahrens mode |= S_IWUSR; 819789Sahrens } 820789Sahrens } 8215331Samw if ((access_mask & ACE_EXECUTE) && 822789Sahrens (!(seen & S_IXUSR))) { 823789Sahrens seen |= S_IXUSR; 8245331Samw if (type == ALLOW) { 825789Sahrens mode |= S_IXUSR; 826789Sahrens } 827789Sahrens } 828789Sahrens } else if (entry_type == OWNING_GROUP) { 8295331Samw if ((access_mask & ACE_READ_DATA) && 830789Sahrens (!(seen & S_IRGRP))) { 831789Sahrens seen |= S_IRGRP; 8325331Samw if (type == ALLOW) { 833789Sahrens mode |= S_IRGRP; 834789Sahrens } 835789Sahrens } 8365331Samw if ((access_mask & ACE_WRITE_DATA) && 837789Sahrens (!(seen & S_IWGRP))) { 838789Sahrens seen |= S_IWGRP; 8395331Samw if (type == ALLOW) { 840789Sahrens mode |= S_IWGRP; 841789Sahrens } 842789Sahrens } 8435331Samw if ((access_mask & ACE_EXECUTE) && 844789Sahrens (!(seen & S_IXGRP))) { 845789Sahrens seen |= S_IXGRP; 8465331Samw if (type == ALLOW) { 847789Sahrens mode |= S_IXGRP; 848789Sahrens } 849789Sahrens } 850789Sahrens } else if (entry_type == ACE_EVERYONE) { 8515331Samw if ((access_mask & ACE_READ_DATA)) { 852789Sahrens if (!(seen & S_IRUSR)) { 853789Sahrens seen |= S_IRUSR; 8545331Samw if (type == ALLOW) { 855789Sahrens mode |= S_IRUSR; 856789Sahrens } 857789Sahrens } 858789Sahrens if (!(seen & S_IRGRP)) { 859789Sahrens seen |= S_IRGRP; 8605331Samw if (type == ALLOW) { 861789Sahrens mode |= S_IRGRP; 862789Sahrens } 863789Sahrens } 864789Sahrens if (!(seen & S_IROTH)) { 865789Sahrens seen |= S_IROTH; 8665331Samw if (type == ALLOW) { 867789Sahrens mode |= S_IROTH; 868789Sahrens } 869789Sahrens } 870789Sahrens } 8715331Samw if ((access_mask & ACE_WRITE_DATA)) { 872789Sahrens if (!(seen & S_IWUSR)) { 873789Sahrens seen |= S_IWUSR; 8745331Samw if (type == ALLOW) { 875789Sahrens mode |= S_IWUSR; 876789Sahrens } 877789Sahrens } 878789Sahrens if (!(seen & S_IWGRP)) { 879789Sahrens seen |= S_IWGRP; 8805331Samw if (type == ALLOW) { 881789Sahrens mode |= S_IWGRP; 882789Sahrens } 883789Sahrens } 884789Sahrens if (!(seen & S_IWOTH)) { 885789Sahrens seen |= S_IWOTH; 8865331Samw if (type == ALLOW) { 887789Sahrens mode |= S_IWOTH; 888789Sahrens } 889789Sahrens } 890789Sahrens } 8915331Samw if ((access_mask & ACE_EXECUTE)) { 892789Sahrens if (!(seen & S_IXUSR)) { 893789Sahrens seen |= S_IXUSR; 8945331Samw if (type == ALLOW) { 895789Sahrens mode |= S_IXUSR; 896789Sahrens } 897789Sahrens } 898789Sahrens if (!(seen & S_IXGRP)) { 899789Sahrens seen |= S_IXGRP; 9005331Samw if (type == ALLOW) { 901789Sahrens mode |= S_IXGRP; 902789Sahrens } 903789Sahrens } 904789Sahrens if (!(seen & S_IXOTH)) { 905789Sahrens seen |= S_IXOTH; 9065331Samw if (type == ALLOW) { 907789Sahrens mode |= S_IXOTH; 908789Sahrens } 909789Sahrens } 910789Sahrens } 9119981STim.Haley@Sun.COM } else { 9129981STim.Haley@Sun.COM /* 9139981STim.Haley@Sun.COM * Only care if this IDENTIFIER_GROUP or 9149981STim.Haley@Sun.COM * USER ACE denies execute access to someone, 9159981STim.Haley@Sun.COM * mode is not affected 9169981STim.Haley@Sun.COM */ 9179981STim.Haley@Sun.COM if ((access_mask & ACE_EXECUTE) && type == DENY) 9189981STim.Haley@Sun.COM an_exec_denied = B_TRUE; 919789Sahrens } 920789Sahrens } 9219981STim.Haley@Sun.COM 92210143STim.Haley@Sun.COM /* 92310143STim.Haley@Sun.COM * Failure to allow is effectively a deny, so execute permission 92410143STim.Haley@Sun.COM * is denied if it was never mentioned or if we explicitly 92510143STim.Haley@Sun.COM * weren't allowed it. 92610143STim.Haley@Sun.COM */ 92710143STim.Haley@Sun.COM if (!an_exec_denied && 92810143STim.Haley@Sun.COM ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 92910143STim.Haley@Sun.COM (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 9309981STim.Haley@Sun.COM an_exec_denied = B_TRUE; 9319981STim.Haley@Sun.COM 9329981STim.Haley@Sun.COM if (an_exec_denied) 9339981STim.Haley@Sun.COM zp->z_phys->zp_flags &= ~ZFS_NO_EXECS_DENIED; 9349981STim.Haley@Sun.COM else 9359981STim.Haley@Sun.COM zp->z_phys->zp_flags |= ZFS_NO_EXECS_DENIED; 9369981STim.Haley@Sun.COM 937789Sahrens return (mode); 938789Sahrens } 939789Sahrens 940789Sahrens static zfs_acl_t * 9415331Samw zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify) 942789Sahrens { 943789Sahrens zfs_acl_t *aclp; 9445331Samw zfs_acl_node_t *aclnode; 945789Sahrens 9465331Samw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 9475331Samw 9485331Samw /* 9495331Samw * Version 0 to 1 znode_acl_phys has the size/count fields swapped. 9505331Samw * Version 0 didn't have a size field, only a count. 9515331Samw */ 9525331Samw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 9535331Samw aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size; 9545331Samw aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count); 9555331Samw } else { 9565331Samw aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count; 9575331Samw aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size; 9585331Samw } 9595331Samw 9605331Samw aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0); 9615331Samw aclnode->z_ace_count = aclp->z_acl_count; 9625331Samw if (will_modify) { 9635331Samw bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata, 9645331Samw aclp->z_acl_bytes); 9655331Samw } else { 9665331Samw aclnode->z_size = aclp->z_acl_bytes; 9675331Samw aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0]; 9685331Samw } 9695331Samw 9705331Samw list_insert_head(&aclp->z_acl, aclnode); 971789Sahrens 972789Sahrens return (aclp); 973789Sahrens } 974789Sahrens 975789Sahrens /* 97610143STim.Haley@Sun.COM * Read an external acl object. If the intent is to modify, always 97710143STim.Haley@Sun.COM * create a new acl and leave any cached acl in place. 978789Sahrens */ 9791544Seschrock static int 9805331Samw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) 981789Sahrens { 982789Sahrens uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj; 983789Sahrens zfs_acl_t *aclp; 9845331Samw size_t aclsize; 9855331Samw size_t acl_count; 9865331Samw zfs_acl_node_t *aclnode; 9871544Seschrock int error; 988789Sahrens 989789Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 990789Sahrens 99110143STim.Haley@Sun.COM if (zp->z_acl_cached && !will_modify) { 9929981STim.Haley@Sun.COM *aclpp = zp->z_acl_cached; 9939981STim.Haley@Sun.COM return (0); 9949981STim.Haley@Sun.COM } 9959981STim.Haley@Sun.COM 9961544Seschrock if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) { 9975331Samw *aclpp = zfs_acl_node_read_internal(zp, will_modify); 99810143STim.Haley@Sun.COM if (!will_modify) 99910143STim.Haley@Sun.COM zp->z_acl_cached = *aclpp; 10001544Seschrock return (0); 10011544Seschrock } 1002789Sahrens 10035331Samw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 10045331Samw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 10055331Samw zfs_acl_phys_v0_t *zacl0 = 10065331Samw (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl; 1007789Sahrens 10085331Samw aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count); 10095331Samw acl_count = zacl0->z_acl_count; 10105331Samw } else { 10115331Samw aclsize = zp->z_phys->zp_acl.z_acl_size; 10125331Samw acl_count = zp->z_phys->zp_acl.z_acl_count; 10135331Samw if (aclsize == 0) 10145331Samw aclsize = acl_count * sizeof (zfs_ace_t); 10155331Samw } 10165331Samw aclnode = zfs_acl_node_alloc(aclsize); 10175331Samw list_insert_head(&aclp->z_acl, aclnode); 10181544Seschrock error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0, 10199512SNeil.Perrin@Sun.COM aclsize, aclnode->z_acldata, DMU_READ_PREFETCH); 10205331Samw aclnode->z_ace_count = acl_count; 10215331Samw aclp->z_acl_count = acl_count; 10225331Samw aclp->z_acl_bytes = aclsize; 10235331Samw 10241544Seschrock if (error != 0) { 10251544Seschrock zfs_acl_free(aclp); 10267294Sperrin /* convert checksum errors into IO errors */ 10277294Sperrin if (error == ECKSUM) 10287294Sperrin error = EIO; 10291544Seschrock return (error); 10301544Seschrock } 1031789Sahrens 103210143STim.Haley@Sun.COM *aclpp = aclp; 103310143STim.Haley@Sun.COM if (!will_modify) 103410143STim.Haley@Sun.COM zp->z_acl_cached = aclp; 10351544Seschrock return (0); 1036789Sahrens } 1037789Sahrens 1038789Sahrens /* 10395331Samw * common code for setting ACLs. 1040789Sahrens * 1041789Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1042789Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1043789Sahrens * already checked the acl and knows whether to inherit. 1044789Sahrens */ 1045789Sahrens int 10469179SMark.Shellenbaum@Sun.COM zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1047789Sahrens { 1048789Sahrens int error; 1049789Sahrens znode_phys_t *zphys = zp->z_phys; 10505331Samw zfs_acl_phys_t *zacl = &zphys->zp_acl; 1051789Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1052789Sahrens uint64_t aoid = zphys->zp_acl.z_acl_extern_obj; 10535331Samw uint64_t off = 0; 10545331Samw dmu_object_type_t otype; 10555331Samw zfs_acl_node_t *aclnode; 1056789Sahrens 10575331Samw dmu_buf_will_dirty(zp->z_dbuf, tx); 1058789Sahrens 105910143STim.Haley@Sun.COM if (zp->z_acl_cached) { 10609981STim.Haley@Sun.COM zfs_acl_free(zp->z_acl_cached); 10619981STim.Haley@Sun.COM zp->z_acl_cached = NULL; 10629981STim.Haley@Sun.COM } 10639981STim.Haley@Sun.COM 10649179SMark.Shellenbaum@Sun.COM zphys->zp_mode = zfs_mode_compute(zp, aclp); 1065789Sahrens 1066789Sahrens /* 106710143STim.Haley@Sun.COM * Decide which object type to use. If we are forced to 106810143STim.Haley@Sun.COM * use old ACL format then transform ACL into zfs_oldace_t 10695331Samw * layout. 1070789Sahrens */ 10715331Samw if (!zfsvfs->z_use_fuids) { 10725331Samw otype = DMU_OT_OLDACL; 10735331Samw } else { 10745331Samw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 10755331Samw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 10769179SMark.Shellenbaum@Sun.COM zfs_acl_xform(zp, aclp, cr); 10775331Samw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 10785331Samw otype = DMU_OT_ACL; 10795331Samw } 10805331Samw 10815331Samw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 10825331Samw /* 10835331Samw * If ACL was previously external and we are now 10845331Samw * converting to new ACL format then release old 10855331Samw * ACL object and create a new one. 10865331Samw */ 10875331Samw if (aoid && aclp->z_version != zacl->z_acl_version) { 10885331Samw error = dmu_object_free(zfsvfs->z_os, 10895331Samw zp->z_phys->zp_acl.z_acl_extern_obj, tx); 10905331Samw if (error) 10915331Samw return (error); 10925331Samw aoid = 0; 10935331Samw } 1094789Sahrens if (aoid == 0) { 1095789Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 10965331Samw otype, aclp->z_acl_bytes, 10975331Samw otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE, 10985331Samw otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx); 1099789Sahrens } else { 1100789Sahrens (void) dmu_object_set_blocksize(zfsvfs->z_os, aoid, 11015331Samw aclp->z_acl_bytes, 0, tx); 1102789Sahrens } 1103789Sahrens zphys->zp_acl.z_acl_extern_obj = aoid; 11045331Samw for (aclnode = list_head(&aclp->z_acl); aclnode; 11055331Samw aclnode = list_next(&aclp->z_acl, aclnode)) { 11065331Samw if (aclnode->z_ace_count == 0) 11075331Samw continue; 11085331Samw dmu_write(zfsvfs->z_os, aoid, off, 11095331Samw aclnode->z_size, aclnode->z_acldata, tx); 11105331Samw off += aclnode->z_size; 11115331Samw } 1112789Sahrens } else { 11135331Samw void *start = zacl->z_ace_data; 1114789Sahrens /* 1115789Sahrens * Migrating back embedded? 1116789Sahrens */ 1117789Sahrens if (zphys->zp_acl.z_acl_extern_obj) { 1118789Sahrens error = dmu_object_free(zfsvfs->z_os, 11194300Smarks zp->z_phys->zp_acl.z_acl_extern_obj, tx); 1120789Sahrens if (error) 1121789Sahrens return (error); 1122789Sahrens zphys->zp_acl.z_acl_extern_obj = 0; 1123789Sahrens } 11245331Samw 11255331Samw for (aclnode = list_head(&aclp->z_acl); aclnode; 11265331Samw aclnode = list_next(&aclp->z_acl, aclnode)) { 11275331Samw if (aclnode->z_ace_count == 0) 11285331Samw continue; 11295331Samw bcopy(aclnode->z_acldata, start, aclnode->z_size); 11305331Samw start = (caddr_t)start + aclnode->z_size; 11315331Samw } 1132789Sahrens } 1133905Smarks 11345331Samw /* 11355331Samw * If Old version then swap count/bytes to match old 11365331Samw * layout of znode_acl_phys_t. 11375331Samw */ 11385331Samw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 11395331Samw zphys->zp_acl.z_acl_size = aclp->z_acl_count; 11405331Samw zphys->zp_acl.z_acl_count = aclp->z_acl_bytes; 11415331Samw } else { 11425331Samw zphys->zp_acl.z_acl_size = aclp->z_acl_bytes; 11435331Samw zphys->zp_acl.z_acl_count = aclp->z_acl_count; 1144905Smarks } 1145789Sahrens 11465331Samw zphys->zp_acl.z_acl_version = aclp->z_version; 11475331Samw 11485331Samw /* 11495331Samw * Replace ACL wide bits, but first clear them. 11505331Samw */ 11515331Samw zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS; 11525331Samw 11535331Samw zp->z_phys->zp_flags |= aclp->z_hints; 11545331Samw 11555331Samw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 11565331Samw zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL; 11575331Samw 1158789Sahrens return (0); 1159789Sahrens } 1160789Sahrens 1161789Sahrens /* 1162789Sahrens * Update access mask for prepended ACE 1163789Sahrens * 1164789Sahrens * This applies the "groupmask" value for aclmode property. 1165789Sahrens */ 1166789Sahrens static void 11675331Samw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, 11685331Samw mode_t mode, uint64_t owner) 1169789Sahrens { 1170789Sahrens int rmask, wmask, xmask; 1171789Sahrens int user_ace; 11725331Samw uint16_t aceflags; 11735331Samw uint32_t origmask, acepmask; 11745331Samw uint64_t fuid; 1175789Sahrens 11765331Samw aceflags = aclp->z_ops.ace_flags_get(acep); 11775331Samw fuid = aclp->z_ops.ace_who_get(acep); 11785331Samw origmask = aclp->z_ops.ace_mask_get(origacep); 11795331Samw acepmask = aclp->z_ops.ace_mask_get(acep); 11805331Samw 11815331Samw user_ace = (!(aceflags & 1182789Sahrens (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); 1183789Sahrens 11845331Samw if (user_ace && (fuid == owner)) { 1185789Sahrens rmask = S_IRUSR; 1186789Sahrens wmask = S_IWUSR; 1187789Sahrens xmask = S_IXUSR; 1188789Sahrens } else { 1189789Sahrens rmask = S_IRGRP; 1190789Sahrens wmask = S_IWGRP; 1191789Sahrens xmask = S_IXGRP; 1192789Sahrens } 1193789Sahrens 11945331Samw if (origmask & ACE_READ_DATA) { 11955331Samw if (mode & rmask) { 11965331Samw acepmask &= ~ACE_READ_DATA; 11975331Samw } else { 11985331Samw acepmask |= ACE_READ_DATA; 11995331Samw } 1200789Sahrens } 1201789Sahrens 12025331Samw if (origmask & ACE_WRITE_DATA) { 12035331Samw if (mode & wmask) { 12045331Samw acepmask &= ~ACE_WRITE_DATA; 12055331Samw } else { 12065331Samw acepmask |= ACE_WRITE_DATA; 12075331Samw } 1208789Sahrens } 1209789Sahrens 12105331Samw if (origmask & ACE_APPEND_DATA) { 12115331Samw if (mode & wmask) { 12125331Samw acepmask &= ~ACE_APPEND_DATA; 12135331Samw } else { 12145331Samw acepmask |= ACE_APPEND_DATA; 12155331Samw } 1216789Sahrens } 1217789Sahrens 12185331Samw if (origmask & ACE_EXECUTE) { 12195331Samw if (mode & xmask) { 12205331Samw acepmask &= ~ACE_EXECUTE; 12215331Samw } else { 12225331Samw acepmask |= ACE_EXECUTE; 12235331Samw } 1224789Sahrens } 12255331Samw aclp->z_ops.ace_mask_set(acep, acepmask); 1226789Sahrens } 1227789Sahrens 1228789Sahrens /* 1229789Sahrens * Apply mode to canonical six ACEs. 1230789Sahrens */ 1231789Sahrens static void 1232789Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode) 1233789Sahrens { 12345331Samw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 12355331Samw void *acep; 12365331Samw int maskoff = aclp->z_ops.ace_mask_off(); 12375331Samw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1238789Sahrens 12395331Samw ASSERT(aclnode != NULL); 12405331Samw 12415331Samw acep = (void *)((caddr_t)aclnode->z_acldata + 12425331Samw aclnode->z_size - (abstract_size * 6)); 1243789Sahrens 1244789Sahrens /* 1245789Sahrens * Fixup final ACEs to match the mode 1246789Sahrens */ 1247789Sahrens 12485331Samw adjust_ace_pair_common(acep, maskoff, abstract_size, 12495331Samw (mode & 0700) >> 6); /* owner@ */ 12505331Samw 12515331Samw acep = (caddr_t)acep + (abstract_size * 2); 12525331Samw 12535331Samw adjust_ace_pair_common(acep, maskoff, abstract_size, 12545331Samw (mode & 0070) >> 3); /* group@ */ 12555331Samw 12565331Samw acep = (caddr_t)acep + (abstract_size * 2); 12575331Samw adjust_ace_pair_common(acep, maskoff, 12585331Samw abstract_size, mode); /* everyone@ */ 1259789Sahrens } 1260789Sahrens 1261789Sahrens 1262789Sahrens static int 12635331Samw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny, 12645331Samw int entry_type, int accessmask) 1265789Sahrens { 12665331Samw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 12675331Samw uint16_t type = aclp->z_ops.ace_type_get(acep); 12685331Samw uint16_t flags = aclp->z_ops.ace_flags_get(acep); 12695331Samw 12705331Samw return (mask == accessmask && type == allow_deny && 12715331Samw ((flags & ACE_TYPE_FLAGS) == entry_type)); 1272789Sahrens } 1273789Sahrens 1274789Sahrens /* 1275789Sahrens * Can prepended ACE be reused? 1276789Sahrens */ 1277789Sahrens static int 12785331Samw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep) 1279789Sahrens { 1280789Sahrens int okay_masks; 12815331Samw uint16_t prevtype; 12825331Samw uint16_t prevflags; 12835331Samw uint16_t flags; 12845331Samw uint32_t mask, prevmask; 1285789Sahrens 12865331Samw if (prevacep == NULL) 1287789Sahrens return (B_FALSE); 1288789Sahrens 12895331Samw prevtype = aclp->z_ops.ace_type_get(prevacep); 12905331Samw prevflags = aclp->z_ops.ace_flags_get(prevacep); 12915331Samw flags = aclp->z_ops.ace_flags_get(acep); 12925331Samw mask = aclp->z_ops.ace_mask_get(acep); 12935331Samw prevmask = aclp->z_ops.ace_mask_get(prevacep); 12945331Samw 12955331Samw if (prevtype != DENY) 1296789Sahrens return (B_FALSE); 1297789Sahrens 12985331Samw if (prevflags != (flags & ACE_IDENTIFIER_GROUP)) 1299789Sahrens return (B_FALSE); 1300789Sahrens 13015331Samw okay_masks = (mask & OKAY_MASK_BITS); 1302789Sahrens 13035331Samw if (prevmask & ~okay_masks) 1304789Sahrens return (B_FALSE); 1305789Sahrens 1306789Sahrens return (B_TRUE); 1307789Sahrens } 1308789Sahrens 1309789Sahrens 13105331Samw /* 13115331Samw * Insert new ACL node into chain of zfs_acl_node_t's 13125331Samw * 13135331Samw * This will result in two possible results. 13145331Samw * 1. If the ACL is currently just a single zfs_acl_node and 13155331Samw * we are prepending the entry then current acl node will have 13165331Samw * a new node inserted above it. 13175331Samw * 13185331Samw * 2. If we are inserting in the middle of current acl node then 13195331Samw * the current node will be split in two and new node will be inserted 13205331Samw * in between the two split nodes. 13215331Samw */ 13225331Samw static zfs_acl_node_t * 13235331Samw zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep) 13245331Samw { 13255331Samw zfs_acl_node_t *newnode; 13265331Samw zfs_acl_node_t *trailernode = NULL; 13275331Samw zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp); 13285331Samw int curr_idx = aclp->z_curr_node->z_ace_idx; 13295331Samw int trailer_count; 13305331Samw size_t oldsize; 1331789Sahrens 13325331Samw newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep)); 13335331Samw newnode->z_ace_count = 1; 13345331Samw 13355331Samw oldsize = currnode->z_size; 13365331Samw 13375331Samw if (curr_idx != 1) { 13385331Samw trailernode = zfs_acl_node_alloc(0); 13395331Samw trailernode->z_acldata = acep; 13405331Samw 13415331Samw trailer_count = currnode->z_ace_count - curr_idx + 1; 13425331Samw currnode->z_ace_count = curr_idx - 1; 13435331Samw currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata; 13445331Samw trailernode->z_size = oldsize - currnode->z_size; 13455331Samw trailernode->z_ace_count = trailer_count; 1346789Sahrens } 1347789Sahrens 13485331Samw aclp->z_acl_count += 1; 13495331Samw aclp->z_acl_bytes += aclp->z_ops.ace_size(acep); 1350789Sahrens 13515331Samw if (curr_idx == 1) 13525331Samw list_insert_before(&aclp->z_acl, currnode, newnode); 13535331Samw else 13545331Samw list_insert_after(&aclp->z_acl, currnode, newnode); 13555331Samw if (trailernode) { 13565331Samw list_insert_after(&aclp->z_acl, newnode, trailernode); 13575331Samw aclp->z_curr_node = trailernode; 13585331Samw trailernode->z_ace_idx = 1; 1359789Sahrens } 1360789Sahrens 13615331Samw return (newnode); 1362789Sahrens } 1363789Sahrens 1364789Sahrens /* 1365789Sahrens * Prepend deny ACE 1366789Sahrens */ 13675331Samw static void * 13689179SMark.Shellenbaum@Sun.COM zfs_acl_prepend_deny(uint64_t uid, zfs_acl_t *aclp, void *acep, 1369789Sahrens mode_t mode) 1370789Sahrens { 13715331Samw zfs_acl_node_t *aclnode; 13725331Samw void *newacep; 13735331Samw uint64_t fuid; 13745331Samw uint16_t flags; 1375789Sahrens 13765331Samw aclnode = zfs_acl_ace_insert(aclp, acep); 13775331Samw newacep = aclnode->z_acldata; 13785331Samw fuid = aclp->z_ops.ace_who_get(acep); 13795331Samw flags = aclp->z_ops.ace_flags_get(acep); 13805331Samw zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS)); 13819179SMark.Shellenbaum@Sun.COM zfs_acl_prepend_fixup(aclp, newacep, acep, mode, uid); 13825331Samw 13835331Samw return (newacep); 1384789Sahrens } 1385789Sahrens 1386789Sahrens /* 1387789Sahrens * Split an inherited ACE into inherit_only ACE 1388789Sahrens * and original ACE with inheritance flags stripped off. 1389789Sahrens */ 1390789Sahrens static void 13915331Samw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep) 1392789Sahrens { 13935331Samw zfs_acl_node_t *aclnode; 13945435Smarks zfs_acl_node_t *currnode; 13955331Samw void *newacep; 13965331Samw uint16_t type, flags; 13975331Samw uint32_t mask; 13985331Samw uint64_t fuid; 1399789Sahrens 14005331Samw type = aclp->z_ops.ace_type_get(acep); 14015331Samw flags = aclp->z_ops.ace_flags_get(acep); 14025331Samw mask = aclp->z_ops.ace_mask_get(acep); 14035331Samw fuid = aclp->z_ops.ace_who_get(acep); 14045331Samw 14055331Samw aclnode = zfs_acl_ace_insert(aclp, acep); 14065331Samw newacep = aclnode->z_acldata; 14075331Samw 14085331Samw aclp->z_ops.ace_type_set(newacep, type); 14095331Samw aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE); 14105331Samw aclp->z_ops.ace_mask_set(newacep, mask); 14115331Samw aclp->z_ops.ace_type_set(newacep, type); 14125331Samw aclp->z_ops.ace_who_set(newacep, fuid); 14135331Samw aclp->z_next_ace = acep; 14145331Samw flags &= ~ALL_INHERIT; 14155331Samw aclp->z_ops.ace_flags_set(acep, flags); 14165435Smarks currnode = zfs_acl_curr_node(aclp); 14175435Smarks ASSERT(currnode->z_ace_idx >= 1); 14185331Samw currnode->z_ace_idx -= 1; 1419789Sahrens } 1420789Sahrens 1421789Sahrens /* 1422789Sahrens * Are ACES started at index i, the canonical six ACES? 1423789Sahrens */ 1424789Sahrens static int 14255331Samw zfs_have_canonical_six(zfs_acl_t *aclp) 1426789Sahrens { 14275331Samw void *acep; 14285331Samw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 14295331Samw int i = 0; 14305331Samw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 14315331Samw 14325331Samw ASSERT(aclnode != NULL); 1433789Sahrens 14345331Samw if (aclnode->z_ace_count < 6) 14355331Samw return (0); 14365331Samw 14375331Samw acep = (void *)((caddr_t)aclnode->z_acldata + 14385331Samw aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6)); 14395331Samw 14405331Samw if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1441789Sahrens DENY, ACE_OWNER, 0) && 14425331Samw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 14435331Samw ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) && 14445331Samw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY, 14455331Samw OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep + 14465331Samw (abstract_size * i++), 14475331Samw ALLOW, OWNING_GROUP, 0) && 14485331Samw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1449789Sahrens DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) && 14505331Samw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 14515331Samw ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) { 1452789Sahrens return (1); 1453789Sahrens } else { 1454789Sahrens return (0); 1455789Sahrens } 1456789Sahrens } 1457789Sahrens 14585331Samw 1459789Sahrens /* 1460789Sahrens * Apply step 1g, to group entries 1461789Sahrens * 1462789Sahrens * Need to deal with corner case where group may have 1463789Sahrens * greater permissions than owner. If so then limit 1464789Sahrens * group permissions, based on what extra permissions 1465789Sahrens * group has. 1466789Sahrens */ 1467789Sahrens static void 14685331Samw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep, 14695331Samw mode_t mode) 1470789Sahrens { 14715331Samw uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep); 14725331Samw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 14735331Samw uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep); 1474789Sahrens mode_t extramode = (mode >> 3) & 07; 1475789Sahrens mode_t ownermode = (mode >> 6); 1476789Sahrens 14775331Samw if (prevflags & ACE_IDENTIFIER_GROUP) { 1478789Sahrens 1479789Sahrens extramode &= ~ownermode; 1480789Sahrens 1481789Sahrens if (extramode) { 14825331Samw if (extramode & S_IROTH) { 14835331Samw prevmask &= ~ACE_READ_DATA; 14845331Samw mask &= ~ACE_READ_DATA; 1485789Sahrens } 14865331Samw if (extramode & S_IWOTH) { 14875331Samw prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 14885331Samw mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1489789Sahrens } 14905331Samw if (extramode & S_IXOTH) { 14915331Samw prevmask &= ~ACE_EXECUTE; 14925331Samw mask &= ~ACE_EXECUTE; 1493789Sahrens } 1494789Sahrens } 1495789Sahrens } 14965331Samw aclp->z_ops.ace_mask_set(acep, mask); 14975331Samw aclp->z_ops.ace_mask_set(prevacep, prevmask); 1498789Sahrens } 1499789Sahrens 1500789Sahrens /* 1501789Sahrens * Apply the chmod algorithm as described 1502789Sahrens * in PSARC/2002/240 1503789Sahrens */ 15045824Smarks static void 15059179SMark.Shellenbaum@Sun.COM zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t uid, 15069179SMark.Shellenbaum@Sun.COM uint64_t mode, zfs_acl_t *aclp) 1507789Sahrens { 15085331Samw void *acep = NULL, *prevacep = NULL; 15095331Samw uint64_t who; 1510789Sahrens int i; 1511789Sahrens int entry_type; 1512789Sahrens int reuse_deny; 1513789Sahrens int need_canonical_six = 1; 15145331Samw uint16_t iflags, type; 15155331Samw uint32_t access_mask; 1516789Sahrens 15175489Smarks /* 15185489Smarks * If discard then just discard all ACL nodes which 15195489Smarks * represent the ACEs. 15205489Smarks * 15215489Smarks * New owner@/group@/everone@ ACEs will be added 15225489Smarks * later. 15235489Smarks */ 15245489Smarks if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 15255489Smarks zfs_acl_release_nodes(aclp); 15265489Smarks 15275331Samw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 15285331Samw &iflags, &type)) { 15295331Samw 15305331Samw entry_type = (iflags & ACE_TYPE_FLAGS); 15315331Samw iflags = (iflags & ALL_INHERIT); 1532789Sahrens 15335331Samw if ((type != ALLOW && type != DENY) || 1534905Smarks (iflags & ACE_INHERIT_ONLY_ACE)) { 1535905Smarks if (iflags) 15365331Samw aclp->z_hints |= ZFS_INHERIT_ACE; 15375331Samw switch (type) { 15385331Samw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 15395331Samw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 15405331Samw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 15415331Samw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 15425331Samw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 15435331Samw break; 15445331Samw } 15455331Samw goto nextace; 1546789Sahrens } 1547789Sahrens 1548789Sahrens /* 1549789Sahrens * Need to split ace into two? 1550789Sahrens */ 1551905Smarks if ((iflags & (ACE_FILE_INHERIT_ACE| 1552789Sahrens ACE_DIRECTORY_INHERIT_ACE)) && 1553905Smarks (!(iflags & ACE_INHERIT_ONLY_ACE))) { 15545331Samw zfs_acl_split_ace(aclp, acep); 15555331Samw aclp->z_hints |= ZFS_INHERIT_ACE; 15565331Samw goto nextace; 1557789Sahrens } 1558789Sahrens 1559789Sahrens if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 1560789Sahrens (entry_type == OWNING_GROUP)) { 15615331Samw access_mask &= ~OGE_CLEAR; 15625331Samw aclp->z_ops.ace_mask_set(acep, access_mask); 15635331Samw goto nextace; 1564789Sahrens } else { 15655331Samw reuse_deny = B_TRUE; 15665331Samw if (type == ALLOW) { 1567789Sahrens 1568789Sahrens /* 1569789Sahrens * Check preceding ACE if any, to see 1570789Sahrens * if we need to prepend a DENY ACE. 1571789Sahrens * This is only applicable when the acl_mode 1572789Sahrens * property == groupmask. 1573789Sahrens */ 15742676Seschrock if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) { 1575789Sahrens 15765331Samw reuse_deny = zfs_reuse_deny(aclp, acep, 15775331Samw prevacep); 1578789Sahrens 15795959Smarks if (!reuse_deny) { 15805331Samw prevacep = 15819179SMark.Shellenbaum@Sun.COM zfs_acl_prepend_deny(uid, 15825331Samw aclp, acep, mode); 1583789Sahrens } else { 1584789Sahrens zfs_acl_prepend_fixup( 15855331Samw aclp, prevacep, 15869179SMark.Shellenbaum@Sun.COM acep, mode, uid); 1587789Sahrens } 15885331Samw zfs_fixup_group_entries(aclp, acep, 15895331Samw prevacep, mode); 1590789Sahrens } 1591789Sahrens } 1592789Sahrens } 15935331Samw nextace: 15945331Samw prevacep = acep; 1595789Sahrens } 1596789Sahrens 1597789Sahrens /* 1598789Sahrens * Check out last six aces, if we have six. 1599789Sahrens */ 1600789Sahrens 1601789Sahrens if (aclp->z_acl_count >= 6) { 16025331Samw if (zfs_have_canonical_six(aclp)) { 1603789Sahrens need_canonical_six = 0; 1604789Sahrens } 1605789Sahrens } 1606789Sahrens 1607789Sahrens if (need_canonical_six) { 16085331Samw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 16095331Samw void *zacep; 16105331Samw zfs_acl_node_t *aclnode = 16115331Samw zfs_acl_node_alloc(abstract_size * 6); 1612789Sahrens 16135331Samw aclnode->z_size = abstract_size * 6; 16145331Samw aclnode->z_ace_count = 6; 16155331Samw aclp->z_acl_bytes += aclnode->z_size; 16165331Samw list_insert_tail(&aclp->z_acl, aclnode); 16175331Samw 16185331Samw zacep = aclnode->z_acldata; 16195331Samw 16205331Samw i = 0; 16215331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 16225331Samw 0, DENY, -1, ACE_OWNER); 16235331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 16245331Samw OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER); 16255331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 16265331Samw DENY, -1, OWNING_GROUP); 16275331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 16285331Samw ALLOW, -1, OWNING_GROUP); 16295331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 16305331Samw EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE); 16315331Samw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 16325331Samw EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE); 1633789Sahrens aclp->z_acl_count += 6; 1634789Sahrens } 1635789Sahrens 1636789Sahrens zfs_acl_fixup_canonical_six(aclp, mode); 1637789Sahrens } 1638789Sahrens 1639789Sahrens int 16405824Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1641789Sahrens { 1642789Sahrens int error; 1643789Sahrens 16445824Smarks mutex_enter(&zp->z_lock); 1645789Sahrens mutex_enter(&zp->z_acl_lock); 16465824Smarks *aclp = NULL; 16475824Smarks error = zfs_acl_node_read(zp, aclp, B_TRUE); 16489179SMark.Shellenbaum@Sun.COM if (error == 0) { 16499179SMark.Shellenbaum@Sun.COM (*aclp)->z_hints = zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS; 16509179SMark.Shellenbaum@Sun.COM zfs_acl_chmod(zp->z_zfsvfs, zp->z_phys->zp_uid, mode, *aclp); 16519179SMark.Shellenbaum@Sun.COM } 1652789Sahrens mutex_exit(&zp->z_acl_lock); 16535824Smarks mutex_exit(&zp->z_lock); 1654789Sahrens return (error); 1655789Sahrens } 1656789Sahrens 1657789Sahrens /* 1658789Sahrens * strip off write_owner and write_acl 1659789Sahrens */ 1660789Sahrens static void 16616385Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1662789Sahrens { 16635331Samw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 16645331Samw 16656385Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 16665331Samw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 16676385Smarks mask &= ~RESTRICTED_CLEAR; 16685331Samw aclp->z_ops.ace_mask_set(acep, mask); 16695331Samw } 16705331Samw } 16715331Samw 16725331Samw /* 16735331Samw * Should ACE be inherited? 16745331Samw */ 16755331Samw static int 16769179SMark.Shellenbaum@Sun.COM zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 16775331Samw { 16785331Samw int iflags = (acep_flags & 0xf); 16795331Samw 16805331Samw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 16815331Samw return (1); 16825331Samw else if (iflags & ACE_FILE_INHERIT_ACE) 16835331Samw return (!((vtype == VDIR) && 16845331Samw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 16855331Samw return (0); 1686789Sahrens } 1687789Sahrens 1688789Sahrens /* 1689789Sahrens * inherit inheritable ACEs from parent 1690789Sahrens */ 1691789Sahrens static zfs_acl_t * 16929179SMark.Shellenbaum@Sun.COM zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 16939179SMark.Shellenbaum@Sun.COM uint64_t mode, boolean_t *need_chmod) 1694789Sahrens { 16955331Samw void *pacep; 16965331Samw void *acep, *acep2; 16975331Samw zfs_acl_node_t *aclnode, *aclnode2; 1698789Sahrens zfs_acl_t *aclp = NULL; 16995331Samw uint64_t who; 17005331Samw uint32_t access_mask; 17015331Samw uint16_t iflags, newflags, type; 17025331Samw size_t ace_size; 17035331Samw void *data1, *data2; 17045331Samw size_t data1sz, data2sz; 17059179SMark.Shellenbaum@Sun.COM boolean_t vdir = vtype == VDIR; 17069179SMark.Shellenbaum@Sun.COM boolean_t vreg = vtype == VREG; 17078053SMark.Shellenbaum@Sun.COM boolean_t passthrough, passthrough_x, noallow; 17088053SMark.Shellenbaum@Sun.COM 17098053SMark.Shellenbaum@Sun.COM passthrough_x = 17108053SMark.Shellenbaum@Sun.COM zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 17118053SMark.Shellenbaum@Sun.COM passthrough = passthrough_x || 17128053SMark.Shellenbaum@Sun.COM zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 17138053SMark.Shellenbaum@Sun.COM noallow = 17148053SMark.Shellenbaum@Sun.COM zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1715789Sahrens 17166385Smarks *need_chmod = B_TRUE; 17175331Samw pacep = NULL; 17187559SMark.Shellenbaum@Sun.COM aclp = zfs_acl_alloc(paclp->z_version); 17198053SMark.Shellenbaum@Sun.COM if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD) 17208053SMark.Shellenbaum@Sun.COM return (aclp); 17218053SMark.Shellenbaum@Sun.COM while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 17228053SMark.Shellenbaum@Sun.COM &access_mask, &iflags, &type)) { 17238053SMark.Shellenbaum@Sun.COM 17248053SMark.Shellenbaum@Sun.COM /* 17258053SMark.Shellenbaum@Sun.COM * don't inherit bogus ACEs 17268053SMark.Shellenbaum@Sun.COM */ 17278053SMark.Shellenbaum@Sun.COM if (!zfs_acl_valid_ace_type(type, iflags)) 17288053SMark.Shellenbaum@Sun.COM continue; 17298053SMark.Shellenbaum@Sun.COM 17308053SMark.Shellenbaum@Sun.COM if (noallow && type == ALLOW) 17318053SMark.Shellenbaum@Sun.COM continue; 17328053SMark.Shellenbaum@Sun.COM 17338053SMark.Shellenbaum@Sun.COM ace_size = aclp->z_ops.ace_size(pacep); 17348053SMark.Shellenbaum@Sun.COM 17359179SMark.Shellenbaum@Sun.COM if (!zfs_ace_can_use(vtype, iflags)) 17368053SMark.Shellenbaum@Sun.COM continue; 1737789Sahrens 17388053SMark.Shellenbaum@Sun.COM /* 17398053SMark.Shellenbaum@Sun.COM * If owner@, group@, or everyone@ inheritable 17408053SMark.Shellenbaum@Sun.COM * then zfs_acl_chmod() isn't needed. 17418053SMark.Shellenbaum@Sun.COM */ 17428053SMark.Shellenbaum@Sun.COM if (passthrough && 17438053SMark.Shellenbaum@Sun.COM ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 17448053SMark.Shellenbaum@Sun.COM ((iflags & OWNING_GROUP) == 17458053SMark.Shellenbaum@Sun.COM OWNING_GROUP)) && (vreg || (vdir && (iflags & 17468053SMark.Shellenbaum@Sun.COM ACE_DIRECTORY_INHERIT_ACE)))) { 17478053SMark.Shellenbaum@Sun.COM *need_chmod = B_FALSE; 17487559SMark.Shellenbaum@Sun.COM 17498053SMark.Shellenbaum@Sun.COM if (!vdir && passthrough_x && 17508053SMark.Shellenbaum@Sun.COM ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 17518053SMark.Shellenbaum@Sun.COM access_mask &= ~ACE_EXECUTE; 17528053SMark.Shellenbaum@Sun.COM } 17538053SMark.Shellenbaum@Sun.COM } 1754789Sahrens 17558053SMark.Shellenbaum@Sun.COM aclnode = zfs_acl_node_alloc(ace_size); 17568053SMark.Shellenbaum@Sun.COM list_insert_tail(&aclp->z_acl, aclnode); 17578053SMark.Shellenbaum@Sun.COM acep = aclnode->z_acldata; 17586385Smarks 17598053SMark.Shellenbaum@Sun.COM zfs_set_ace(aclp, acep, access_mask, type, 17608053SMark.Shellenbaum@Sun.COM who, iflags|ACE_INHERITED_ACE); 17618053SMark.Shellenbaum@Sun.COM 17628053SMark.Shellenbaum@Sun.COM /* 17638053SMark.Shellenbaum@Sun.COM * Copy special opaque data if any 17648053SMark.Shellenbaum@Sun.COM */ 17658053SMark.Shellenbaum@Sun.COM if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 17668053SMark.Shellenbaum@Sun.COM VERIFY((data2sz = aclp->z_ops.ace_data(acep, 17678053SMark.Shellenbaum@Sun.COM &data2)) == data1sz); 17688053SMark.Shellenbaum@Sun.COM bcopy(data1, data2, data2sz); 17698053SMark.Shellenbaum@Sun.COM } 17708053SMark.Shellenbaum@Sun.COM aclp->z_acl_count++; 17718053SMark.Shellenbaum@Sun.COM aclnode->z_ace_count++; 17728053SMark.Shellenbaum@Sun.COM aclp->z_acl_bytes += aclnode->z_size; 17738053SMark.Shellenbaum@Sun.COM newflags = aclp->z_ops.ace_flags_get(acep); 17748053SMark.Shellenbaum@Sun.COM 17758053SMark.Shellenbaum@Sun.COM if (vdir) 17768053SMark.Shellenbaum@Sun.COM aclp->z_hints |= ZFS_INHERIT_ACE; 17776385Smarks 17788053SMark.Shellenbaum@Sun.COM if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 17798053SMark.Shellenbaum@Sun.COM newflags &= ~ALL_INHERIT; 17808053SMark.Shellenbaum@Sun.COM aclp->z_ops.ace_flags_set(acep, 17818053SMark.Shellenbaum@Sun.COM newflags|ACE_INHERITED_ACE); 17828053SMark.Shellenbaum@Sun.COM zfs_restricted_update(zfsvfs, aclp, acep); 17838053SMark.Shellenbaum@Sun.COM continue; 17848053SMark.Shellenbaum@Sun.COM } 17858053SMark.Shellenbaum@Sun.COM 17868053SMark.Shellenbaum@Sun.COM ASSERT(vdir); 17878053SMark.Shellenbaum@Sun.COM 17888053SMark.Shellenbaum@Sun.COM newflags = aclp->z_ops.ace_flags_get(acep); 17898053SMark.Shellenbaum@Sun.COM if ((iflags & (ACE_FILE_INHERIT_ACE | 17908053SMark.Shellenbaum@Sun.COM ACE_DIRECTORY_INHERIT_ACE)) != 17918053SMark.Shellenbaum@Sun.COM ACE_FILE_INHERIT_ACE) { 17928053SMark.Shellenbaum@Sun.COM aclnode2 = zfs_acl_node_alloc(ace_size); 17938053SMark.Shellenbaum@Sun.COM list_insert_tail(&aclp->z_acl, aclnode2); 17948053SMark.Shellenbaum@Sun.COM acep2 = aclnode2->z_acldata; 17958053SMark.Shellenbaum@Sun.COM zfs_set_ace(aclp, acep2, 17968053SMark.Shellenbaum@Sun.COM access_mask, type, who, 17978053SMark.Shellenbaum@Sun.COM iflags|ACE_INHERITED_ACE); 17988053SMark.Shellenbaum@Sun.COM newflags |= ACE_INHERIT_ONLY_ACE; 17998053SMark.Shellenbaum@Sun.COM aclp->z_ops.ace_flags_set(acep, newflags); 18008053SMark.Shellenbaum@Sun.COM newflags &= ~ALL_INHERIT; 18018053SMark.Shellenbaum@Sun.COM aclp->z_ops.ace_flags_set(acep2, 18028053SMark.Shellenbaum@Sun.COM newflags|ACE_INHERITED_ACE); 1803789Sahrens 18046385Smarks /* 18056385Smarks * Copy special opaque data if any 18066385Smarks */ 18078053SMark.Shellenbaum@Sun.COM if ((data1sz = aclp->z_ops.ace_data(acep, 18086385Smarks &data1)) != 0) { 18098053SMark.Shellenbaum@Sun.COM VERIFY((data2sz = 18108053SMark.Shellenbaum@Sun.COM aclp->z_ops.ace_data(acep2, 18116385Smarks &data2)) == data1sz); 18128053SMark.Shellenbaum@Sun.COM bcopy(data1, data2, data1sz); 18136385Smarks } 18146385Smarks aclp->z_acl_count++; 18158053SMark.Shellenbaum@Sun.COM aclnode2->z_ace_count++; 18166385Smarks aclp->z_acl_bytes += aclnode->z_size; 18178053SMark.Shellenbaum@Sun.COM zfs_restricted_update(zfsvfs, aclp, acep2); 18188053SMark.Shellenbaum@Sun.COM } else { 18198053SMark.Shellenbaum@Sun.COM newflags |= ACE_INHERIT_ONLY_ACE; 18208053SMark.Shellenbaum@Sun.COM aclp->z_ops.ace_flags_set(acep, 18218053SMark.Shellenbaum@Sun.COM newflags|ACE_INHERITED_ACE); 1822789Sahrens } 1823789Sahrens } 1824789Sahrens return (aclp); 1825789Sahrens } 1826789Sahrens 1827789Sahrens /* 1828789Sahrens * Create file system object initial permissions 1829789Sahrens * including inheritable ACEs. 1830789Sahrens */ 18319179SMark.Shellenbaum@Sun.COM int 18329179SMark.Shellenbaum@Sun.COM zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 18339179SMark.Shellenbaum@Sun.COM vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1834789Sahrens { 1835789Sahrens int error; 18369179SMark.Shellenbaum@Sun.COM zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 18375331Samw zfs_acl_t *paclp; 18385959Smarks gid_t gid; 18396385Smarks boolean_t need_chmod = B_TRUE; 18405331Samw 18419179SMark.Shellenbaum@Sun.COM bzero(acl_ids, sizeof (zfs_acl_ids_t)); 18429179SMark.Shellenbaum@Sun.COM acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1843789Sahrens 18449179SMark.Shellenbaum@Sun.COM if (vsecp) 18459179SMark.Shellenbaum@Sun.COM if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 18469179SMark.Shellenbaum@Sun.COM &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 18479179SMark.Shellenbaum@Sun.COM return (error); 1848789Sahrens 1849789Sahrens /* 1850789Sahrens * Determine uid and gid. 1851789Sahrens */ 185211249SMark.Shellenbaum@Sun.COM if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1853789Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 18549179SMark.Shellenbaum@Sun.COM acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 18559179SMark.Shellenbaum@Sun.COM (uint64_t)vap->va_uid, cr, 18569179SMark.Shellenbaum@Sun.COM ZFS_OWNER, &acl_ids->z_fuidp); 18579179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 18589179SMark.Shellenbaum@Sun.COM (uint64_t)vap->va_gid, cr, 18599179SMark.Shellenbaum@Sun.COM ZFS_GROUP, &acl_ids->z_fuidp); 18605959Smarks gid = vap->va_gid; 1861789Sahrens } else { 18629179SMark.Shellenbaum@Sun.COM acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 18639179SMark.Shellenbaum@Sun.COM cr, &acl_ids->z_fuidp); 18649179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = 0; 18655959Smarks if (vap->va_mask & AT_GID) { 18669179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 18679179SMark.Shellenbaum@Sun.COM (uint64_t)vap->va_gid, 18689179SMark.Shellenbaum@Sun.COM cr, ZFS_GROUP, &acl_ids->z_fuidp); 18695959Smarks gid = vap->va_gid; 18709179SMark.Shellenbaum@Sun.COM if (acl_ids->z_fgid != dzp->z_phys->zp_gid && 18715959Smarks !groupmember(vap->va_gid, cr) && 18725959Smarks secpolicy_vnode_create_gid(cr) != 0) 18739179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = 0; 18745959Smarks } 18759179SMark.Shellenbaum@Sun.COM if (acl_ids->z_fgid == 0) { 18769179SMark.Shellenbaum@Sun.COM if (dzp->z_phys->zp_mode & S_ISGID) { 1877*11574SJohn.Harres@Sun.COM char *domain; 1878*11574SJohn.Harres@Sun.COM uint32_t rid; 1879*11574SJohn.Harres@Sun.COM 18809179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = dzp->z_phys->zp_gid; 18819179SMark.Shellenbaum@Sun.COM gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 18825959Smarks cr, ZFS_GROUP); 1883*11574SJohn.Harres@Sun.COM 1884*11574SJohn.Harres@Sun.COM if (zfsvfs->z_use_fuids && 1885*11574SJohn.Harres@Sun.COM IS_EPHEMERAL(acl_ids->z_fgid)) { 1886*11574SJohn.Harres@Sun.COM domain = zfs_fuid_idx_domain( 1887*11574SJohn.Harres@Sun.COM &zfsvfs->z_fuid_idx, 1888*11574SJohn.Harres@Sun.COM FUID_INDEX(acl_ids->z_fgid)); 1889*11574SJohn.Harres@Sun.COM rid = FUID_RID(acl_ids->z_fgid); 1890*11574SJohn.Harres@Sun.COM zfs_fuid_node_add(&acl_ids->z_fuidp, 1891*11574SJohn.Harres@Sun.COM domain, rid, 1892*11574SJohn.Harres@Sun.COM FUID_INDEX(acl_ids->z_fgid), 1893*11574SJohn.Harres@Sun.COM acl_ids->z_fgid, ZFS_GROUP); 1894*11574SJohn.Harres@Sun.COM } 18955959Smarks } else { 18969179SMark.Shellenbaum@Sun.COM acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 18979179SMark.Shellenbaum@Sun.COM ZFS_GROUP, cr, &acl_ids->z_fuidp); 18985959Smarks gid = crgetgid(cr); 18995959Smarks } 19005331Samw } 1901789Sahrens } 1902789Sahrens 1903789Sahrens /* 1904789Sahrens * If we're creating a directory, and the parent directory has the 1905789Sahrens * set-GID bit set, set in on the new directory. 1906789Sahrens * Otherwise, if the user is neither privileged nor a member of the 1907789Sahrens * file's new group, clear the file's set-GID bit. 1908789Sahrens */ 1909789Sahrens 19109179SMark.Shellenbaum@Sun.COM if (!(flag & IS_ROOT_NODE) && (dzp->z_phys->zp_mode & S_ISGID) && 19119179SMark.Shellenbaum@Sun.COM (vap->va_type == VDIR)) { 19129179SMark.Shellenbaum@Sun.COM acl_ids->z_mode |= S_ISGID; 19135959Smarks } else { 19149179SMark.Shellenbaum@Sun.COM if ((acl_ids->z_mode & S_ISGID) && 1915789Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 19169179SMark.Shellenbaum@Sun.COM acl_ids->z_mode &= ~S_ISGID; 1917789Sahrens } 1918789Sahrens 19199179SMark.Shellenbaum@Sun.COM if (acl_ids->z_aclp == NULL) { 19209179SMark.Shellenbaum@Sun.COM mutex_enter(&dzp->z_lock); 19219179SMark.Shellenbaum@Sun.COM if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && 19229179SMark.Shellenbaum@Sun.COM (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)) && 19239179SMark.Shellenbaum@Sun.COM !(dzp->z_phys->zp_flags & ZFS_XATTR)) { 19249179SMark.Shellenbaum@Sun.COM mutex_enter(&dzp->z_acl_lock); 19259179SMark.Shellenbaum@Sun.COM VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE)); 19269179SMark.Shellenbaum@Sun.COM mutex_exit(&dzp->z_acl_lock); 19279179SMark.Shellenbaum@Sun.COM acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 19289179SMark.Shellenbaum@Sun.COM vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 19295331Samw } else { 19309179SMark.Shellenbaum@Sun.COM acl_ids->z_aclp = 19319179SMark.Shellenbaum@Sun.COM zfs_acl_alloc(zfs_acl_version_zp(dzp)); 19325331Samw } 19339179SMark.Shellenbaum@Sun.COM mutex_exit(&dzp->z_lock); 19349179SMark.Shellenbaum@Sun.COM if (need_chmod) { 19359179SMark.Shellenbaum@Sun.COM acl_ids->z_aclp->z_hints = (vap->va_type == VDIR) ? 19369179SMark.Shellenbaum@Sun.COM ZFS_ACL_AUTO_INHERIT : 0; 19379179SMark.Shellenbaum@Sun.COM zfs_acl_chmod(zfsvfs, acl_ids->z_fuid, 19389179SMark.Shellenbaum@Sun.COM acl_ids->z_mode, acl_ids->z_aclp); 19399179SMark.Shellenbaum@Sun.COM } 1940789Sahrens } 19415331Samw 19429179SMark.Shellenbaum@Sun.COM return (0); 19439179SMark.Shellenbaum@Sun.COM } 19445331Samw 19459179SMark.Shellenbaum@Sun.COM /* 19469179SMark.Shellenbaum@Sun.COM * Free ACL and fuid_infop, but not the acl_ids structure 19479179SMark.Shellenbaum@Sun.COM */ 19489179SMark.Shellenbaum@Sun.COM void 19499179SMark.Shellenbaum@Sun.COM zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 19509179SMark.Shellenbaum@Sun.COM { 19519179SMark.Shellenbaum@Sun.COM if (acl_ids->z_aclp) 19529179SMark.Shellenbaum@Sun.COM zfs_acl_free(acl_ids->z_aclp); 19539179SMark.Shellenbaum@Sun.COM if (acl_ids->z_fuidp) 19549179SMark.Shellenbaum@Sun.COM zfs_fuid_info_free(acl_ids->z_fuidp); 19559179SMark.Shellenbaum@Sun.COM acl_ids->z_aclp = NULL; 19569179SMark.Shellenbaum@Sun.COM acl_ids->z_fuidp = NULL; 19579179SMark.Shellenbaum@Sun.COM } 19585331Samw 19599396SMatthew.Ahrens@Sun.COM boolean_t 19609396SMatthew.Ahrens@Sun.COM zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 19619396SMatthew.Ahrens@Sun.COM { 19629396SMatthew.Ahrens@Sun.COM return (zfs_usergroup_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 19639396SMatthew.Ahrens@Sun.COM zfs_usergroup_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 19649396SMatthew.Ahrens@Sun.COM } 1965789Sahrens 1966789Sahrens /* 1967789Sahrens * Retrieve a files ACL 1968789Sahrens */ 1969789Sahrens int 19705331Samw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1971789Sahrens { 1972789Sahrens zfs_acl_t *aclp; 19735331Samw ulong_t mask; 1974789Sahrens int error; 19755331Samw int count = 0; 19765331Samw int largeace = 0; 1977789Sahrens 19785331Samw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 19795331Samw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 19805331Samw 19815331Samw if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 19825331Samw return (error); 1983789Sahrens 1984789Sahrens if (mask == 0) 1985789Sahrens return (ENOSYS); 1986789Sahrens 1987789Sahrens mutex_enter(&zp->z_acl_lock); 1988789Sahrens 19895331Samw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 19901544Seschrock if (error != 0) { 19911544Seschrock mutex_exit(&zp->z_acl_lock); 19921544Seschrock return (error); 19931544Seschrock } 19941544Seschrock 19955331Samw /* 19965331Samw * Scan ACL to determine number of ACEs 19975331Samw */ 19985331Samw if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) && 19995331Samw !(mask & VSA_ACE_ALLTYPES)) { 20005331Samw void *zacep = NULL; 20015331Samw uint64_t who; 20025331Samw uint32_t access_mask; 20035331Samw uint16_t type, iflags; 20045331Samw 20055331Samw while (zacep = zfs_acl_next_ace(aclp, zacep, 20065331Samw &who, &access_mask, &iflags, &type)) { 20075331Samw switch (type) { 20085331Samw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 20095331Samw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 20105331Samw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 20115331Samw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 20125331Samw largeace++; 20135331Samw continue; 20145331Samw default: 20155331Samw count++; 20165331Samw } 20175331Samw } 20185331Samw vsecp->vsa_aclcnt = count; 20195331Samw } else 20205331Samw count = aclp->z_acl_count; 2021789Sahrens 2022789Sahrens if (mask & VSA_ACECNT) { 20235331Samw vsecp->vsa_aclcnt = count; 2024789Sahrens } 2025789Sahrens 2026789Sahrens if (mask & VSA_ACE) { 20275331Samw size_t aclsz; 20285331Samw 20295331Samw aclsz = count * sizeof (ace_t) + 20305331Samw sizeof (ace_object_t) * largeace; 20315331Samw 20325331Samw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 20335331Samw vsecp->vsa_aclentsz = aclsz; 20345331Samw 20355331Samw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 20365771Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 20375331Samw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 20385331Samw else { 203910295SMark.Shellenbaum@Sun.COM zfs_acl_node_t *aclnode; 204010295SMark.Shellenbaum@Sun.COM void *start = vsecp->vsa_aclentp; 204110295SMark.Shellenbaum@Sun.COM 204210295SMark.Shellenbaum@Sun.COM for (aclnode = list_head(&aclp->z_acl); aclnode; 204310295SMark.Shellenbaum@Sun.COM aclnode = list_next(&aclp->z_acl, aclnode)) { 204410295SMark.Shellenbaum@Sun.COM bcopy(aclnode->z_acldata, start, 204510295SMark.Shellenbaum@Sun.COM aclnode->z_size); 204610295SMark.Shellenbaum@Sun.COM start = (caddr_t)start + aclnode->z_size; 204710295SMark.Shellenbaum@Sun.COM } 204810295SMark.Shellenbaum@Sun.COM ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 204910295SMark.Shellenbaum@Sun.COM aclp->z_acl_bytes); 20505331Samw } 20515331Samw } 20525331Samw if (mask & VSA_ACE_ACLFLAGS) { 20535331Samw vsecp->vsa_aclflags = 0; 20545331Samw if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED) 20555331Samw vsecp->vsa_aclflags |= ACL_DEFAULTED; 20565331Samw if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED) 20575331Samw vsecp->vsa_aclflags |= ACL_PROTECTED; 20585331Samw if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT) 20595331Samw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 2060789Sahrens } 2061789Sahrens 2062789Sahrens mutex_exit(&zp->z_acl_lock); 2063789Sahrens 2064789Sahrens return (0); 2065789Sahrens } 2066789Sahrens 20675331Samw int 20685331Samw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 20699179SMark.Shellenbaum@Sun.COM vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 20705331Samw { 20715331Samw zfs_acl_t *aclp; 20725331Samw zfs_acl_node_t *aclnode; 20735331Samw int aclcnt = vsecp->vsa_aclcnt; 20745331Samw int error; 20755331Samw 20765331Samw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 20775331Samw return (EINVAL); 20785331Samw 20795331Samw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 20805331Samw 20815331Samw aclp->z_hints = 0; 20825331Samw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 20835331Samw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 20845331Samw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 20855331Samw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 20865331Samw aclcnt, &aclnode->z_size)) != 0) { 20875331Samw zfs_acl_free(aclp); 20885331Samw zfs_acl_node_free(aclnode); 20895331Samw return (error); 20905331Samw } 20915331Samw } else { 20929179SMark.Shellenbaum@Sun.COM if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 20935331Samw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 20949179SMark.Shellenbaum@Sun.COM &aclnode->z_size, fuidp, cr)) != 0) { 20955331Samw zfs_acl_free(aclp); 20965331Samw zfs_acl_node_free(aclnode); 20975331Samw return (error); 20985331Samw } 20995331Samw } 21005331Samw aclp->z_acl_bytes = aclnode->z_size; 21015331Samw aclnode->z_ace_count = aclcnt; 21025331Samw aclp->z_acl_count = aclcnt; 21035331Samw list_insert_head(&aclp->z_acl, aclnode); 21045331Samw 21055331Samw /* 21065331Samw * If flags are being set then add them to z_hints 21075331Samw */ 21085331Samw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 21095331Samw if (vsecp->vsa_aclflags & ACL_PROTECTED) 21105331Samw aclp->z_hints |= ZFS_ACL_PROTECTED; 21115331Samw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 21125331Samw aclp->z_hints |= ZFS_ACL_DEFAULTED; 21135331Samw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 21145331Samw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 21155331Samw } 21165331Samw 21175331Samw *zaclp = aclp; 21185331Samw 21195331Samw return (0); 21205331Samw } 21215331Samw 2122789Sahrens /* 2123789Sahrens * Set a files ACL 2124789Sahrens */ 2125789Sahrens int 21265331Samw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 2127789Sahrens { 2128789Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2129789Sahrens zilog_t *zilog = zfsvfs->z_log; 2130789Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 2131789Sahrens dmu_tx_t *tx; 2132789Sahrens int error; 2133789Sahrens zfs_acl_t *aclp; 21345331Samw zfs_fuid_info_t *fuidp = NULL; 21359179SMark.Shellenbaum@Sun.COM boolean_t fuid_dirtied; 2136789Sahrens 2137789Sahrens if (mask == 0) 21384300Smarks return (ENOSYS); 2139789Sahrens 21405331Samw if (zp->z_phys->zp_flags & ZFS_IMMUTABLE) 21415331Samw return (EPERM); 21425331Samw 21435331Samw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 21445331Samw return (error); 21455331Samw 21469179SMark.Shellenbaum@Sun.COM error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 21479179SMark.Shellenbaum@Sun.COM &aclp); 21485331Samw if (error) 21495331Samw return (error); 21505331Samw 21515331Samw /* 21525331Samw * If ACL wide flags aren't being set then preserve any 21535331Samw * existing flags. 21545331Samw */ 21555331Samw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 21565331Samw aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS); 21575331Samw } 2158789Sahrens top: 2159789Sahrens mutex_enter(&zp->z_lock); 2160789Sahrens mutex_enter(&zp->z_acl_lock); 2161789Sahrens 2162789Sahrens tx = dmu_tx_create(zfsvfs->z_os); 2163789Sahrens dmu_tx_hold_bonus(tx, zp->z_id); 2164789Sahrens 2165789Sahrens if (zp->z_phys->zp_acl.z_acl_extern_obj) { 21665331Samw /* Are we upgrading ACL? */ 21675331Samw if (zfsvfs->z_version <= ZPL_VERSION_FUID && 21685331Samw zp->z_phys->zp_acl.z_acl_version == 21695331Samw ZFS_ACL_VERSION_INITIAL) { 21705331Samw dmu_tx_hold_free(tx, 21715331Samw zp->z_phys->zp_acl.z_acl_extern_obj, 21725331Samw 0, DMU_OBJECT_END); 21735331Samw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 21745824Smarks 0, aclp->z_acl_bytes); 21755331Samw } else { 21765331Samw dmu_tx_hold_write(tx, 21775331Samw zp->z_phys->zp_acl.z_acl_extern_obj, 21785331Samw 0, aclp->z_acl_bytes); 21795331Samw } 21805331Samw } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 21815331Samw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 21825331Samw } 21839179SMark.Shellenbaum@Sun.COM fuid_dirtied = zfsvfs->z_fuid_dirty; 21849396SMatthew.Ahrens@Sun.COM if (fuid_dirtied) 21859396SMatthew.Ahrens@Sun.COM zfs_fuid_txhold(zfsvfs, tx); 2186789Sahrens 21878227SNeil.Perrin@Sun.COM error = dmu_tx_assign(tx, TXG_NOWAIT); 2188789Sahrens if (error) { 2189789Sahrens mutex_exit(&zp->z_acl_lock); 2190789Sahrens mutex_exit(&zp->z_lock); 2191789Sahrens 21928227SNeil.Perrin@Sun.COM if (error == ERESTART) { 21932113Sahrens dmu_tx_wait(tx); 21942113Sahrens dmu_tx_abort(tx); 2195789Sahrens goto top; 2196789Sahrens } 21972113Sahrens dmu_tx_abort(tx); 21985331Samw zfs_acl_free(aclp); 2199789Sahrens return (error); 2200789Sahrens } 2201789Sahrens 22029179SMark.Shellenbaum@Sun.COM error = zfs_aclset_common(zp, aclp, cr, tx); 2203789Sahrens ASSERT(error == 0); 220410143STim.Haley@Sun.COM zp->z_acl_cached = aclp; 2205789Sahrens 22069179SMark.Shellenbaum@Sun.COM if (fuid_dirtied) 22079179SMark.Shellenbaum@Sun.COM zfs_fuid_sync(zfsvfs, tx); 22089179SMark.Shellenbaum@Sun.COM 22099179SMark.Shellenbaum@Sun.COM zfs_time_stamper_locked(zp, STATE_CHANGED, tx); 22105331Samw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 22115331Samw 22125331Samw if (fuidp) 22135331Samw zfs_fuid_info_free(fuidp); 2214789Sahrens dmu_tx_commit(tx); 2215789Sahrens done: 2216789Sahrens mutex_exit(&zp->z_acl_lock); 2217789Sahrens mutex_exit(&zp->z_lock); 2218789Sahrens 2219789Sahrens return (error); 2220789Sahrens } 2221789Sahrens 22225331Samw /* 22239749STim.Haley@Sun.COM * Check accesses of interest (AoI) against attributes of the dataset 22249749STim.Haley@Sun.COM * such as read-only. Returns zero if no AoI conflict with dataset 22259749STim.Haley@Sun.COM * attributes, otherwise an appropriate errno is returned. 22265331Samw */ 2227789Sahrens static int 22289749STim.Haley@Sun.COM zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2229789Sahrens { 22309749STim.Haley@Sun.COM if ((v4_mode & WRITE_MASK) && 22319749STim.Haley@Sun.COM (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 22329749STim.Haley@Sun.COM (!IS_DEVVP(ZTOV(zp)) || 22339749STim.Haley@Sun.COM (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 22349749STim.Haley@Sun.COM return (EROFS); 22359749STim.Haley@Sun.COM } 22369749STim.Haley@Sun.COM 22379749STim.Haley@Sun.COM /* 22389749STim.Haley@Sun.COM * Only check for READONLY on non-directories. 22399749STim.Haley@Sun.COM */ 22409749STim.Haley@Sun.COM if ((v4_mode & WRITE_MASK_DATA) && 22419749STim.Haley@Sun.COM (((ZTOV(zp)->v_type != VDIR) && 22429749STim.Haley@Sun.COM (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 22439749STim.Haley@Sun.COM (ZTOV(zp)->v_type == VDIR && 22449749STim.Haley@Sun.COM (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) { 22459749STim.Haley@Sun.COM return (EPERM); 22469749STim.Haley@Sun.COM } 22479749STim.Haley@Sun.COM 22489749STim.Haley@Sun.COM if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 22499749STim.Haley@Sun.COM (zp->z_phys->zp_flags & ZFS_NOUNLINK)) { 22509749STim.Haley@Sun.COM return (EPERM); 22519749STim.Haley@Sun.COM } 22529749STim.Haley@Sun.COM 22539749STim.Haley@Sun.COM if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 22549749STim.Haley@Sun.COM (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) { 22559749STim.Haley@Sun.COM return (EACCES); 22569749STim.Haley@Sun.COM } 22579749STim.Haley@Sun.COM 22589749STim.Haley@Sun.COM return (0); 22599749STim.Haley@Sun.COM } 22609749STim.Haley@Sun.COM 22619749STim.Haley@Sun.COM /* 22629749STim.Haley@Sun.COM * The primary usage of this function is to loop through all of the 22639749STim.Haley@Sun.COM * ACEs in the znode, determining what accesses of interest (AoI) to 22649749STim.Haley@Sun.COM * the caller are allowed or denied. The AoI are expressed as bits in 22659749STim.Haley@Sun.COM * the working_mode parameter. As each ACE is processed, bits covered 22669749STim.Haley@Sun.COM * by that ACE are removed from the working_mode. This removal 22679749STim.Haley@Sun.COM * facilitates two things. The first is that when the working mode is 22689749STim.Haley@Sun.COM * empty (= 0), we know we've looked at all the AoI. The second is 22699749STim.Haley@Sun.COM * that the ACE interpretation rules don't allow a later ACE to undo 22709749STim.Haley@Sun.COM * something granted or denied by an earlier ACE. Removing the 22719749STim.Haley@Sun.COM * discovered access or denial enforces this rule. At the end of 22729749STim.Haley@Sun.COM * processing the ACEs, all AoI that were found to be denied are 22739749STim.Haley@Sun.COM * placed into the working_mode, giving the caller a mask of denied 22749749STim.Haley@Sun.COM * accesses. Returns: 22759749STim.Haley@Sun.COM * 0 if all AoI granted 22769749STim.Haley@Sun.COM * EACCESS if the denied mask is non-zero 22779749STim.Haley@Sun.COM * other error if abnormal failure (e.g., IO error) 22789749STim.Haley@Sun.COM * 22799749STim.Haley@Sun.COM * A secondary usage of the function is to determine if any of the 22809749STim.Haley@Sun.COM * AoI are granted. If an ACE grants any access in 22819749STim.Haley@Sun.COM * the working_mode, we immediately short circuit out of the function. 22829749STim.Haley@Sun.COM * This mode is chosen by setting anyaccess to B_TRUE. The 22839749STim.Haley@Sun.COM * working_mode is not a denied access mask upon exit if the function 22849749STim.Haley@Sun.COM * is used in this manner. 22859749STim.Haley@Sun.COM */ 22869749STim.Haley@Sun.COM static int 22879749STim.Haley@Sun.COM zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 22889749STim.Haley@Sun.COM boolean_t anyaccess, cred_t *cr) 22899749STim.Haley@Sun.COM { 22909749STim.Haley@Sun.COM zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2291789Sahrens zfs_acl_t *aclp; 22921544Seschrock int error; 2293789Sahrens uid_t uid = crgetuid(cr); 22945331Samw uint64_t who; 22955331Samw uint16_t type, iflags; 22965331Samw uint16_t entry_type; 22975331Samw uint32_t access_mask; 22986056Smarks uint32_t deny_mask = 0; 22995331Samw zfs_ace_hdr_t *acep = NULL; 23005331Samw boolean_t checkit; 23015331Samw uid_t fowner; 23025331Samw uid_t gowner; 23035331Samw 23045771Sjp151216 zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 23055331Samw 2306789Sahrens mutex_enter(&zp->z_acl_lock); 2307789Sahrens 23085331Samw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 23091544Seschrock if (error != 0) { 23101544Seschrock mutex_exit(&zp->z_acl_lock); 23111544Seschrock return (error); 23121544Seschrock } 23131544Seschrock 23145331Samw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 23155331Samw &iflags, &type)) { 23169749STim.Haley@Sun.COM uint32_t mask_matched; 2317789Sahrens 23187559SMark.Shellenbaum@Sun.COM if (!zfs_acl_valid_ace_type(type, iflags)) 23197559SMark.Shellenbaum@Sun.COM continue; 23207559SMark.Shellenbaum@Sun.COM 23217057Smarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2322789Sahrens continue; 2323789Sahrens 23249749STim.Haley@Sun.COM /* Skip ACE if it does not affect any AoI */ 23259749STim.Haley@Sun.COM mask_matched = (access_mask & *working_mode); 23269749STim.Haley@Sun.COM if (!mask_matched) 23279749STim.Haley@Sun.COM continue; 23289749STim.Haley@Sun.COM 23295331Samw entry_type = (iflags & ACE_TYPE_FLAGS); 23305331Samw 23315331Samw checkit = B_FALSE; 23325331Samw 2333789Sahrens switch (entry_type) { 2334789Sahrens case ACE_OWNER: 23355331Samw if (uid == fowner) 23365331Samw checkit = B_TRUE; 2337789Sahrens break; 23385331Samw case OWNING_GROUP: 23395331Samw who = gowner; 23405331Samw /*FALLTHROUGH*/ 2341789Sahrens case ACE_IDENTIFIER_GROUP: 23425331Samw checkit = zfs_groupmember(zfsvfs, who, cr); 2343789Sahrens break; 2344789Sahrens case ACE_EVERYONE: 23455331Samw checkit = B_TRUE; 2346789Sahrens break; 2347789Sahrens 2348789Sahrens /* USER Entry */ 2349789Sahrens default: 2350789Sahrens if (entry_type == 0) { 23515331Samw uid_t newid; 23525331Samw 23535959Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 23545959Smarks ZFS_ACE_USER); 23555331Samw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 23565331Samw uid == newid) 23575331Samw checkit = B_TRUE; 2358789Sahrens break; 23595331Samw } else { 23605331Samw mutex_exit(&zp->z_acl_lock); 23615331Samw return (EIO); 2362789Sahrens } 23635331Samw } 23645331Samw 23655331Samw if (checkit) { 23669749STim.Haley@Sun.COM if (type == DENY) { 23679749STim.Haley@Sun.COM DTRACE_PROBE3(zfs__ace__denies, 23689749STim.Haley@Sun.COM znode_t *, zp, 23699749STim.Haley@Sun.COM zfs_ace_hdr_t *, acep, 23709749STim.Haley@Sun.COM uint32_t, mask_matched); 23719749STim.Haley@Sun.COM deny_mask |= mask_matched; 23729749STim.Haley@Sun.COM } else { 23739749STim.Haley@Sun.COM DTRACE_PROBE3(zfs__ace__allows, 23749749STim.Haley@Sun.COM znode_t *, zp, 23759749STim.Haley@Sun.COM zfs_ace_hdr_t *, acep, 23769749STim.Haley@Sun.COM uint32_t, mask_matched); 23779749STim.Haley@Sun.COM if (anyaccess) { 23789749STim.Haley@Sun.COM mutex_exit(&zp->z_acl_lock); 23799749STim.Haley@Sun.COM return (0); 23809749STim.Haley@Sun.COM } 23815331Samw } 23829749STim.Haley@Sun.COM *working_mode &= ~mask_matched; 2383789Sahrens } 2384789Sahrens 23856056Smarks /* Are we done? */ 23866056Smarks if (*working_mode == 0) 2387789Sahrens break; 2388789Sahrens } 2389789Sahrens 2390789Sahrens mutex_exit(&zp->z_acl_lock); 23916056Smarks 23926056Smarks /* Put the found 'denies' back on the working mode */ 23937163Smarks if (deny_mask) { 23947163Smarks *working_mode |= deny_mask; 23956056Smarks return (EACCES); 23967163Smarks } else if (*working_mode) { 23977163Smarks return (-1); 23987163Smarks } 23996056Smarks 24006056Smarks return (0); 2401789Sahrens } 2402789Sahrens 24039749STim.Haley@Sun.COM /* 24049749STim.Haley@Sun.COM * Return true if any access whatsoever granted, we don't actually 24059749STim.Haley@Sun.COM * care what access is granted. 24069749STim.Haley@Sun.COM */ 24079749STim.Haley@Sun.COM boolean_t 24089749STim.Haley@Sun.COM zfs_has_access(znode_t *zp, cred_t *cr) 24099749STim.Haley@Sun.COM { 24109749STim.Haley@Sun.COM uint32_t have = ACE_ALL_PERMS; 24119749STim.Haley@Sun.COM 24129749STim.Haley@Sun.COM if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 24139749STim.Haley@Sun.COM uid_t owner; 24149749STim.Haley@Sun.COM 24159749STim.Haley@Sun.COM owner = zfs_fuid_map_id(zp->z_zfsvfs, 24169749STim.Haley@Sun.COM zp->z_phys->zp_uid, cr, ZFS_OWNER); 24179749STim.Haley@Sun.COM 24189749STim.Haley@Sun.COM return ( 24199749STim.Haley@Sun.COM secpolicy_vnode_access(cr, ZTOV(zp), owner, VREAD) == 0 || 24209749STim.Haley@Sun.COM secpolicy_vnode_access(cr, ZTOV(zp), owner, VWRITE) == 0 || 24219749STim.Haley@Sun.COM secpolicy_vnode_access(cr, ZTOV(zp), owner, VEXEC) == 0 || 24229866SMark.Shellenbaum@Sun.COM secpolicy_vnode_chown(cr, owner) == 0 || 24239749STim.Haley@Sun.COM secpolicy_vnode_setdac(cr, owner) == 0 || 24249749STim.Haley@Sun.COM secpolicy_vnode_remove(cr) == 0); 24259749STim.Haley@Sun.COM } 24269749STim.Haley@Sun.COM return (B_TRUE); 24279749STim.Haley@Sun.COM } 24289749STim.Haley@Sun.COM 24299749STim.Haley@Sun.COM static int 24309749STim.Haley@Sun.COM zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 24319749STim.Haley@Sun.COM boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 24329749STim.Haley@Sun.COM { 24339749STim.Haley@Sun.COM zfsvfs_t *zfsvfs = zp->z_zfsvfs; 24349749STim.Haley@Sun.COM int err; 24359749STim.Haley@Sun.COM 24369749STim.Haley@Sun.COM *working_mode = v4_mode; 24379749STim.Haley@Sun.COM *check_privs = B_TRUE; 24389749STim.Haley@Sun.COM 24399749STim.Haley@Sun.COM /* 24409749STim.Haley@Sun.COM * Short circuit empty requests 24419749STim.Haley@Sun.COM */ 24429749STim.Haley@Sun.COM if (v4_mode == 0 || zfsvfs->z_replay) { 24439749STim.Haley@Sun.COM *working_mode = 0; 24449749STim.Haley@Sun.COM return (0); 24459749STim.Haley@Sun.COM } 24469749STim.Haley@Sun.COM 24479749STim.Haley@Sun.COM if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 24489749STim.Haley@Sun.COM *check_privs = B_FALSE; 24499749STim.Haley@Sun.COM return (err); 24509749STim.Haley@Sun.COM } 24519749STim.Haley@Sun.COM 24529749STim.Haley@Sun.COM /* 24539749STim.Haley@Sun.COM * The caller requested that the ACL check be skipped. This 24549749STim.Haley@Sun.COM * would only happen if the caller checked VOP_ACCESS() with a 24559749STim.Haley@Sun.COM * 32 bit ACE mask and already had the appropriate permissions. 24569749STim.Haley@Sun.COM */ 24579749STim.Haley@Sun.COM if (skipaclchk) { 24589749STim.Haley@Sun.COM *working_mode = 0; 24599749STim.Haley@Sun.COM return (0); 24609749STim.Haley@Sun.COM } 24619749STim.Haley@Sun.COM 24629749STim.Haley@Sun.COM return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 24639749STim.Haley@Sun.COM } 24649749STim.Haley@Sun.COM 24655331Samw static int 24665331Samw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 24675331Samw cred_t *cr) 24685331Samw { 24695331Samw if (*working_mode != ACE_WRITE_DATA) 24705331Samw return (EACCES); 24715331Samw 24725331Samw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 24735331Samw check_privs, B_FALSE, cr)); 24745331Samw } 2475789Sahrens 24769981STim.Haley@Sun.COM int 24779981STim.Haley@Sun.COM zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 24789981STim.Haley@Sun.COM { 24799981STim.Haley@Sun.COM boolean_t owner = B_FALSE; 24809981STim.Haley@Sun.COM boolean_t groupmbr = B_FALSE; 24819981STim.Haley@Sun.COM boolean_t is_attr; 24829981STim.Haley@Sun.COM uid_t fowner; 24839981STim.Haley@Sun.COM uid_t gowner; 24849981STim.Haley@Sun.COM uid_t uid = crgetuid(cr); 24859981STim.Haley@Sun.COM int error; 24869981STim.Haley@Sun.COM 24879981STim.Haley@Sun.COM if (zdp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 24889981STim.Haley@Sun.COM return (EACCES); 24899981STim.Haley@Sun.COM 24909981STim.Haley@Sun.COM is_attr = ((zdp->z_phys->zp_flags & ZFS_XATTR) && 24919981STim.Haley@Sun.COM (ZTOV(zdp)->v_type == VDIR)); 24929981STim.Haley@Sun.COM if (is_attr) 24939981STim.Haley@Sun.COM goto slow; 24949981STim.Haley@Sun.COM 24959981STim.Haley@Sun.COM mutex_enter(&zdp->z_acl_lock); 24969981STim.Haley@Sun.COM 24979981STim.Haley@Sun.COM if (zdp->z_phys->zp_flags & ZFS_NO_EXECS_DENIED) { 24989981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 24999981STim.Haley@Sun.COM return (0); 25009981STim.Haley@Sun.COM } 25019981STim.Haley@Sun.COM 25029981STim.Haley@Sun.COM if (FUID_INDEX(zdp->z_phys->zp_uid) != 0 || 25039981STim.Haley@Sun.COM FUID_INDEX(zdp->z_phys->zp_gid) != 0) { 25049981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 25059981STim.Haley@Sun.COM goto slow; 25069981STim.Haley@Sun.COM } 25079981STim.Haley@Sun.COM 25089981STim.Haley@Sun.COM fowner = (uid_t)zdp->z_phys->zp_uid; 25099981STim.Haley@Sun.COM gowner = (uid_t)zdp->z_phys->zp_gid; 25109981STim.Haley@Sun.COM 25119981STim.Haley@Sun.COM if (uid == fowner) { 25129981STim.Haley@Sun.COM owner = B_TRUE; 25139981STim.Haley@Sun.COM if (zdp->z_phys->zp_mode & S_IXUSR) { 25149981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 25159981STim.Haley@Sun.COM return (0); 251610232STim.Haley@Sun.COM } else { 251710232STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 251810232STim.Haley@Sun.COM goto slow; 25199981STim.Haley@Sun.COM } 25209981STim.Haley@Sun.COM } 25219981STim.Haley@Sun.COM if (groupmember(gowner, cr)) { 25229981STim.Haley@Sun.COM groupmbr = B_TRUE; 25239981STim.Haley@Sun.COM if (zdp->z_phys->zp_mode & S_IXGRP) { 25249981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 25259981STim.Haley@Sun.COM return (0); 252610232STim.Haley@Sun.COM } else { 252710232STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 252810232STim.Haley@Sun.COM goto slow; 25299981STim.Haley@Sun.COM } 25309981STim.Haley@Sun.COM } 25319981STim.Haley@Sun.COM if (!owner && !groupmbr) { 25329981STim.Haley@Sun.COM if (zdp->z_phys->zp_mode & S_IXOTH) { 25339981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 25349981STim.Haley@Sun.COM return (0); 25359981STim.Haley@Sun.COM } 25369981STim.Haley@Sun.COM } 25379981STim.Haley@Sun.COM 25389981STim.Haley@Sun.COM mutex_exit(&zdp->z_acl_lock); 25399981STim.Haley@Sun.COM 25409981STim.Haley@Sun.COM slow: 25419981STim.Haley@Sun.COM DTRACE_PROBE(zfs__fastpath__execute__access__miss); 25429981STim.Haley@Sun.COM ZFS_ENTER(zdp->z_zfsvfs); 25439981STim.Haley@Sun.COM error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 25449981STim.Haley@Sun.COM ZFS_EXIT(zdp->z_zfsvfs); 25459981STim.Haley@Sun.COM return (error); 25469981STim.Haley@Sun.COM } 25479981STim.Haley@Sun.COM 2548789Sahrens /* 2549789Sahrens * Determine whether Access should be granted/denied, invoking least 2550789Sahrens * priv subsytem when a deny is determined. 2551789Sahrens */ 2552789Sahrens int 25535331Samw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2554789Sahrens { 25555331Samw uint32_t working_mode; 25565331Samw int error; 25575331Samw int is_attr; 25585331Samw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 25595331Samw boolean_t check_privs; 25605331Samw znode_t *xzp; 25615331Samw znode_t *check_zp = zp; 2562789Sahrens 2563789Sahrens is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) && 2564789Sahrens (ZTOV(zp)->v_type == VDIR)); 2565789Sahrens 2566789Sahrens /* 2567789Sahrens * If attribute then validate against base file 2568789Sahrens */ 2569789Sahrens if (is_attr) { 2570789Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 2571789Sahrens zp->z_phys->zp_parent, &xzp)) != 0) { 2572789Sahrens return (error); 2573789Sahrens } 25745331Samw 2575789Sahrens check_zp = xzp; 25765331Samw 2577789Sahrens /* 2578789Sahrens * fixup mode to map to xattr perms 2579789Sahrens */ 2580789Sahrens 2581789Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2582789Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2583789Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2584789Sahrens } 2585789Sahrens 2586789Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2587789Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2588789Sahrens mode |= ACE_READ_NAMED_ATTRS; 2589789Sahrens } 2590789Sahrens } 2591789Sahrens 25925331Samw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 25935331Samw &check_privs, skipaclchk, cr)) == 0) { 25945331Samw if (is_attr) 25955331Samw VN_RELE(ZTOV(xzp)); 25965331Samw return (0); 25975331Samw } 2598789Sahrens 25995959Smarks if (error && !check_privs) { 2600789Sahrens if (is_attr) 2601789Sahrens VN_RELE(ZTOV(xzp)); 2602789Sahrens return (error); 2603789Sahrens } 2604789Sahrens 26055331Samw if (error && (flags & V_APPEND)) { 26065331Samw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 26075331Samw } 26085331Samw 26095331Samw if (error && check_privs) { 26105331Samw uid_t owner; 26115331Samw mode_t checkmode = 0; 26125331Samw 26135959Smarks owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr, 26145959Smarks ZFS_OWNER); 26155331Samw 26165331Samw /* 26175331Samw * First check for implicit owner permission on 26185331Samw * read_acl/read_attributes 26195331Samw */ 26205331Samw 26215331Samw error = 0; 26225331Samw ASSERT(working_mode != 0); 26235331Samw 26245331Samw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 26255331Samw owner == crgetuid(cr))) 26265331Samw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 26275331Samw 26285331Samw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 26297624SMark.Shellenbaum@Sun.COM ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 26305331Samw checkmode |= VREAD; 26315331Samw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 26327624SMark.Shellenbaum@Sun.COM ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 26335331Samw checkmode |= VWRITE; 26345331Samw if (working_mode & ACE_EXECUTE) 26355331Samw checkmode |= VEXEC; 26365331Samw 26375331Samw if (checkmode) 26385331Samw error = secpolicy_vnode_access(cr, ZTOV(check_zp), 26395331Samw owner, checkmode); 26405331Samw 26415331Samw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 26429866SMark.Shellenbaum@Sun.COM error = secpolicy_vnode_chown(cr, owner); 26435331Samw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 26445331Samw error = secpolicy_vnode_setdac(cr, owner); 26455331Samw 26465331Samw if (error == 0 && (working_mode & 26475331Samw (ACE_DELETE|ACE_DELETE_CHILD))) 26485331Samw error = secpolicy_vnode_remove(cr); 26495331Samw 26507624SMark.Shellenbaum@Sun.COM if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 26519866SMark.Shellenbaum@Sun.COM error = secpolicy_vnode_chown(cr, owner); 26527624SMark.Shellenbaum@Sun.COM } 26535331Samw if (error == 0) { 26545331Samw /* 26555331Samw * See if any bits other than those already checked 26565331Samw * for are still present. If so then return EACCES 26575331Samw */ 26585331Samw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 26595331Samw error = EACCES; 26605331Samw } 26615331Samw } 2662789Sahrens } 2663789Sahrens 2664789Sahrens if (is_attr) 2665789Sahrens VN_RELE(ZTOV(xzp)); 2666789Sahrens 2667789Sahrens return (error); 2668789Sahrens } 2669789Sahrens 2670789Sahrens /* 26715331Samw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 26725331Samw * native ACL format and call zfs_zaccess() 2673789Sahrens */ 2674789Sahrens int 26755331Samw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2676789Sahrens { 26775331Samw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2678789Sahrens } 2679789Sahrens 2680789Sahrens /* 26815331Samw * Access function for secpolicy_vnode_setattr 2682789Sahrens */ 2683789Sahrens int 26845331Samw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2685789Sahrens { 2686789Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2687789Sahrens 26885331Samw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2689789Sahrens } 2690789Sahrens 26912604Smarks static int 26926257Smarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 26936257Smarks mode_t missing_perms, cred_t *cr) 26942604Smarks { 26952604Smarks int error; 26965331Samw uid_t downer; 26975331Samw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 26982604Smarks 26995959Smarks downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER); 27005331Samw 27016257Smarks error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms); 27022604Smarks 27032604Smarks if (error == 0) 27042604Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 27052604Smarks 27062604Smarks return (error); 27072604Smarks } 27082604Smarks 2709789Sahrens /* 2710789Sahrens * Determine whether Access should be granted/deny, without 2711789Sahrens * consulting least priv subsystem. 2712789Sahrens * 2713789Sahrens * 2714789Sahrens * The following chart is the recommended NFSv4 enforcement for 2715789Sahrens * ability to delete an object. 2716789Sahrens * 2717789Sahrens * ------------------------------------------------------- 2718789Sahrens * | Parent Dir | Target Object Permissions | 2719789Sahrens * | permissions | | 2720789Sahrens * ------------------------------------------------------- 2721789Sahrens * | | ACL Allows | ACL Denies| Delete | 2722789Sahrens * | | Delete | Delete | unspecified| 2723789Sahrens * ------------------------------------------------------- 2724789Sahrens * | ACL Allows | Permit | Permit | Permit | 2725789Sahrens * | DELETE_CHILD | | 2726789Sahrens * ------------------------------------------------------- 2727789Sahrens * | ACL Denies | Permit | Deny | Deny | 2728789Sahrens * | DELETE_CHILD | | | | 2729789Sahrens * ------------------------------------------------------- 2730789Sahrens * | ACL specifies | | | | 2731789Sahrens * | only allow | Permit | Permit | Permit | 2732789Sahrens * | write and | | | | 2733789Sahrens * | execute | | | | 2734789Sahrens * ------------------------------------------------------- 2735789Sahrens * | ACL denies | | | | 2736789Sahrens * | write and | Permit | Deny | Deny | 2737789Sahrens * | execute | | | | 2738789Sahrens * ------------------------------------------------------- 2739789Sahrens * ^ 2740789Sahrens * | 2741789Sahrens * No search privilege, can't even look up file? 2742789Sahrens * 2743789Sahrens */ 2744789Sahrens int 2745789Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2746789Sahrens { 27475331Samw uint32_t dzp_working_mode = 0; 27485331Samw uint32_t zp_working_mode = 0; 2749789Sahrens int dzp_error, zp_error; 27506257Smarks mode_t missing_perms; 27515331Samw boolean_t dzpcheck_privs = B_TRUE; 27525331Samw boolean_t zpcheck_privs = B_TRUE; 2753789Sahrens 2754789Sahrens /* 27556257Smarks * We want specific DELETE permissions to 2756789Sahrens * take precedence over WRITE/EXECUTE. We don't 2757789Sahrens * want an ACL such as this to mess us up. 27582604Smarks * user:joe:write_data:deny,user:joe:delete:allow 2759789Sahrens * 2760789Sahrens * However, deny permissions may ultimately be overridden 2761789Sahrens * by secpolicy_vnode_access(). 27626257Smarks * 27636257Smarks * We will ask for all of the necessary permissions and then 27646257Smarks * look at the working modes from the directory and target object 27656257Smarks * to determine what was found. 2766789Sahrens */ 2767789Sahrens 27685331Samw if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 27695331Samw return (EPERM); 27705331Samw 27716257Smarks /* 27727163Smarks * First row 27736257Smarks * If the directory permissions allow the delete, we are done. 27746257Smarks */ 27757163Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 27766257Smarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 27776257Smarks return (0); 2778789Sahrens 27796257Smarks /* 27806257Smarks * If target object has delete permission then we are done 27816257Smarks */ 27826257Smarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 27836257Smarks &zpcheck_privs, B_FALSE, cr)) == 0) 27846257Smarks return (0); 27856257Smarks 27867163Smarks ASSERT(dzp_error && zp_error); 27877163Smarks 27886257Smarks if (!dzpcheck_privs) 2789789Sahrens return (dzp_error); 27907163Smarks if (!zpcheck_privs) 27916257Smarks return (zp_error); 2792789Sahrens 2793789Sahrens /* 2794789Sahrens * Second row 27957163Smarks * 27967163Smarks * If directory returns EACCES then delete_child was denied 27977163Smarks * due to deny delete_child. In this case send the request through 27987163Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 27997163Smarks * since that *could* allow the delete based on write/execute permission 28007163Smarks * and we want delete permissions to override write/execute. 2801789Sahrens */ 2802789Sahrens 28032604Smarks if (dzp_error == EACCES) 28047163Smarks return (secpolicy_vnode_remove(cr)); 28052604Smarks 28062604Smarks /* 2807789Sahrens * Third Row 28086257Smarks * only need to see if we have write/execute on directory. 2809789Sahrens */ 2810789Sahrens 28117163Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 28127163Smarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 28132604Smarks return (zfs_sticky_remove_access(dzp, zp, cr)); 2814789Sahrens 28157163Smarks if (!dzpcheck_privs) 28167163Smarks return (dzp_error); 28177163Smarks 2818789Sahrens /* 28197163Smarks * Fourth row 2820789Sahrens */ 2821789Sahrens 28227163Smarks missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0; 28237163Smarks missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0; 28247163Smarks 28257163Smarks ASSERT(missing_perms); 2826789Sahrens 28276257Smarks return (zfs_delete_final_check(zp, dzp, missing_perms, cr)); 28287163Smarks 2829789Sahrens } 2830789Sahrens 2831789Sahrens int 2832789Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2833789Sahrens znode_t *tzp, cred_t *cr) 2834789Sahrens { 2835789Sahrens int add_perm; 2836789Sahrens int error; 2837789Sahrens 28385331Samw if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 28395331Samw return (EACCES); 28405331Samw 2841789Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2842789Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2843789Sahrens 2844789Sahrens /* 2845789Sahrens * Rename permissions are combination of delete permission + 2846789Sahrens * add file/subdir permission. 2847789Sahrens */ 2848789Sahrens 2849789Sahrens /* 2850789Sahrens * first make sure we do the delete portion. 2851789Sahrens * 2852789Sahrens * If that succeeds then check for add_file/add_subdir permissions 2853789Sahrens */ 2854789Sahrens 2855789Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2856789Sahrens return (error); 2857789Sahrens 2858789Sahrens /* 2859789Sahrens * If we have a tzp, see if we can delete it? 2860789Sahrens */ 2861789Sahrens if (tzp) { 2862789Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2863789Sahrens return (error); 2864789Sahrens } 2865789Sahrens 2866789Sahrens /* 2867789Sahrens * Now check for add permissions 2868789Sahrens */ 28695331Samw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2870789Sahrens 2871789Sahrens return (error); 2872789Sahrens } 2873