1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22f52e0e2bSMark Shellenbaum * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/time.h> 29fa9e4066Sahrens #include <sys/systm.h> 30fa9e4066Sahrens #include <sys/sysmacros.h> 31fa9e4066Sahrens #include <sys/resource.h> 32fa9e4066Sahrens #include <sys/vfs.h> 33fa9e4066Sahrens #include <sys/vnode.h> 34da6c28aaSamw #include <sys/sid.h> 35fa9e4066Sahrens #include <sys/file.h> 36fa9e4066Sahrens #include <sys/stat.h> 37fa9e4066Sahrens #include <sys/kmem.h> 38fa9e4066Sahrens #include <sys/cmn_err.h> 39fa9e4066Sahrens #include <sys/errno.h> 40fa9e4066Sahrens #include <sys/unistd.h> 41169cdae2Smarks #include <sys/sdt.h> 42fa9e4066Sahrens #include <sys/fs/zfs.h> 43fa9e4066Sahrens #include <sys/mode.h> 44fa9e4066Sahrens #include <sys/policy.h> 45fa9e4066Sahrens #include <sys/zfs_znode.h> 46da6c28aaSamw #include <sys/zfs_fuid.h> 47fa9e4066Sahrens #include <sys/zfs_acl.h> 48fa9e4066Sahrens #include <sys/zfs_dir.h> 49fa9e4066Sahrens #include <sys/zfs_vfsops.h> 50fa9e4066Sahrens #include <sys/dmu.h> 51da6c28aaSamw #include <sys/dnode.h> 52fa9e4066Sahrens #include <sys/zap.h> 53fa9e4066Sahrens #include "fs/fs_subr.h" 54fa9e4066Sahrens #include <acl/acl_common.h> 55fa9e4066Sahrens 56fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 57fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 58da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 59003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW 60fa9e4066Sahrens 61fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 62fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 63fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 64fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 65fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 66fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 67fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 68da6c28aaSamw 69da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 70da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 71da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 72da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 73da6c28aaSamw 74f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS) 75f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \ 76f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD) 77f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS) 78fa9e4066Sahrens 79fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 80fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 81fa9e4066Sahrens 82fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 83fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 84fa9e4066Sahrens 85fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \ 86da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE) 87fa9e4066Sahrens 88b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER) 89fa9e4066Sahrens 90da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\ 91da6c28aaSamw ZFS_ACL_PROTECTED) 92fa9e4066Sahrens 93da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 94da6c28aaSamw ZFS_ACL_OBJ_ACE) 95da6c28aaSamw 96da6c28aaSamw static uint16_t 97da6c28aaSamw zfs_ace_v0_get_type(void *acep) 98da6c28aaSamw { 99da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type); 100da6c28aaSamw } 101da6c28aaSamw 102da6c28aaSamw static uint16_t 103da6c28aaSamw zfs_ace_v0_get_flags(void *acep) 104da6c28aaSamw { 105da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags); 106da6c28aaSamw } 107da6c28aaSamw 108da6c28aaSamw static uint32_t 109da6c28aaSamw zfs_ace_v0_get_mask(void *acep) 110da6c28aaSamw { 111da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask); 112da6c28aaSamw } 113da6c28aaSamw 114da6c28aaSamw static uint64_t 115da6c28aaSamw zfs_ace_v0_get_who(void *acep) 116da6c28aaSamw { 117da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid); 118da6c28aaSamw } 119da6c28aaSamw 120da6c28aaSamw static void 121da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type) 122da6c28aaSamw { 123da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type; 124da6c28aaSamw } 125da6c28aaSamw 126da6c28aaSamw static void 127da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags) 128da6c28aaSamw { 129da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags; 130da6c28aaSamw } 131da6c28aaSamw 132da6c28aaSamw static void 133da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask) 134da6c28aaSamw { 135da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask; 136da6c28aaSamw } 137da6c28aaSamw 138da6c28aaSamw static void 139da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who) 140da6c28aaSamw { 141da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who; 142da6c28aaSamw } 143da6c28aaSamw 144da6c28aaSamw /*ARGSUSED*/ 145da6c28aaSamw static size_t 146da6c28aaSamw zfs_ace_v0_size(void *acep) 147da6c28aaSamw { 148da6c28aaSamw return (sizeof (zfs_oldace_t)); 149da6c28aaSamw } 150da6c28aaSamw 151da6c28aaSamw static size_t 152da6c28aaSamw zfs_ace_v0_abstract_size(void) 153da6c28aaSamw { 154da6c28aaSamw return (sizeof (zfs_oldace_t)); 155da6c28aaSamw } 156da6c28aaSamw 157da6c28aaSamw static int 158da6c28aaSamw zfs_ace_v0_mask_off(void) 159da6c28aaSamw { 160da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask)); 161da6c28aaSamw } 162da6c28aaSamw 163da6c28aaSamw /*ARGSUSED*/ 164da6c28aaSamw static int 165da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap) 166da6c28aaSamw { 167da6c28aaSamw *datap = NULL; 168da6c28aaSamw return (0); 169da6c28aaSamw } 170da6c28aaSamw 171da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = { 172da6c28aaSamw zfs_ace_v0_get_mask, 173da6c28aaSamw zfs_ace_v0_set_mask, 174da6c28aaSamw zfs_ace_v0_get_flags, 175da6c28aaSamw zfs_ace_v0_set_flags, 176da6c28aaSamw zfs_ace_v0_get_type, 177da6c28aaSamw zfs_ace_v0_set_type, 178da6c28aaSamw zfs_ace_v0_get_who, 179da6c28aaSamw zfs_ace_v0_set_who, 180da6c28aaSamw zfs_ace_v0_size, 181da6c28aaSamw zfs_ace_v0_abstract_size, 182da6c28aaSamw zfs_ace_v0_mask_off, 183da6c28aaSamw zfs_ace_v0_data 184da6c28aaSamw }; 185da6c28aaSamw 186da6c28aaSamw static uint16_t 187da6c28aaSamw zfs_ace_fuid_get_type(void *acep) 188da6c28aaSamw { 189da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type); 190da6c28aaSamw } 191da6c28aaSamw 192da6c28aaSamw static uint16_t 193da6c28aaSamw zfs_ace_fuid_get_flags(void *acep) 194da6c28aaSamw { 195da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags); 196da6c28aaSamw } 197da6c28aaSamw 198da6c28aaSamw static uint32_t 199da6c28aaSamw zfs_ace_fuid_get_mask(void *acep) 200da6c28aaSamw { 201da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask); 202da6c28aaSamw } 203da6c28aaSamw 204da6c28aaSamw static uint64_t 205da6c28aaSamw zfs_ace_fuid_get_who(void *args) 206da6c28aaSamw { 207da6c28aaSamw uint16_t entry_type; 208da6c28aaSamw zfs_ace_t *acep = args; 209da6c28aaSamw 210da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 211da6c28aaSamw 212da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 213da6c28aaSamw entry_type == ACE_EVERYONE) 214da6c28aaSamw return (-1); 215da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid); 216da6c28aaSamw } 217da6c28aaSamw 218da6c28aaSamw static void 219da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type) 220da6c28aaSamw { 221da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type; 222da6c28aaSamw } 223da6c28aaSamw 224da6c28aaSamw static void 225da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags) 226da6c28aaSamw { 227da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags; 228da6c28aaSamw } 229da6c28aaSamw 230da6c28aaSamw static void 231da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask) 232da6c28aaSamw { 233da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask; 234da6c28aaSamw } 235da6c28aaSamw 236da6c28aaSamw static void 237da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who) 238da6c28aaSamw { 239da6c28aaSamw zfs_ace_t *acep = arg; 240da6c28aaSamw 241da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 242da6c28aaSamw 243da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 244da6c28aaSamw entry_type == ACE_EVERYONE) 245da6c28aaSamw return; 246da6c28aaSamw acep->z_fuid = who; 247da6c28aaSamw } 248da6c28aaSamw 249da6c28aaSamw static size_t 250da6c28aaSamw zfs_ace_fuid_size(void *acep) 251da6c28aaSamw { 252da6c28aaSamw zfs_ace_hdr_t *zacep = acep; 253da6c28aaSamw uint16_t entry_type; 254da6c28aaSamw 255da6c28aaSamw switch (zacep->z_type) { 256da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 257da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 258da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 259da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 260da6c28aaSamw return (sizeof (zfs_object_ace_t)); 261da6c28aaSamw case ALLOW: 262da6c28aaSamw case DENY: 263da6c28aaSamw entry_type = 264da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS); 265da6c28aaSamw if (entry_type == ACE_OWNER || 2661ab99678SMark Shellenbaum entry_type == OWNING_GROUP || 267da6c28aaSamw entry_type == ACE_EVERYONE) 268da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 269da6c28aaSamw /*FALLTHROUGH*/ 270da6c28aaSamw default: 271da6c28aaSamw return (sizeof (zfs_ace_t)); 272da6c28aaSamw } 273da6c28aaSamw } 274da6c28aaSamw 275da6c28aaSamw static size_t 276da6c28aaSamw zfs_ace_fuid_abstract_size(void) 277da6c28aaSamw { 278da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 279da6c28aaSamw } 280da6c28aaSamw 281da6c28aaSamw static int 282da6c28aaSamw zfs_ace_fuid_mask_off(void) 283da6c28aaSamw { 284da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 285da6c28aaSamw } 286da6c28aaSamw 287da6c28aaSamw static int 288da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap) 289da6c28aaSamw { 290da6c28aaSamw zfs_ace_t *zacep = acep; 291da6c28aaSamw zfs_object_ace_t *zobjp; 292da6c28aaSamw 293da6c28aaSamw switch (zacep->z_hdr.z_type) { 294da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 295da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 296da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 297da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 298da6c28aaSamw zobjp = acep; 299da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t); 300da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t)); 301da6c28aaSamw default: 302da6c28aaSamw *datap = NULL; 303da6c28aaSamw return (0); 304da6c28aaSamw } 305da6c28aaSamw } 306da6c28aaSamw 307da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = { 308da6c28aaSamw zfs_ace_fuid_get_mask, 309da6c28aaSamw zfs_ace_fuid_set_mask, 310da6c28aaSamw zfs_ace_fuid_get_flags, 311da6c28aaSamw zfs_ace_fuid_set_flags, 312da6c28aaSamw zfs_ace_fuid_get_type, 313da6c28aaSamw zfs_ace_fuid_set_type, 314da6c28aaSamw zfs_ace_fuid_get_who, 315da6c28aaSamw zfs_ace_fuid_set_who, 316da6c28aaSamw zfs_ace_fuid_size, 317da6c28aaSamw zfs_ace_fuid_abstract_size, 318da6c28aaSamw zfs_ace_fuid_mask_off, 319da6c28aaSamw zfs_ace_fuid_data 320da6c28aaSamw }; 321da6c28aaSamw 322da6c28aaSamw static int 323da6c28aaSamw zfs_acl_version(int version) 324da6c28aaSamw { 325da6c28aaSamw if (version < ZPL_VERSION_FUID) 326da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 327da6c28aaSamw else 328da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 329da6c28aaSamw } 330da6c28aaSamw 331da6c28aaSamw static int 332da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 333da6c28aaSamw { 334da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 335da6c28aaSamw } 336fa9e4066Sahrens 337fa9e4066Sahrens static zfs_acl_t * 338da6c28aaSamw zfs_acl_alloc(int vers) 339fa9e4066Sahrens { 340fa9e4066Sahrens zfs_acl_t *aclp; 341fa9e4066Sahrens 342fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 343da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 344da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 345da6c28aaSamw aclp->z_version = vers; 346da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 347da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 348da6c28aaSamw else 349da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 350fa9e4066Sahrens return (aclp); 351fa9e4066Sahrens } 352fa9e4066Sahrens 353da6c28aaSamw static zfs_acl_node_t * 354da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 355da6c28aaSamw { 356da6c28aaSamw zfs_acl_node_t *aclnode; 357da6c28aaSamw 358da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 359da6c28aaSamw if (bytes) { 360da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 361da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 362da6c28aaSamw aclnode->z_allocsize = bytes; 363da6c28aaSamw aclnode->z_size = bytes; 364da6c28aaSamw } 365da6c28aaSamw 366da6c28aaSamw return (aclnode); 367da6c28aaSamw } 368da6c28aaSamw 369da6c28aaSamw static void 370da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 371da6c28aaSamw { 372da6c28aaSamw if (aclnode->z_allocsize) 373da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 374da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 375da6c28aaSamw } 376da6c28aaSamw 3772459a9eaSmarks static void 3782459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 379fa9e4066Sahrens { 380da6c28aaSamw zfs_acl_node_t *aclnode; 381da6c28aaSamw 382da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 383da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 384da6c28aaSamw zfs_acl_node_free(aclnode); 385fa9e4066Sahrens } 3862459a9eaSmarks aclp->z_acl_count = 0; 3872459a9eaSmarks aclp->z_acl_bytes = 0; 3882459a9eaSmarks } 389da6c28aaSamw 3902459a9eaSmarks void 3912459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 3922459a9eaSmarks { 3932459a9eaSmarks zfs_acl_release_nodes(aclp); 394da6c28aaSamw list_destroy(&aclp->z_acl); 395fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 396fa9e4066Sahrens } 397fa9e4066Sahrens 398da6c28aaSamw static boolean_t 399003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 400003c2582SMark Shellenbaum { 401003c2582SMark Shellenbaum uint16_t entry_type; 402003c2582SMark Shellenbaum 403003c2582SMark Shellenbaum switch (type) { 404003c2582SMark Shellenbaum case ALLOW: 405003c2582SMark Shellenbaum case DENY: 406003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 407003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 408003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 409003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 410003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 411003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 412003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 413003c2582SMark Shellenbaum default: 414003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 415003c2582SMark Shellenbaum return (B_TRUE); 416003c2582SMark Shellenbaum } 417003c2582SMark Shellenbaum return (B_FALSE); 418003c2582SMark Shellenbaum } 419003c2582SMark Shellenbaum 420003c2582SMark Shellenbaum static boolean_t 421da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 422fa9e4066Sahrens { 423da6c28aaSamw /* 424da6c28aaSamw * first check type of entry 425da6c28aaSamw */ 426da6c28aaSamw 427003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 428da6c28aaSamw return (B_FALSE); 429da6c28aaSamw 430da6c28aaSamw switch (type) { 431da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 432da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 433da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 434da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 435da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 436da6c28aaSamw return (B_FALSE); 437da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 438da6c28aaSamw } 439da6c28aaSamw 440003c2582SMark Shellenbaum /* 441003c2582SMark Shellenbaum * next check inheritance level flags 442003c2582SMark Shellenbaum */ 443003c2582SMark Shellenbaum 444b249c65cSmarks if (obj_type == VDIR && 445b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 446da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 447da6c28aaSamw 448da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 449da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 450da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 451da6c28aaSamw return (B_FALSE); 452da6c28aaSamw } 453da6c28aaSamw } 454da6c28aaSamw 455da6c28aaSamw return (B_TRUE); 456da6c28aaSamw } 457da6c28aaSamw 458da6c28aaSamw static void * 459da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 460da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 461da6c28aaSamw { 462da6c28aaSamw zfs_acl_node_t *aclnode; 463da6c28aaSamw 464da6c28aaSamw if (start == NULL) { 465da6c28aaSamw aclnode = list_head(&aclp->z_acl); 466da6c28aaSamw if (aclnode == NULL) 467da6c28aaSamw return (NULL); 468da6c28aaSamw 469da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 470da6c28aaSamw aclp->z_curr_node = aclnode; 471da6c28aaSamw aclnode->z_ace_idx = 0; 472da6c28aaSamw } 473da6c28aaSamw 474da6c28aaSamw aclnode = aclp->z_curr_node; 475da6c28aaSamw 476da6c28aaSamw if (aclnode == NULL) 477da6c28aaSamw return (NULL); 478da6c28aaSamw 479da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 480da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 481da6c28aaSamw if (aclnode == NULL) 482da6c28aaSamw return (NULL); 483da6c28aaSamw else { 484da6c28aaSamw aclp->z_curr_node = aclnode; 485da6c28aaSamw aclnode->z_ace_idx = 0; 486da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 487da6c28aaSamw } 488da6c28aaSamw } 489da6c28aaSamw 490da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 491da6c28aaSamw void *acep = aclp->z_next_ace; 492003c2582SMark Shellenbaum size_t ace_size; 493003c2582SMark Shellenbaum 494003c2582SMark Shellenbaum /* 495003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 496003c2582SMark Shellenbaum */ 497003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 498003c2582SMark Shellenbaum 499003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 500003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 501003c2582SMark Shellenbaum return (NULL); 502003c2582SMark Shellenbaum } 503003c2582SMark Shellenbaum 504da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 505da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 506da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 507da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 508003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 509da6c28aaSamw aclnode->z_ace_idx++; 510da6c28aaSamw return ((void *)acep); 511da6c28aaSamw } 512da6c28aaSamw return (NULL); 513da6c28aaSamw } 514da6c28aaSamw 515da6c28aaSamw /*ARGSUSED*/ 516da6c28aaSamw static uint64_t 517da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 518da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 519da6c28aaSamw { 520da6c28aaSamw zfs_acl_t *aclp = datap; 521da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 522da6c28aaSamw uint64_t who; 523da6c28aaSamw 524da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 525da6c28aaSamw flags, type); 526da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 527da6c28aaSamw } 528da6c28aaSamw 529da6c28aaSamw static zfs_acl_node_t * 530da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 531da6c28aaSamw { 532da6c28aaSamw ASSERT(aclp->z_curr_node); 533da6c28aaSamw return (aclp->z_curr_node); 534da6c28aaSamw } 535da6c28aaSamw 536da6c28aaSamw /* 537da6c28aaSamw * Copy ACE to internal ZFS format. 538da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 539da6c28aaSamw * ACE FUIDs will be created later. 540da6c28aaSamw */ 541da6c28aaSamw int 54289459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 54389459e17SMark Shellenbaum void *datap, zfs_ace_t *z_acl, int aclcnt, size_t *size, 54489459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 545da6c28aaSamw { 546da6c28aaSamw int i; 547da6c28aaSamw uint16_t entry_type; 548da6c28aaSamw zfs_ace_t *aceptr = z_acl; 549da6c28aaSamw ace_t *acep = datap; 550da6c28aaSamw zfs_object_ace_t *zobjacep; 551da6c28aaSamw ace_object_t *aceobjp; 552da6c28aaSamw 553da6c28aaSamw for (i = 0; i != aclcnt; i++) { 554da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 555da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 556da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 557da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 558da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 5594c841f60Smarks entry_type != ACE_EVERYONE) { 56089459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 56189459e17SMark Shellenbaum cr, (entry_type == 0) ? 56289459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 5634c841f60Smarks } 5644c841f60Smarks 565da6c28aaSamw /* 566da6c28aaSamw * Make sure ACE is valid 567da6c28aaSamw */ 568da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 569da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 570da6c28aaSamw return (EINVAL); 571da6c28aaSamw 572da6c28aaSamw switch (acep->a_type) { 573da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 574da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 575da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 576da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 577da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 578da6c28aaSamw aceobjp = (ace_object_t *)acep; 579da6c28aaSamw 580da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 581da6c28aaSamw sizeof (aceobjp->a_obj_type)); 582da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 583da6c28aaSamw zobjacep->z_inherit_type, 584da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 585da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 586da6c28aaSamw break; 587da6c28aaSamw default: 588da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 589da6c28aaSamw } 590da6c28aaSamw 591da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 592da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 593da6c28aaSamw } 594da6c28aaSamw 595da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 596da6c28aaSamw 597da6c28aaSamw return (0); 598da6c28aaSamw } 599da6c28aaSamw 600da6c28aaSamw /* 601da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 602da6c28aaSamw */ 603da6c28aaSamw static void 604bda89588Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 605bda89588Sjp151216 void *datap, int filter) 606da6c28aaSamw { 607da6c28aaSamw uint64_t who; 608da6c28aaSamw uint32_t access_mask; 609da6c28aaSamw uint16_t iflags, type; 610da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 611da6c28aaSamw ace_t *acep = datap; 612da6c28aaSamw ace_object_t *objacep; 613da6c28aaSamw zfs_object_ace_t *zobjacep; 614da6c28aaSamw size_t ace_size; 615da6c28aaSamw uint16_t entry_type; 616da6c28aaSamw 617da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 618da6c28aaSamw &who, &access_mask, &iflags, &type)) { 619da6c28aaSamw 620da6c28aaSamw switch (type) { 621da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 622da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 623da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 624da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 625da6c28aaSamw if (filter) { 626da6c28aaSamw continue; 627da6c28aaSamw } 628da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 629da6c28aaSamw objacep = (ace_object_t *)acep; 630da6c28aaSamw bcopy(zobjacep->z_object_type, 631da6c28aaSamw objacep->a_obj_type, 632da6c28aaSamw sizeof (zobjacep->z_object_type)); 633da6c28aaSamw bcopy(zobjacep->z_inherit_type, 634da6c28aaSamw objacep->a_inherit_obj_type, 635da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 636da6c28aaSamw ace_size = sizeof (ace_object_t); 637da6c28aaSamw break; 638da6c28aaSamw default: 639da6c28aaSamw ace_size = sizeof (ace_t); 640da6c28aaSamw break; 641da6c28aaSamw } 642da6c28aaSamw 643da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 644da6c28aaSamw if ((entry_type != ACE_OWNER && 6451ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 646e0d35c44Smarks entry_type != ACE_EVERYONE)) { 647e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 648e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 649e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 650e0d35c44Smarks } else { 651da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 652e0d35c44Smarks } 653da6c28aaSamw acep->a_access_mask = access_mask; 654da6c28aaSamw acep->a_flags = iflags; 655da6c28aaSamw acep->a_type = type; 656da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 657da6c28aaSamw } 658da6c28aaSamw } 659da6c28aaSamw 660da6c28aaSamw static int 661da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 662da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 663da6c28aaSamw { 664da6c28aaSamw int i; 665da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 666da6c28aaSamw 667da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 668da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 669da6c28aaSamw aceptr->z_type = acep[i].a_type; 670da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 671da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 672da6c28aaSamw /* 673da6c28aaSamw * Make sure ACE is valid 674da6c28aaSamw */ 675da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 676da6c28aaSamw aceptr->z_flags) != B_TRUE) 677da6c28aaSamw return (EINVAL); 678da6c28aaSamw } 679da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 680da6c28aaSamw return (0); 681da6c28aaSamw } 682da6c28aaSamw 683da6c28aaSamw /* 684da6c28aaSamw * convert old ACL format to new 685da6c28aaSamw */ 686da6c28aaSamw void 68789459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 688da6c28aaSamw { 689da6c28aaSamw zfs_oldace_t *oldaclp; 690da6c28aaSamw int i; 691da6c28aaSamw uint16_t type, iflags; 692da6c28aaSamw uint32_t access_mask; 693da6c28aaSamw uint64_t who; 694da6c28aaSamw void *cookie = NULL; 6952459a9eaSmarks zfs_acl_node_t *newaclnode; 696da6c28aaSamw 697da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 698da6c28aaSamw /* 699da6c28aaSamw * First create the ACE in a contiguous piece of memory 700da6c28aaSamw * for zfs_copy_ace_2_fuid(). 701da6c28aaSamw * 702da6c28aaSamw * We only convert an ACL once, so this won't happen 703da6c28aaSamw * everytime. 704da6c28aaSamw */ 705da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 706da6c28aaSamw KM_SLEEP); 707da6c28aaSamw i = 0; 708da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 709da6c28aaSamw &access_mask, &iflags, &type)) { 710da6c28aaSamw oldaclp[i].z_flags = iflags; 711da6c28aaSamw oldaclp[i].z_type = type; 712da6c28aaSamw oldaclp[i].z_fuid = who; 713da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 714da6c28aaSamw } 715da6c28aaSamw 716da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 717da6c28aaSamw sizeof (zfs_object_ace_t)); 718da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 71989459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 72089459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 72189459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 722da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 723da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 724da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 725da6c28aaSamw 726da6c28aaSamw /* 727da6c28aaSamw * Release all previous ACL nodes 728da6c28aaSamw */ 729da6c28aaSamw 7302459a9eaSmarks zfs_acl_release_nodes(aclp); 7312459a9eaSmarks 732da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 7332459a9eaSmarks 7342459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 7352459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 7362459a9eaSmarks 737fa9e4066Sahrens } 738fa9e4066Sahrens 739fa9e4066Sahrens /* 740fa9e4066Sahrens * Convert unix access mask to v4 access mask 741fa9e4066Sahrens */ 742fa9e4066Sahrens static uint32_t 743fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 744fa9e4066Sahrens { 745fa9e4066Sahrens uint32_t new_mask = 0; 746fa9e4066Sahrens 747da6c28aaSamw if (access_mask & S_IXOTH) 748da6c28aaSamw new_mask |= ACE_EXECUTE; 749da6c28aaSamw if (access_mask & S_IWOTH) 750da6c28aaSamw new_mask |= ACE_WRITE_DATA; 751da6c28aaSamw if (access_mask & S_IROTH) 752fa9e4066Sahrens new_mask |= ACE_READ_DATA; 753fa9e4066Sahrens return (new_mask); 754fa9e4066Sahrens } 755fa9e4066Sahrens 756fa9e4066Sahrens static void 757da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 758da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 759fa9e4066Sahrens { 760da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 761da6c28aaSamw 762da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 763da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 764da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 7651ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 766da6c28aaSamw type != ACE_EVERYONE)) 767da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 768fa9e4066Sahrens } 769fa9e4066Sahrens 770da6c28aaSamw /* 771da6c28aaSamw * Determine mode of file based on ACL. 772da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 773da6c28aaSamw */ 774fa9e4066Sahrens static uint64_t 77589459e17SMark Shellenbaum zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp) 776fa9e4066Sahrens { 777fa9e4066Sahrens int entry_type; 778da6c28aaSamw mode_t mode; 779fa9e4066Sahrens mode_t seen = 0; 780da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 781da6c28aaSamw uint64_t who; 782da6c28aaSamw uint16_t iflags, type; 783da6c28aaSamw uint32_t access_mask; 784*d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 785fa9e4066Sahrens 786da6c28aaSamw mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 787da6c28aaSamw 788da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 789da6c28aaSamw &access_mask, &iflags, &type)) { 79029a0b737Smarks 791003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 792003c2582SMark Shellenbaum continue; 793003c2582SMark Shellenbaum 794e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 795e6032be1Smarks 7961ab99678SMark Shellenbaum /* 7971ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 7981ab99678SMark Shellenbaum */ 7991ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 8001ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 8011ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 8021ab99678SMark Shellenbaum continue; 8031ab99678SMark Shellenbaum 804fa9e4066Sahrens if (entry_type == ACE_OWNER) { 805da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 806fa9e4066Sahrens (!(seen & S_IRUSR))) { 807fa9e4066Sahrens seen |= S_IRUSR; 808da6c28aaSamw if (type == ALLOW) { 809fa9e4066Sahrens mode |= S_IRUSR; 810fa9e4066Sahrens } 811fa9e4066Sahrens } 812da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 813fa9e4066Sahrens (!(seen & S_IWUSR))) { 814fa9e4066Sahrens seen |= S_IWUSR; 815da6c28aaSamw if (type == ALLOW) { 816fa9e4066Sahrens mode |= S_IWUSR; 817fa9e4066Sahrens } 818fa9e4066Sahrens } 819da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 820fa9e4066Sahrens (!(seen & S_IXUSR))) { 821fa9e4066Sahrens seen |= S_IXUSR; 822da6c28aaSamw if (type == ALLOW) { 823fa9e4066Sahrens mode |= S_IXUSR; 824fa9e4066Sahrens } 825fa9e4066Sahrens } 826fa9e4066Sahrens } else if (entry_type == OWNING_GROUP) { 827da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 828fa9e4066Sahrens (!(seen & S_IRGRP))) { 829fa9e4066Sahrens seen |= S_IRGRP; 830da6c28aaSamw if (type == ALLOW) { 831fa9e4066Sahrens mode |= S_IRGRP; 832fa9e4066Sahrens } 833fa9e4066Sahrens } 834da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 835fa9e4066Sahrens (!(seen & S_IWGRP))) { 836fa9e4066Sahrens seen |= S_IWGRP; 837da6c28aaSamw if (type == ALLOW) { 838fa9e4066Sahrens mode |= S_IWGRP; 839fa9e4066Sahrens } 840fa9e4066Sahrens } 841da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 842fa9e4066Sahrens (!(seen & S_IXGRP))) { 843fa9e4066Sahrens seen |= S_IXGRP; 844da6c28aaSamw if (type == ALLOW) { 845fa9e4066Sahrens mode |= S_IXGRP; 846fa9e4066Sahrens } 847fa9e4066Sahrens } 848fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 849da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 850fa9e4066Sahrens if (!(seen & S_IRUSR)) { 851fa9e4066Sahrens seen |= S_IRUSR; 852da6c28aaSamw if (type == ALLOW) { 853fa9e4066Sahrens mode |= S_IRUSR; 854fa9e4066Sahrens } 855fa9e4066Sahrens } 856fa9e4066Sahrens if (!(seen & S_IRGRP)) { 857fa9e4066Sahrens seen |= S_IRGRP; 858da6c28aaSamw if (type == ALLOW) { 859fa9e4066Sahrens mode |= S_IRGRP; 860fa9e4066Sahrens } 861fa9e4066Sahrens } 862fa9e4066Sahrens if (!(seen & S_IROTH)) { 863fa9e4066Sahrens seen |= S_IROTH; 864da6c28aaSamw if (type == ALLOW) { 865fa9e4066Sahrens mode |= S_IROTH; 866fa9e4066Sahrens } 867fa9e4066Sahrens } 868fa9e4066Sahrens } 869da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 870fa9e4066Sahrens if (!(seen & S_IWUSR)) { 871fa9e4066Sahrens seen |= S_IWUSR; 872da6c28aaSamw if (type == ALLOW) { 873fa9e4066Sahrens mode |= S_IWUSR; 874fa9e4066Sahrens } 875fa9e4066Sahrens } 876fa9e4066Sahrens if (!(seen & S_IWGRP)) { 877fa9e4066Sahrens seen |= S_IWGRP; 878da6c28aaSamw if (type == ALLOW) { 879fa9e4066Sahrens mode |= S_IWGRP; 880fa9e4066Sahrens } 881fa9e4066Sahrens } 882fa9e4066Sahrens if (!(seen & S_IWOTH)) { 883fa9e4066Sahrens seen |= S_IWOTH; 884da6c28aaSamw if (type == ALLOW) { 885fa9e4066Sahrens mode |= S_IWOTH; 886fa9e4066Sahrens } 887fa9e4066Sahrens } 888fa9e4066Sahrens } 889da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 890fa9e4066Sahrens if (!(seen & S_IXUSR)) { 891fa9e4066Sahrens seen |= S_IXUSR; 892da6c28aaSamw if (type == ALLOW) { 893fa9e4066Sahrens mode |= S_IXUSR; 894fa9e4066Sahrens } 895fa9e4066Sahrens } 896fa9e4066Sahrens if (!(seen & S_IXGRP)) { 897fa9e4066Sahrens seen |= S_IXGRP; 898da6c28aaSamw if (type == ALLOW) { 899fa9e4066Sahrens mode |= S_IXGRP; 900fa9e4066Sahrens } 901fa9e4066Sahrens } 902fa9e4066Sahrens if (!(seen & S_IXOTH)) { 903fa9e4066Sahrens seen |= S_IXOTH; 904da6c28aaSamw if (type == ALLOW) { 905fa9e4066Sahrens mode |= S_IXOTH; 906fa9e4066Sahrens } 907fa9e4066Sahrens } 908fa9e4066Sahrens } 909*d47621a4STim Haley } else { 910*d47621a4STim Haley /* 911*d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 912*d47621a4STim Haley * USER ACE denies execute access to someone, 913*d47621a4STim Haley * mode is not affected 914*d47621a4STim Haley */ 915*d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 916*d47621a4STim Haley an_exec_denied = B_TRUE; 917fa9e4066Sahrens } 918fa9e4066Sahrens } 919*d47621a4STim Haley 920*d47621a4STim Haley if (!an_exec_denied && !(seen & (S_IXUSR | S_IXGRP | S_IXOTH)) || 921*d47621a4STim Haley !(mode & (S_IXUSR | S_IXGRP | S_IXOTH))) 922*d47621a4STim Haley an_exec_denied = B_TRUE; 923*d47621a4STim Haley 924*d47621a4STim Haley if (an_exec_denied) 925*d47621a4STim Haley zp->z_phys->zp_flags &= ~ZFS_NO_EXECS_DENIED; 926*d47621a4STim Haley else 927*d47621a4STim Haley zp->z_phys->zp_flags |= ZFS_NO_EXECS_DENIED; 928*d47621a4STim Haley 929fa9e4066Sahrens return (mode); 930fa9e4066Sahrens } 931fa9e4066Sahrens 932fa9e4066Sahrens static zfs_acl_t * 933da6c28aaSamw zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify) 934fa9e4066Sahrens { 935fa9e4066Sahrens zfs_acl_t *aclp; 936da6c28aaSamw zfs_acl_node_t *aclnode; 937fa9e4066Sahrens 938da6c28aaSamw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 939da6c28aaSamw 940da6c28aaSamw /* 941da6c28aaSamw * Version 0 to 1 znode_acl_phys has the size/count fields swapped. 942da6c28aaSamw * Version 0 didn't have a size field, only a count. 943da6c28aaSamw */ 944da6c28aaSamw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 945da6c28aaSamw aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size; 946da6c28aaSamw aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count); 947da6c28aaSamw } else { 948fa9e4066Sahrens aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count; 949da6c28aaSamw aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size; 950da6c28aaSamw } 951da6c28aaSamw 952da6c28aaSamw aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0); 953da6c28aaSamw aclnode->z_ace_count = aclp->z_acl_count; 954da6c28aaSamw if (will_modify) { 955da6c28aaSamw bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata, 956da6c28aaSamw aclp->z_acl_bytes); 957da6c28aaSamw } else { 958da6c28aaSamw aclnode->z_size = aclp->z_acl_bytes; 959da6c28aaSamw aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0]; 960da6c28aaSamw } 961da6c28aaSamw 962da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 963fa9e4066Sahrens 964fa9e4066Sahrens return (aclp); 965fa9e4066Sahrens } 966fa9e4066Sahrens 967fa9e4066Sahrens /* 968fa9e4066Sahrens * Read an external acl object. 969fa9e4066Sahrens */ 970ea8dc4b6Seschrock static int 971da6c28aaSamw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) 972fa9e4066Sahrens { 973fa9e4066Sahrens uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj; 974fa9e4066Sahrens zfs_acl_t *aclp; 975da6c28aaSamw size_t aclsize; 976da6c28aaSamw size_t acl_count; 977da6c28aaSamw zfs_acl_node_t *aclnode; 978ea8dc4b6Seschrock int error; 979fa9e4066Sahrens 980fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 981fa9e4066Sahrens 982*d47621a4STim Haley if (zp->z_acl_cached) { 983*d47621a4STim Haley *aclpp = zp->z_acl_cached; 984*d47621a4STim Haley return (0); 985*d47621a4STim Haley } 986*d47621a4STim Haley 987ea8dc4b6Seschrock if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) { 988da6c28aaSamw *aclpp = zfs_acl_node_read_internal(zp, will_modify); 989*d47621a4STim Haley zp->z_acl_cached = *aclpp; 990ea8dc4b6Seschrock return (0); 991ea8dc4b6Seschrock } 992fa9e4066Sahrens 993da6c28aaSamw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 994da6c28aaSamw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 995da6c28aaSamw zfs_acl_phys_v0_t *zacl0 = 996da6c28aaSamw (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl; 997fa9e4066Sahrens 998da6c28aaSamw aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count); 999da6c28aaSamw acl_count = zacl0->z_acl_count; 1000da6c28aaSamw } else { 1001da6c28aaSamw aclsize = zp->z_phys->zp_acl.z_acl_size; 1002da6c28aaSamw acl_count = zp->z_phys->zp_acl.z_acl_count; 1003da6c28aaSamw if (aclsize == 0) 1004da6c28aaSamw aclsize = acl_count * sizeof (zfs_ace_t); 1005da6c28aaSamw } 1006da6c28aaSamw aclnode = zfs_acl_node_alloc(aclsize); 1007da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1008ea8dc4b6Seschrock error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0, 10097bfdf011SNeil Perrin aclsize, aclnode->z_acldata, DMU_READ_PREFETCH); 1010da6c28aaSamw aclnode->z_ace_count = acl_count; 1011da6c28aaSamw aclp->z_acl_count = acl_count; 1012da6c28aaSamw aclp->z_acl_bytes = aclsize; 1013da6c28aaSamw 1014ea8dc4b6Seschrock if (error != 0) { 1015ea8dc4b6Seschrock zfs_acl_free(aclp); 1016b87f3af3Sperrin /* convert checksum errors into IO errors */ 1017b87f3af3Sperrin if (error == ECKSUM) 1018b87f3af3Sperrin error = EIO; 1019ea8dc4b6Seschrock return (error); 1020ea8dc4b6Seschrock } 1021fa9e4066Sahrens 1022*d47621a4STim Haley zp->z_acl_cached = *aclpp = aclp; 1023ea8dc4b6Seschrock return (0); 1024fa9e4066Sahrens } 1025fa9e4066Sahrens 1026fa9e4066Sahrens /* 1027da6c28aaSamw * common code for setting ACLs. 1028fa9e4066Sahrens * 1029fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1030fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1031fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1032fa9e4066Sahrens */ 1033fa9e4066Sahrens int 103489459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1035fa9e4066Sahrens { 1036fa9e4066Sahrens int error; 1037fa9e4066Sahrens znode_phys_t *zphys = zp->z_phys; 1038da6c28aaSamw zfs_acl_phys_t *zacl = &zphys->zp_acl; 1039fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1040fa9e4066Sahrens uint64_t aoid = zphys->zp_acl.z_acl_extern_obj; 1041da6c28aaSamw uint64_t off = 0; 1042da6c28aaSamw dmu_object_type_t otype; 1043da6c28aaSamw zfs_acl_node_t *aclnode; 1044fa9e4066Sahrens 1045fa9e4066Sahrens dmu_buf_will_dirty(zp->z_dbuf, tx); 1046fa9e4066Sahrens 1047*d47621a4STim Haley if (zp->z_acl_cached != aclp && zp->z_acl_cached) { 1048*d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1049*d47621a4STim Haley zp->z_acl_cached = NULL; 1050*d47621a4STim Haley } 1051*d47621a4STim Haley 105289459e17SMark Shellenbaum zphys->zp_mode = zfs_mode_compute(zp, aclp); 1053da6c28aaSamw 1054fa9e4066Sahrens /* 1055da6c28aaSamw * Decide which opbject type to use. If we are forced to 1056da6c28aaSamw * use old ACL format than transform ACL into zfs_oldace_t 1057da6c28aaSamw * layout. 1058fa9e4066Sahrens */ 1059da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1060da6c28aaSamw otype = DMU_OT_OLDACL; 1061da6c28aaSamw } else { 1062da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1063da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 106489459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1065da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1066da6c28aaSamw otype = DMU_OT_ACL; 1067da6c28aaSamw } 1068da6c28aaSamw 1069da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1070da6c28aaSamw /* 1071da6c28aaSamw * If ACL was previously external and we are now 1072da6c28aaSamw * converting to new ACL format then release old 1073da6c28aaSamw * ACL object and create a new one. 1074da6c28aaSamw */ 1075da6c28aaSamw if (aoid && aclp->z_version != zacl->z_acl_version) { 1076da6c28aaSamw error = dmu_object_free(zfsvfs->z_os, 1077da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, tx); 1078da6c28aaSamw if (error) 1079da6c28aaSamw return (error); 1080da6c28aaSamw aoid = 0; 1081da6c28aaSamw } 1082fa9e4066Sahrens if (aoid == 0) { 1083fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1084da6c28aaSamw otype, aclp->z_acl_bytes, 1085da6c28aaSamw otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE, 1086da6c28aaSamw otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx); 1087fa9e4066Sahrens } else { 1088fa9e4066Sahrens (void) dmu_object_set_blocksize(zfsvfs->z_os, aoid, 1089da6c28aaSamw aclp->z_acl_bytes, 0, tx); 1090fa9e4066Sahrens } 1091fa9e4066Sahrens zphys->zp_acl.z_acl_extern_obj = aoid; 1092da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1093da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1094da6c28aaSamw if (aclnode->z_ace_count == 0) 1095da6c28aaSamw continue; 1096da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1097da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1098da6c28aaSamw off += aclnode->z_size; 1099da6c28aaSamw } 1100fa9e4066Sahrens } else { 1101da6c28aaSamw void *start = zacl->z_ace_data; 1102fa9e4066Sahrens /* 1103fa9e4066Sahrens * Migrating back embedded? 1104fa9e4066Sahrens */ 1105fa9e4066Sahrens if (zphys->zp_acl.z_acl_extern_obj) { 1106fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 1107fa9e4066Sahrens zp->z_phys->zp_acl.z_acl_extern_obj, tx); 1108fa9e4066Sahrens if (error) 1109fa9e4066Sahrens return (error); 1110fa9e4066Sahrens zphys->zp_acl.z_acl_extern_obj = 0; 1111fa9e4066Sahrens } 1112da6c28aaSamw 1113da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1114da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1115da6c28aaSamw if (aclnode->z_ace_count == 0) 1116da6c28aaSamw continue; 1117da6c28aaSamw bcopy(aclnode->z_acldata, start, aclnode->z_size); 1118da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1119da6c28aaSamw } 1120fa9e4066Sahrens } 1121de122929Smarks 1122da6c28aaSamw /* 1123da6c28aaSamw * If Old version then swap count/bytes to match old 1124da6c28aaSamw * layout of znode_acl_phys_t. 1125da6c28aaSamw */ 1126da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1127da6c28aaSamw zphys->zp_acl.z_acl_size = aclp->z_acl_count; 1128da6c28aaSamw zphys->zp_acl.z_acl_count = aclp->z_acl_bytes; 1129da6c28aaSamw } else { 1130da6c28aaSamw zphys->zp_acl.z_acl_size = aclp->z_acl_bytes; 1131da6c28aaSamw zphys->zp_acl.z_acl_count = aclp->z_acl_count; 1132da6c28aaSamw } 1133da6c28aaSamw 1134da6c28aaSamw zphys->zp_acl.z_acl_version = aclp->z_version; 1135da6c28aaSamw 1136da6c28aaSamw /* 1137da6c28aaSamw * Replace ACL wide bits, but first clear them. 1138da6c28aaSamw */ 1139da6c28aaSamw zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS; 1140da6c28aaSamw 1141da6c28aaSamw zp->z_phys->zp_flags |= aclp->z_hints; 1142da6c28aaSamw 1143da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 1144de122929Smarks zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL; 1145fa9e4066Sahrens 1146fa9e4066Sahrens return (0); 1147fa9e4066Sahrens } 1148fa9e4066Sahrens 1149fa9e4066Sahrens /* 1150fa9e4066Sahrens * Update access mask for prepended ACE 1151fa9e4066Sahrens * 1152fa9e4066Sahrens * This applies the "groupmask" value for aclmode property. 1153fa9e4066Sahrens */ 1154fa9e4066Sahrens static void 1155da6c28aaSamw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, 1156da6c28aaSamw mode_t mode, uint64_t owner) 1157fa9e4066Sahrens { 1158fa9e4066Sahrens int rmask, wmask, xmask; 1159fa9e4066Sahrens int user_ace; 1160da6c28aaSamw uint16_t aceflags; 1161da6c28aaSamw uint32_t origmask, acepmask; 1162da6c28aaSamw uint64_t fuid; 1163fa9e4066Sahrens 1164da6c28aaSamw aceflags = aclp->z_ops.ace_flags_get(acep); 1165da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1166da6c28aaSamw origmask = aclp->z_ops.ace_mask_get(origacep); 1167da6c28aaSamw acepmask = aclp->z_ops.ace_mask_get(acep); 1168da6c28aaSamw 1169da6c28aaSamw user_ace = (!(aceflags & 1170fa9e4066Sahrens (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); 1171fa9e4066Sahrens 1172da6c28aaSamw if (user_ace && (fuid == owner)) { 1173fa9e4066Sahrens rmask = S_IRUSR; 1174fa9e4066Sahrens wmask = S_IWUSR; 1175fa9e4066Sahrens xmask = S_IXUSR; 1176fa9e4066Sahrens } else { 1177fa9e4066Sahrens rmask = S_IRGRP; 1178fa9e4066Sahrens wmask = S_IWGRP; 1179fa9e4066Sahrens xmask = S_IXGRP; 1180fa9e4066Sahrens } 1181fa9e4066Sahrens 1182da6c28aaSamw if (origmask & ACE_READ_DATA) { 1183da6c28aaSamw if (mode & rmask) { 1184da6c28aaSamw acepmask &= ~ACE_READ_DATA; 1185da6c28aaSamw } else { 1186da6c28aaSamw acepmask |= ACE_READ_DATA; 1187da6c28aaSamw } 1188fa9e4066Sahrens } 1189fa9e4066Sahrens 1190da6c28aaSamw if (origmask & ACE_WRITE_DATA) { 1191da6c28aaSamw if (mode & wmask) { 1192da6c28aaSamw acepmask &= ~ACE_WRITE_DATA; 1193da6c28aaSamw } else { 1194da6c28aaSamw acepmask |= ACE_WRITE_DATA; 1195da6c28aaSamw } 1196fa9e4066Sahrens } 1197fa9e4066Sahrens 1198da6c28aaSamw if (origmask & ACE_APPEND_DATA) { 1199da6c28aaSamw if (mode & wmask) { 1200da6c28aaSamw acepmask &= ~ACE_APPEND_DATA; 1201da6c28aaSamw } else { 1202da6c28aaSamw acepmask |= ACE_APPEND_DATA; 1203da6c28aaSamw } 1204fa9e4066Sahrens } 1205fa9e4066Sahrens 1206da6c28aaSamw if (origmask & ACE_EXECUTE) { 1207da6c28aaSamw if (mode & xmask) { 1208da6c28aaSamw acepmask &= ~ACE_EXECUTE; 1209da6c28aaSamw } else { 1210da6c28aaSamw acepmask |= ACE_EXECUTE; 1211fa9e4066Sahrens } 1212fa9e4066Sahrens } 1213da6c28aaSamw aclp->z_ops.ace_mask_set(acep, acepmask); 1214da6c28aaSamw } 1215fa9e4066Sahrens 1216fa9e4066Sahrens /* 1217fa9e4066Sahrens * Apply mode to canonical six ACEs. 1218fa9e4066Sahrens */ 1219fa9e4066Sahrens static void 1220fa9e4066Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode) 1221fa9e4066Sahrens { 1222da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1223da6c28aaSamw void *acep; 1224da6c28aaSamw int maskoff = aclp->z_ops.ace_mask_off(); 1225da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1226fa9e4066Sahrens 1227da6c28aaSamw ASSERT(aclnode != NULL); 1228da6c28aaSamw 1229da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1230da6c28aaSamw aclnode->z_size - (abstract_size * 6)); 1231fa9e4066Sahrens 1232fa9e4066Sahrens /* 1233fa9e4066Sahrens * Fixup final ACEs to match the mode 1234fa9e4066Sahrens */ 1235fa9e4066Sahrens 1236da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1237da6c28aaSamw (mode & 0700) >> 6); /* owner@ */ 1238da6c28aaSamw 1239da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1240da6c28aaSamw 1241da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1242da6c28aaSamw (mode & 0070) >> 3); /* group@ */ 1243da6c28aaSamw 1244da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1245da6c28aaSamw adjust_ace_pair_common(acep, maskoff, 1246da6c28aaSamw abstract_size, mode); /* everyone@ */ 1247fa9e4066Sahrens } 1248fa9e4066Sahrens 1249fa9e4066Sahrens 1250fa9e4066Sahrens static int 1251da6c28aaSamw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny, 1252da6c28aaSamw int entry_type, int accessmask) 1253fa9e4066Sahrens { 1254da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1255da6c28aaSamw uint16_t type = aclp->z_ops.ace_type_get(acep); 1256da6c28aaSamw uint16_t flags = aclp->z_ops.ace_flags_get(acep); 1257da6c28aaSamw 1258da6c28aaSamw return (mask == accessmask && type == allow_deny && 1259da6c28aaSamw ((flags & ACE_TYPE_FLAGS) == entry_type)); 1260fa9e4066Sahrens } 1261fa9e4066Sahrens 1262fa9e4066Sahrens /* 1263fa9e4066Sahrens * Can prepended ACE be reused? 1264fa9e4066Sahrens */ 1265fa9e4066Sahrens static int 1266da6c28aaSamw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep) 1267fa9e4066Sahrens { 1268fa9e4066Sahrens int okay_masks; 1269da6c28aaSamw uint16_t prevtype; 1270da6c28aaSamw uint16_t prevflags; 1271da6c28aaSamw uint16_t flags; 1272da6c28aaSamw uint32_t mask, prevmask; 1273fa9e4066Sahrens 1274da6c28aaSamw if (prevacep == NULL) 1275fa9e4066Sahrens return (B_FALSE); 1276fa9e4066Sahrens 1277da6c28aaSamw prevtype = aclp->z_ops.ace_type_get(prevacep); 1278da6c28aaSamw prevflags = aclp->z_ops.ace_flags_get(prevacep); 1279da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1280da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1281da6c28aaSamw prevmask = aclp->z_ops.ace_mask_get(prevacep); 1282da6c28aaSamw 1283da6c28aaSamw if (prevtype != DENY) 1284fa9e4066Sahrens return (B_FALSE); 1285fa9e4066Sahrens 1286da6c28aaSamw if (prevflags != (flags & ACE_IDENTIFIER_GROUP)) 1287fa9e4066Sahrens return (B_FALSE); 1288fa9e4066Sahrens 1289da6c28aaSamw okay_masks = (mask & OKAY_MASK_BITS); 1290fa9e4066Sahrens 1291da6c28aaSamw if (prevmask & ~okay_masks) 1292fa9e4066Sahrens return (B_FALSE); 1293fa9e4066Sahrens 1294fa9e4066Sahrens return (B_TRUE); 1295fa9e4066Sahrens } 1296fa9e4066Sahrens 1297da6c28aaSamw 1298fa9e4066Sahrens /* 1299da6c28aaSamw * Insert new ACL node into chain of zfs_acl_node_t's 1300da6c28aaSamw * 1301da6c28aaSamw * This will result in two possible results. 1302da6c28aaSamw * 1. If the ACL is currently just a single zfs_acl_node and 1303da6c28aaSamw * we are prepending the entry then current acl node will have 1304da6c28aaSamw * a new node inserted above it. 1305da6c28aaSamw * 1306da6c28aaSamw * 2. If we are inserting in the middle of current acl node then 1307da6c28aaSamw * the current node will be split in two and new node will be inserted 1308da6c28aaSamw * in between the two split nodes. 1309fa9e4066Sahrens */ 1310da6c28aaSamw static zfs_acl_node_t * 1311da6c28aaSamw zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep) 1312fa9e4066Sahrens { 1313da6c28aaSamw zfs_acl_node_t *newnode; 1314da6c28aaSamw zfs_acl_node_t *trailernode = NULL; 1315da6c28aaSamw zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp); 1316da6c28aaSamw int curr_idx = aclp->z_curr_node->z_ace_idx; 1317da6c28aaSamw int trailer_count; 1318da6c28aaSamw size_t oldsize; 1319fa9e4066Sahrens 1320da6c28aaSamw newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep)); 1321da6c28aaSamw newnode->z_ace_count = 1; 1322fa9e4066Sahrens 1323da6c28aaSamw oldsize = currnode->z_size; 1324fa9e4066Sahrens 1325da6c28aaSamw if (curr_idx != 1) { 1326da6c28aaSamw trailernode = zfs_acl_node_alloc(0); 1327da6c28aaSamw trailernode->z_acldata = acep; 1328da6c28aaSamw 1329da6c28aaSamw trailer_count = currnode->z_ace_count - curr_idx + 1; 1330da6c28aaSamw currnode->z_ace_count = curr_idx - 1; 1331da6c28aaSamw currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata; 1332da6c28aaSamw trailernode->z_size = oldsize - currnode->z_size; 1333da6c28aaSamw trailernode->z_ace_count = trailer_count; 1334fa9e4066Sahrens } 1335fa9e4066Sahrens 1336da6c28aaSamw aclp->z_acl_count += 1; 1337da6c28aaSamw aclp->z_acl_bytes += aclp->z_ops.ace_size(acep); 1338fa9e4066Sahrens 1339da6c28aaSamw if (curr_idx == 1) 1340da6c28aaSamw list_insert_before(&aclp->z_acl, currnode, newnode); 1341da6c28aaSamw else 1342da6c28aaSamw list_insert_after(&aclp->z_acl, currnode, newnode); 1343da6c28aaSamw if (trailernode) { 1344da6c28aaSamw list_insert_after(&aclp->z_acl, newnode, trailernode); 1345da6c28aaSamw aclp->z_curr_node = trailernode; 1346da6c28aaSamw trailernode->z_ace_idx = 1; 1347fa9e4066Sahrens } 1348fa9e4066Sahrens 1349da6c28aaSamw return (newnode); 1350fa9e4066Sahrens } 1351fa9e4066Sahrens 1352fa9e4066Sahrens /* 1353fa9e4066Sahrens * Prepend deny ACE 1354fa9e4066Sahrens */ 1355da6c28aaSamw static void * 135689459e17SMark Shellenbaum zfs_acl_prepend_deny(uint64_t uid, zfs_acl_t *aclp, void *acep, 1357fa9e4066Sahrens mode_t mode) 1358fa9e4066Sahrens { 1359da6c28aaSamw zfs_acl_node_t *aclnode; 1360da6c28aaSamw void *newacep; 1361da6c28aaSamw uint64_t fuid; 1362da6c28aaSamw uint16_t flags; 1363fa9e4066Sahrens 1364da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1365da6c28aaSamw newacep = aclnode->z_acldata; 1366da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1367da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1368da6c28aaSamw zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS)); 136989459e17SMark Shellenbaum zfs_acl_prepend_fixup(aclp, newacep, acep, mode, uid); 1370fa9e4066Sahrens 1371da6c28aaSamw return (newacep); 1372fa9e4066Sahrens } 1373fa9e4066Sahrens 1374fa9e4066Sahrens /* 1375fa9e4066Sahrens * Split an inherited ACE into inherit_only ACE 1376fa9e4066Sahrens * and original ACE with inheritance flags stripped off. 1377fa9e4066Sahrens */ 1378fa9e4066Sahrens static void 1379da6c28aaSamw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep) 1380fa9e4066Sahrens { 1381da6c28aaSamw zfs_acl_node_t *aclnode; 1382569e6c63Smarks zfs_acl_node_t *currnode; 1383da6c28aaSamw void *newacep; 1384da6c28aaSamw uint16_t type, flags; 1385da6c28aaSamw uint32_t mask; 1386da6c28aaSamw uint64_t fuid; 1387fa9e4066Sahrens 1388da6c28aaSamw type = aclp->z_ops.ace_type_get(acep); 1389da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1390da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1391da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1392da6c28aaSamw 1393da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1394da6c28aaSamw newacep = aclnode->z_acldata; 1395da6c28aaSamw 1396da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1397da6c28aaSamw aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE); 1398da6c28aaSamw aclp->z_ops.ace_mask_set(newacep, mask); 1399da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1400da6c28aaSamw aclp->z_ops.ace_who_set(newacep, fuid); 1401da6c28aaSamw aclp->z_next_ace = acep; 1402da6c28aaSamw flags &= ~ALL_INHERIT; 1403da6c28aaSamw aclp->z_ops.ace_flags_set(acep, flags); 1404569e6c63Smarks currnode = zfs_acl_curr_node(aclp); 1405569e6c63Smarks ASSERT(currnode->z_ace_idx >= 1); 1406da6c28aaSamw currnode->z_ace_idx -= 1; 1407fa9e4066Sahrens } 1408fa9e4066Sahrens 1409fa9e4066Sahrens /* 1410fa9e4066Sahrens * Are ACES started at index i, the canonical six ACES? 1411fa9e4066Sahrens */ 1412fa9e4066Sahrens static int 1413da6c28aaSamw zfs_have_canonical_six(zfs_acl_t *aclp) 1414fa9e4066Sahrens { 1415da6c28aaSamw void *acep; 1416da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1417da6c28aaSamw int i = 0; 1418da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1419fa9e4066Sahrens 1420da6c28aaSamw ASSERT(aclnode != NULL); 1421da6c28aaSamw 1422da6c28aaSamw if (aclnode->z_ace_count < 6) 1423da6c28aaSamw return (0); 1424da6c28aaSamw 1425da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1426da6c28aaSamw aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6)); 1427da6c28aaSamw 1428da6c28aaSamw if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1429fa9e4066Sahrens DENY, ACE_OWNER, 0) && 1430da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1431da6c28aaSamw ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) && 1432da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY, 1433da6c28aaSamw OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep + 1434da6c28aaSamw (abstract_size * i++), 1435da6c28aaSamw ALLOW, OWNING_GROUP, 0) && 1436da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1437fa9e4066Sahrens DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) && 1438da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1439da6c28aaSamw ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) { 1440fa9e4066Sahrens return (1); 1441fa9e4066Sahrens } else { 1442fa9e4066Sahrens return (0); 1443fa9e4066Sahrens } 1444fa9e4066Sahrens } 1445fa9e4066Sahrens 1446da6c28aaSamw 1447fa9e4066Sahrens /* 1448fa9e4066Sahrens * Apply step 1g, to group entries 1449fa9e4066Sahrens * 1450fa9e4066Sahrens * Need to deal with corner case where group may have 1451fa9e4066Sahrens * greater permissions than owner. If so then limit 1452fa9e4066Sahrens * group permissions, based on what extra permissions 1453fa9e4066Sahrens * group has. 1454fa9e4066Sahrens */ 1455fa9e4066Sahrens static void 1456da6c28aaSamw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep, 1457da6c28aaSamw mode_t mode) 1458fa9e4066Sahrens { 1459da6c28aaSamw uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep); 1460da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1461da6c28aaSamw uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep); 1462fa9e4066Sahrens mode_t extramode = (mode >> 3) & 07; 1463fa9e4066Sahrens mode_t ownermode = (mode >> 6); 1464fa9e4066Sahrens 1465da6c28aaSamw if (prevflags & ACE_IDENTIFIER_GROUP) { 1466fa9e4066Sahrens 1467fa9e4066Sahrens extramode &= ~ownermode; 1468fa9e4066Sahrens 1469fa9e4066Sahrens if (extramode) { 1470da6c28aaSamw if (extramode & S_IROTH) { 1471da6c28aaSamw prevmask &= ~ACE_READ_DATA; 1472da6c28aaSamw mask &= ~ACE_READ_DATA; 1473fa9e4066Sahrens } 1474da6c28aaSamw if (extramode & S_IWOTH) { 1475da6c28aaSamw prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1476da6c28aaSamw mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1477fa9e4066Sahrens } 1478da6c28aaSamw if (extramode & S_IXOTH) { 1479da6c28aaSamw prevmask &= ~ACE_EXECUTE; 1480da6c28aaSamw mask &= ~ACE_EXECUTE; 1481fa9e4066Sahrens } 1482fa9e4066Sahrens } 1483fa9e4066Sahrens } 1484da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1485da6c28aaSamw aclp->z_ops.ace_mask_set(prevacep, prevmask); 1486fa9e4066Sahrens } 1487fa9e4066Sahrens 1488fa9e4066Sahrens /* 1489fa9e4066Sahrens * Apply the chmod algorithm as described 1490fa9e4066Sahrens * in PSARC/2002/240 1491fa9e4066Sahrens */ 14924c841f60Smarks static void 149389459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t uid, 149489459e17SMark Shellenbaum uint64_t mode, zfs_acl_t *aclp) 1495fa9e4066Sahrens { 1496da6c28aaSamw void *acep = NULL, *prevacep = NULL; 1497da6c28aaSamw uint64_t who; 1498fa9e4066Sahrens int i; 1499fa9e4066Sahrens int entry_type; 1500fa9e4066Sahrens int reuse_deny; 1501fa9e4066Sahrens int need_canonical_six = 1; 1502da6c28aaSamw uint16_t iflags, type; 1503da6c28aaSamw uint32_t access_mask; 1504fa9e4066Sahrens 15052459a9eaSmarks /* 15062459a9eaSmarks * If discard then just discard all ACL nodes which 15072459a9eaSmarks * represent the ACEs. 15082459a9eaSmarks * 15092459a9eaSmarks * New owner@/group@/everone@ ACEs will be added 15102459a9eaSmarks * later. 15112459a9eaSmarks */ 15122459a9eaSmarks if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 15132459a9eaSmarks zfs_acl_release_nodes(aclp); 15142459a9eaSmarks 1515da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1516da6c28aaSamw &iflags, &type)) { 1517fa9e4066Sahrens 1518da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 1519da6c28aaSamw iflags = (iflags & ALL_INHERIT); 1520da6c28aaSamw 1521da6c28aaSamw if ((type != ALLOW && type != DENY) || 1522de122929Smarks (iflags & ACE_INHERIT_ONLY_ACE)) { 1523de122929Smarks if (iflags) 1524da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1525da6c28aaSamw switch (type) { 1526da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1527da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1528da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1529da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1530da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1531da6c28aaSamw break; 1532fa9e4066Sahrens } 1533da6c28aaSamw goto nextace; 1534da6c28aaSamw } 1535fa9e4066Sahrens 1536fa9e4066Sahrens /* 1537fa9e4066Sahrens * Need to split ace into two? 1538fa9e4066Sahrens */ 1539de122929Smarks if ((iflags & (ACE_FILE_INHERIT_ACE| 1540fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE)) && 1541de122929Smarks (!(iflags & ACE_INHERIT_ONLY_ACE))) { 1542da6c28aaSamw zfs_acl_split_ace(aclp, acep); 1543da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1544da6c28aaSamw goto nextace; 1545fa9e4066Sahrens } 1546fa9e4066Sahrens 1547fa9e4066Sahrens if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 1548fa9e4066Sahrens (entry_type == OWNING_GROUP)) { 1549da6c28aaSamw access_mask &= ~OGE_CLEAR; 1550da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 1551da6c28aaSamw goto nextace; 1552fa9e4066Sahrens } else { 1553da6c28aaSamw reuse_deny = B_TRUE; 1554da6c28aaSamw if (type == ALLOW) { 1555fa9e4066Sahrens 1556fa9e4066Sahrens /* 1557fa9e4066Sahrens * Check preceding ACE if any, to see 1558fa9e4066Sahrens * if we need to prepend a DENY ACE. 1559fa9e4066Sahrens * This is only applicable when the acl_mode 1560fa9e4066Sahrens * property == groupmask. 1561fa9e4066Sahrens */ 1562e9dbad6fSeschrock if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) { 1563fa9e4066Sahrens 1564da6c28aaSamw reuse_deny = zfs_reuse_deny(aclp, acep, 1565da6c28aaSamw prevacep); 1566fa9e4066Sahrens 1567e0d35c44Smarks if (!reuse_deny) { 1568da6c28aaSamw prevacep = 156989459e17SMark Shellenbaum zfs_acl_prepend_deny(uid, 1570da6c28aaSamw aclp, acep, mode); 1571fa9e4066Sahrens } else { 1572fa9e4066Sahrens zfs_acl_prepend_fixup( 1573da6c28aaSamw aclp, prevacep, 157489459e17SMark Shellenbaum acep, mode, uid); 1575fa9e4066Sahrens } 1576da6c28aaSamw zfs_fixup_group_entries(aclp, acep, 1577da6c28aaSamw prevacep, mode); 1578fa9e4066Sahrens } 1579fa9e4066Sahrens } 1580fa9e4066Sahrens } 1581da6c28aaSamw nextace: 1582da6c28aaSamw prevacep = acep; 1583fa9e4066Sahrens } 1584fa9e4066Sahrens 1585fa9e4066Sahrens /* 1586fa9e4066Sahrens * Check out last six aces, if we have six. 1587fa9e4066Sahrens */ 1588fa9e4066Sahrens 1589fa9e4066Sahrens if (aclp->z_acl_count >= 6) { 1590da6c28aaSamw if (zfs_have_canonical_six(aclp)) { 1591fa9e4066Sahrens need_canonical_six = 0; 1592fa9e4066Sahrens } 1593fa9e4066Sahrens } 1594fa9e4066Sahrens 1595fa9e4066Sahrens if (need_canonical_six) { 1596da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1597da6c28aaSamw void *zacep; 1598da6c28aaSamw zfs_acl_node_t *aclnode = 1599da6c28aaSamw zfs_acl_node_alloc(abstract_size * 6); 1600fa9e4066Sahrens 1601da6c28aaSamw aclnode->z_size = abstract_size * 6; 1602da6c28aaSamw aclnode->z_ace_count = 6; 1603da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1604da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1605da6c28aaSamw 1606da6c28aaSamw zacep = aclnode->z_acldata; 1607da6c28aaSamw 1608da6c28aaSamw i = 0; 1609da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1610da6c28aaSamw 0, DENY, -1, ACE_OWNER); 1611da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1612da6c28aaSamw OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER); 1613da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1614da6c28aaSamw DENY, -1, OWNING_GROUP); 1615da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1616da6c28aaSamw ALLOW, -1, OWNING_GROUP); 1617da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1618da6c28aaSamw EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE); 1619da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1620da6c28aaSamw EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE); 1621fa9e4066Sahrens aclp->z_acl_count += 6; 1622fa9e4066Sahrens } 1623fa9e4066Sahrens 1624fa9e4066Sahrens zfs_acl_fixup_canonical_six(aclp, mode); 1625fa9e4066Sahrens } 1626fa9e4066Sahrens 1627fa9e4066Sahrens int 16284c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1629fa9e4066Sahrens { 1630fa9e4066Sahrens int error; 1631fa9e4066Sahrens 16324c841f60Smarks mutex_enter(&zp->z_lock); 1633fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 16344c841f60Smarks *aclp = NULL; 16354c841f60Smarks error = zfs_acl_node_read(zp, aclp, B_TRUE); 163689459e17SMark Shellenbaum if (error == 0) { 163789459e17SMark Shellenbaum (*aclp)->z_hints = zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS; 163889459e17SMark Shellenbaum zfs_acl_chmod(zp->z_zfsvfs, zp->z_phys->zp_uid, mode, *aclp); 1639*d47621a4STim Haley zp->z_acl_cached = *aclp; 164089459e17SMark Shellenbaum } 1641fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 16424c841f60Smarks mutex_exit(&zp->z_lock); 1643fa9e4066Sahrens return (error); 1644fa9e4066Sahrens } 1645fa9e4066Sahrens 1646fa9e4066Sahrens /* 1647fa9e4066Sahrens * strip off write_owner and write_acl 1648fa9e4066Sahrens */ 1649fa9e4066Sahrens static void 1650b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1651fa9e4066Sahrens { 1652da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1653da6c28aaSamw 1654b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1655da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1656b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1657da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1658da6c28aaSamw } 1659da6c28aaSamw } 1660da6c28aaSamw 1661da6c28aaSamw /* 1662da6c28aaSamw * Should ACE be inherited? 1663da6c28aaSamw */ 1664da6c28aaSamw static int 166589459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1666da6c28aaSamw { 1667da6c28aaSamw int iflags = (acep_flags & 0xf); 1668da6c28aaSamw 1669da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1670da6c28aaSamw return (1); 1671da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1672da6c28aaSamw return (!((vtype == VDIR) && 1673da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1674da6c28aaSamw return (0); 1675fa9e4066Sahrens } 1676fa9e4066Sahrens 1677fa9e4066Sahrens /* 1678fa9e4066Sahrens * inherit inheritable ACEs from parent 1679fa9e4066Sahrens */ 1680fa9e4066Sahrens static zfs_acl_t * 168189459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 168289459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1683fa9e4066Sahrens { 1684da6c28aaSamw void *pacep; 1685da6c28aaSamw void *acep, *acep2; 1686da6c28aaSamw zfs_acl_node_t *aclnode, *aclnode2; 1687fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1688da6c28aaSamw uint64_t who; 1689da6c28aaSamw uint32_t access_mask; 1690da6c28aaSamw uint16_t iflags, newflags, type; 1691da6c28aaSamw size_t ace_size; 1692da6c28aaSamw void *data1, *data2; 1693da6c28aaSamw size_t data1sz, data2sz; 169489459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 169589459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1696d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1697d0f3f37eSMark Shellenbaum 1698d0f3f37eSMark Shellenbaum passthrough_x = 1699d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1700d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1701d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1702d0f3f37eSMark Shellenbaum noallow = 1703d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1704fa9e4066Sahrens 1705b3d141f8Smarks *need_chmod = B_TRUE; 1706da6c28aaSamw pacep = NULL; 1707003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 1708d0f3f37eSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD) 1709d0f3f37eSMark Shellenbaum return (aclp); 1710da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1711da6c28aaSamw &access_mask, &iflags, &type)) { 1712fa9e4066Sahrens 1713003c2582SMark Shellenbaum /* 1714003c2582SMark Shellenbaum * don't inherit bogus ACEs 1715003c2582SMark Shellenbaum */ 1716003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1717003c2582SMark Shellenbaum continue; 1718003c2582SMark Shellenbaum 1719d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1720fa9e4066Sahrens continue; 1721fa9e4066Sahrens 1722da6c28aaSamw ace_size = aclp->z_ops.ace_size(pacep); 1723fa9e4066Sahrens 172489459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1725b3d141f8Smarks continue; 1726fa9e4066Sahrens 1727b3d141f8Smarks /* 1728b3d141f8Smarks * If owner@, group@, or everyone@ inheritable 1729b3d141f8Smarks * then zfs_acl_chmod() isn't needed. 1730b3d141f8Smarks */ 1731d0f3f37eSMark Shellenbaum if (passthrough && 1732b3d141f8Smarks ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1733b3d141f8Smarks ((iflags & OWNING_GROUP) == 1734d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1735d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1736b3d141f8Smarks *need_chmod = B_FALSE; 1737b3d141f8Smarks 1738d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1739d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1740d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1741d0f3f37eSMark Shellenbaum } 1742d0f3f37eSMark Shellenbaum } 1743d0f3f37eSMark Shellenbaum 1744b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1745da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1746da6c28aaSamw acep = aclnode->z_acldata; 1747d0f3f37eSMark Shellenbaum 1748da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1749da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1750169cdae2Smarks 1751fa9e4066Sahrens /* 1752da6c28aaSamw * Copy special opaque data if any 1753fa9e4066Sahrens */ 1754d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1755b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1756da6c28aaSamw &data2)) == data1sz); 1757da6c28aaSamw bcopy(data1, data2, data2sz); 1758da6c28aaSamw } 1759da6c28aaSamw aclp->z_acl_count++; 1760da6c28aaSamw aclnode->z_ace_count++; 1761da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1762da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1763b3d141f8Smarks 1764d0f3f37eSMark Shellenbaum if (vdir) 1765b3d141f8Smarks aclp->z_hints |= ZFS_INHERIT_ACE; 1766b3d141f8Smarks 1767d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1768da6c28aaSamw newflags &= ~ALL_INHERIT; 1769da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1770da6c28aaSamw newflags|ACE_INHERITED_ACE); 1771b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep); 1772fa9e4066Sahrens continue; 1773fa9e4066Sahrens } 1774fa9e4066Sahrens 1775d0f3f37eSMark Shellenbaum ASSERT(vdir); 1776fa9e4066Sahrens 1777da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1778da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE | 1779169cdae2Smarks ACE_DIRECTORY_INHERIT_ACE)) != 178055601ddbSmarks ACE_FILE_INHERIT_ACE) { 1781da6c28aaSamw aclnode2 = zfs_acl_node_alloc(ace_size); 1782b3d141f8Smarks list_insert_tail(&aclp->z_acl, aclnode2); 1783da6c28aaSamw acep2 = aclnode2->z_acldata; 1784da6c28aaSamw zfs_set_ace(aclp, acep2, 1785da6c28aaSamw access_mask, type, who, 1786da6c28aaSamw iflags|ACE_INHERITED_ACE); 1787da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1788b3d141f8Smarks aclp->z_ops.ace_flags_set(acep, newflags); 1789da6c28aaSamw newflags &= ~ALL_INHERIT; 1790da6c28aaSamw aclp->z_ops.ace_flags_set(acep2, 1791da6c28aaSamw newflags|ACE_INHERITED_ACE); 1792fa9e4066Sahrens 1793da6c28aaSamw /* 1794da6c28aaSamw * Copy special opaque data if any 1795da6c28aaSamw */ 1796b3d141f8Smarks if ((data1sz = aclp->z_ops.ace_data(acep, 1797da6c28aaSamw &data1)) != 0) { 1798da6c28aaSamw VERIFY((data2sz = 1799da6c28aaSamw aclp->z_ops.ace_data(acep2, 1800da6c28aaSamw &data2)) == data1sz); 1801da6c28aaSamw bcopy(data1, data2, data1sz); 1802da6c28aaSamw } 1803da6c28aaSamw aclp->z_acl_count++; 1804da6c28aaSamw aclnode2->z_ace_count++; 1805da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1806b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep2); 1807da6c28aaSamw } else { 1808da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1809da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1810da6c28aaSamw newflags|ACE_INHERITED_ACE); 1811da6c28aaSamw } 1812da6c28aaSamw } 1813fa9e4066Sahrens return (aclp); 1814fa9e4066Sahrens } 1815fa9e4066Sahrens 1816fa9e4066Sahrens /* 1817fa9e4066Sahrens * Create file system object initial permissions 1818fa9e4066Sahrens * including inheritable ACEs. 1819fa9e4066Sahrens */ 182089459e17SMark Shellenbaum int 182189459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 182289459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1823fa9e4066Sahrens { 1824fa9e4066Sahrens int error; 182589459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1826da6c28aaSamw zfs_acl_t *paclp; 1827e0d35c44Smarks gid_t gid; 1828b3d141f8Smarks boolean_t need_chmod = B_TRUE; 1829da6c28aaSamw 183089459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 183189459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1832fa9e4066Sahrens 183389459e17SMark Shellenbaum if (vsecp) 183489459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 183589459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 183689459e17SMark Shellenbaum return (error); 1837fa9e4066Sahrens 1838fa9e4066Sahrens /* 1839fa9e4066Sahrens * Determine uid and gid. 1840fa9e4066Sahrens */ 1841fa9e4066Sahrens if ((flag & (IS_ROOT_NODE | IS_REPLAY)) || 1842fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 184389459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 184489459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 184589459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 184689459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 184789459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 184889459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1849e0d35c44Smarks gid = vap->va_gid; 1850fa9e4066Sahrens } else { 185189459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 185289459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 185389459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1854e0d35c44Smarks if (vap->va_mask & AT_GID) { 185589459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 185689459e17SMark Shellenbaum (uint64_t)vap->va_gid, 185789459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1858e0d35c44Smarks gid = vap->va_gid; 185989459e17SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_phys->zp_gid && 1860e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1861e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 186289459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1863e0d35c44Smarks } 186489459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 186589459e17SMark Shellenbaum if (dzp->z_phys->zp_mode & S_ISGID) { 186689459e17SMark Shellenbaum acl_ids->z_fgid = dzp->z_phys->zp_gid; 186789459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1868e0d35c44Smarks cr, ZFS_GROUP); 1869da6c28aaSamw } else { 187089459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 187189459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1872e0d35c44Smarks gid = crgetgid(cr); 1873e0d35c44Smarks } 1874da6c28aaSamw } 1875fa9e4066Sahrens } 1876fa9e4066Sahrens 1877fa9e4066Sahrens /* 1878fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1879fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1880fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1881fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1882fa9e4066Sahrens */ 1883fa9e4066Sahrens 188489459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_phys->zp_mode & S_ISGID) && 188589459e17SMark Shellenbaum (vap->va_type == VDIR)) { 188689459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1887e0d35c44Smarks } else { 188889459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1889fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 189089459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1891fa9e4066Sahrens } 1892fa9e4066Sahrens 189389459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 189489459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 189589459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && 189689459e17SMark Shellenbaum (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)) && 189789459e17SMark Shellenbaum !(dzp->z_phys->zp_flags & ZFS_XATTR)) { 189889459e17SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 189989459e17SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE)); 190089459e17SMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 190189459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 190289459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 1903fa9e4066Sahrens } else { 190489459e17SMark Shellenbaum acl_ids->z_aclp = 190589459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 1906fa9e4066Sahrens } 190789459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 190889459e17SMark Shellenbaum if (need_chmod) { 190989459e17SMark Shellenbaum acl_ids->z_aclp->z_hints = (vap->va_type == VDIR) ? 191089459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 191189459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs, acl_ids->z_fuid, 191289459e17SMark Shellenbaum acl_ids->z_mode, acl_ids->z_aclp); 191389459e17SMark Shellenbaum } 1914da6c28aaSamw } 1915da6c28aaSamw 191689459e17SMark Shellenbaum return (0); 1917fa9e4066Sahrens } 1918fa9e4066Sahrens 1919fa9e4066Sahrens /* 192089459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 192189459e17SMark Shellenbaum */ 192289459e17SMark Shellenbaum void 192389459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 192489459e17SMark Shellenbaum { 192589459e17SMark Shellenbaum if (acl_ids->z_aclp) 192689459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 192789459e17SMark Shellenbaum if (acl_ids->z_fuidp) 192889459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 192989459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 193089459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 193189459e17SMark Shellenbaum } 193289459e17SMark Shellenbaum 193314843421SMatthew Ahrens boolean_t 193414843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 193514843421SMatthew Ahrens { 193614843421SMatthew Ahrens return (zfs_usergroup_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 193714843421SMatthew Ahrens zfs_usergroup_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 193814843421SMatthew Ahrens } 193989459e17SMark Shellenbaum 194089459e17SMark Shellenbaum /* 1941fa9e4066Sahrens * Retrieve a files ACL 1942fa9e4066Sahrens */ 1943fa9e4066Sahrens int 1944da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1945fa9e4066Sahrens { 1946fa9e4066Sahrens zfs_acl_t *aclp; 1947da6c28aaSamw ulong_t mask; 1948fa9e4066Sahrens int error; 1949da6c28aaSamw int count = 0; 1950da6c28aaSamw int largeace = 0; 1951fa9e4066Sahrens 1952da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1953da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1954da6c28aaSamw 1955da6c28aaSamw if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 1956fa9e4066Sahrens return (error); 1957fa9e4066Sahrens 1958fa9e4066Sahrens if (mask == 0) 1959fa9e4066Sahrens return (ENOSYS); 1960fa9e4066Sahrens 1961fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1962fa9e4066Sahrens 1963da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 1964ea8dc4b6Seschrock if (error != 0) { 1965ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1966ea8dc4b6Seschrock return (error); 1967ea8dc4b6Seschrock } 1968ea8dc4b6Seschrock 1969da6c28aaSamw /* 1970da6c28aaSamw * Scan ACL to determine number of ACEs 1971da6c28aaSamw */ 1972da6c28aaSamw if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) && 1973da6c28aaSamw !(mask & VSA_ACE_ALLTYPES)) { 1974da6c28aaSamw void *zacep = NULL; 1975da6c28aaSamw uint64_t who; 1976da6c28aaSamw uint32_t access_mask; 1977da6c28aaSamw uint16_t type, iflags; 1978da6c28aaSamw 1979da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1980da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1981da6c28aaSamw switch (type) { 1982da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1983da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1984da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1985da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1986da6c28aaSamw largeace++; 1987da6c28aaSamw continue; 1988da6c28aaSamw default: 1989da6c28aaSamw count++; 1990da6c28aaSamw } 1991da6c28aaSamw } 1992da6c28aaSamw vsecp->vsa_aclcnt = count; 1993da6c28aaSamw } else 1994da6c28aaSamw count = aclp->z_acl_count; 1995fa9e4066Sahrens 1996fa9e4066Sahrens if (mask & VSA_ACECNT) { 1997da6c28aaSamw vsecp->vsa_aclcnt = count; 1998fa9e4066Sahrens } 1999fa9e4066Sahrens 2000fa9e4066Sahrens if (mask & VSA_ACE) { 2001da6c28aaSamw size_t aclsz; 2002da6c28aaSamw 2003da6c28aaSamw zfs_acl_node_t *aclnode = list_head(&aclp->z_acl); 2004da6c28aaSamw 2005da6c28aaSamw aclsz = count * sizeof (ace_t) + 2006da6c28aaSamw sizeof (ace_object_t) * largeace; 2007da6c28aaSamw 2008da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 2009da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 2010da6c28aaSamw 2011da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 2012bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 2013da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 2014da6c28aaSamw else { 2015da6c28aaSamw bcopy(aclnode->z_acldata, vsecp->vsa_aclentp, 2016da6c28aaSamw count * sizeof (ace_t)); 2017da6c28aaSamw } 2018da6c28aaSamw } 2019da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 2020da6c28aaSamw vsecp->vsa_aclflags = 0; 2021da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED) 2022da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 2023da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED) 2024da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 2025da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT) 2026da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 2027fa9e4066Sahrens } 2028fa9e4066Sahrens 2029fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2030fa9e4066Sahrens 2031fa9e4066Sahrens return (0); 2032fa9e4066Sahrens } 2033fa9e4066Sahrens 2034da6c28aaSamw int 2035da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 203689459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 2037da6c28aaSamw { 2038da6c28aaSamw zfs_acl_t *aclp; 2039da6c28aaSamw zfs_acl_node_t *aclnode; 2040da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 2041da6c28aaSamw int error; 2042da6c28aaSamw 2043da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 2044da6c28aaSamw return (EINVAL); 2045da6c28aaSamw 2046da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 2047da6c28aaSamw 2048da6c28aaSamw aclp->z_hints = 0; 2049da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 2050da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 2051da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 2052da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 2053da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 2054da6c28aaSamw zfs_acl_free(aclp); 2055da6c28aaSamw zfs_acl_node_free(aclnode); 2056da6c28aaSamw return (error); 2057da6c28aaSamw } 2058da6c28aaSamw } else { 205989459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 2060da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 206189459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 2062da6c28aaSamw zfs_acl_free(aclp); 2063da6c28aaSamw zfs_acl_node_free(aclnode); 2064da6c28aaSamw return (error); 2065da6c28aaSamw } 2066da6c28aaSamw } 2067da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 2068da6c28aaSamw aclnode->z_ace_count = aclcnt; 2069da6c28aaSamw aclp->z_acl_count = aclcnt; 2070da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 2071da6c28aaSamw 2072da6c28aaSamw /* 2073da6c28aaSamw * If flags are being set then add them to z_hints 2074da6c28aaSamw */ 2075da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 2076da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 2077da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 2078da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 2079da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 2080da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 2081da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 2082da6c28aaSamw } 2083da6c28aaSamw 2084da6c28aaSamw *zaclp = aclp; 2085da6c28aaSamw 2086da6c28aaSamw return (0); 2087da6c28aaSamw } 2088da6c28aaSamw 2089fa9e4066Sahrens /* 2090fa9e4066Sahrens * Set a files ACL 2091fa9e4066Sahrens */ 2092fa9e4066Sahrens int 2093da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 2094fa9e4066Sahrens { 2095fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2096fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 2097fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 2098fa9e4066Sahrens dmu_tx_t *tx; 2099fa9e4066Sahrens int error; 2100fa9e4066Sahrens zfs_acl_t *aclp; 2101da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 210289459e17SMark Shellenbaum boolean_t fuid_dirtied; 2103fa9e4066Sahrens 2104fa9e4066Sahrens if (mask == 0) 21057106075aSmarks return (ENOSYS); 2106fa9e4066Sahrens 2107da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_IMMUTABLE) 2108da6c28aaSamw return (EPERM); 2109da6c28aaSamw 2110da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 2111fa9e4066Sahrens return (error); 2112da6c28aaSamw 211389459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 211489459e17SMark Shellenbaum &aclp); 2115da6c28aaSamw if (error) 2116da6c28aaSamw return (error); 2117da6c28aaSamw 2118da6c28aaSamw /* 2119da6c28aaSamw * If ACL wide flags aren't being set then preserve any 2120da6c28aaSamw * existing flags. 2121da6c28aaSamw */ 2122da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 2123da6c28aaSamw aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS); 2124fa9e4066Sahrens } 2125da6c28aaSamw top: 2126fa9e4066Sahrens mutex_enter(&zp->z_lock); 2127fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2128fa9e4066Sahrens 2129fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 2130fa9e4066Sahrens dmu_tx_hold_bonus(tx, zp->z_id); 2131fa9e4066Sahrens 2132fa9e4066Sahrens if (zp->z_phys->zp_acl.z_acl_extern_obj) { 2133da6c28aaSamw /* Are we upgrading ACL? */ 2134da6c28aaSamw if (zfsvfs->z_version <= ZPL_VERSION_FUID && 2135da6c28aaSamw zp->z_phys->zp_acl.z_acl_version == 2136da6c28aaSamw ZFS_ACL_VERSION_INITIAL) { 2137da6c28aaSamw dmu_tx_hold_free(tx, 2138da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, 2139da6c28aaSamw 0, DMU_OBJECT_END); 2140da6c28aaSamw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 21414c841f60Smarks 0, aclp->z_acl_bytes); 2142da6c28aaSamw } else { 2143da6c28aaSamw dmu_tx_hold_write(tx, 2144da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, 2145da6c28aaSamw 0, aclp->z_acl_bytes); 2146da6c28aaSamw } 2147da6c28aaSamw } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 2148da6c28aaSamw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 2149da6c28aaSamw } 215089459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 215114843421SMatthew Ahrens if (fuid_dirtied) 215214843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 2153fa9e4066Sahrens 21541209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 2155fa9e4066Sahrens if (error) { 2156fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2157fa9e4066Sahrens mutex_exit(&zp->z_lock); 2158fa9e4066Sahrens 21591209a471SNeil Perrin if (error == ERESTART) { 21608a2f1b91Sahrens dmu_tx_wait(tx); 21618a2f1b91Sahrens dmu_tx_abort(tx); 2162fa9e4066Sahrens goto top; 2163fa9e4066Sahrens } 21648a2f1b91Sahrens dmu_tx_abort(tx); 2165da6c28aaSamw zfs_acl_free(aclp); 2166fa9e4066Sahrens return (error); 2167fa9e4066Sahrens } 2168fa9e4066Sahrens 216989459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2170fa9e4066Sahrens ASSERT(error == 0); 2171fa9e4066Sahrens 217289459e17SMark Shellenbaum if (fuid_dirtied) 217389459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 217489459e17SMark Shellenbaum 217589459e17SMark Shellenbaum zfs_time_stamper_locked(zp, STATE_CHANGED, tx); 2176da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2177da6c28aaSamw 2178da6c28aaSamw if (fuidp) 2179da6c28aaSamw zfs_fuid_info_free(fuidp); 2180*d47621a4STim Haley zp->z_acl_cached = aclp; 2181fa9e4066Sahrens dmu_tx_commit(tx); 2182fa9e4066Sahrens done: 2183fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2184fa9e4066Sahrens mutex_exit(&zp->z_lock); 2185fa9e4066Sahrens 2186fa9e4066Sahrens return (error); 2187fa9e4066Sahrens } 2188fa9e4066Sahrens 2189fa9e4066Sahrens /* 2190e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2191e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2192e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2193fa9e4066Sahrens */ 2194fa9e4066Sahrens static int 2195e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2196fa9e4066Sahrens { 2197fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2198fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2199f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2200f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2201fa9e4066Sahrens return (EROFS); 2202fa9e4066Sahrens } 2203fa9e4066Sahrens 2204da6c28aaSamw /* 2205da6c28aaSamw * Only check for READONLY on non-directories. 2206da6c28aaSamw */ 2207da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2208da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 2209da6c28aaSamw (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2210da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 2211da6c28aaSamw (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) { 2212da6c28aaSamw return (EPERM); 2213da6c28aaSamw } 2214da6c28aaSamw 2215da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 2216da6c28aaSamw (zp->z_phys->zp_flags & ZFS_NOUNLINK)) { 2217da6c28aaSamw return (EPERM); 2218da6c28aaSamw } 2219da6c28aaSamw 2220da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 2221da6c28aaSamw (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) { 2222da6c28aaSamw return (EACCES); 2223da6c28aaSamw } 2224da6c28aaSamw 2225da6c28aaSamw return (0); 2226da6c28aaSamw } 2227da6c28aaSamw 2228e802abbdSTim Haley /* 2229e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2230e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2231e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2232e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2233e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2234e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2235e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2236e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2237e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2238e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2239e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2240e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2241e802abbdSTim Haley * accesses. Returns: 2242e802abbdSTim Haley * 0 if all AoI granted 2243e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2244e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2245e802abbdSTim Haley * 2246e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2247e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2248e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2249e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2250e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2251e802abbdSTim Haley * is used in this manner. 2252e802abbdSTim Haley */ 2253e802abbdSTim Haley static int 2254e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2255e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2256e802abbdSTim Haley { 2257e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2258e802abbdSTim Haley zfs_acl_t *aclp; 2259e802abbdSTim Haley int error; 2260e802abbdSTim Haley uid_t uid = crgetuid(cr); 2261e802abbdSTim Haley uint64_t who; 2262e802abbdSTim Haley uint16_t type, iflags; 2263e802abbdSTim Haley uint16_t entry_type; 2264e802abbdSTim Haley uint32_t access_mask; 2265e802abbdSTim Haley uint32_t deny_mask = 0; 2266e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2267e802abbdSTim Haley boolean_t checkit; 2268e802abbdSTim Haley uid_t fowner; 2269e802abbdSTim Haley uid_t gowner; 2270e802abbdSTim Haley 2271bda89588Sjp151216 zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 2272da6c28aaSamw 2273fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2274fa9e4066Sahrens 2275da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 2276ea8dc4b6Seschrock if (error != 0) { 2277ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2278ea8dc4b6Seschrock return (error); 2279ea8dc4b6Seschrock } 2280ea8dc4b6Seschrock 2281da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2282da6c28aaSamw &iflags, &type)) { 2283e802abbdSTim Haley uint32_t mask_matched; 2284fa9e4066Sahrens 2285003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2286003c2582SMark Shellenbaum continue; 2287003c2582SMark Shellenbaum 2288b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2289fa9e4066Sahrens continue; 2290fa9e4066Sahrens 2291e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2292e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2293e802abbdSTim Haley if (!mask_matched) 2294e802abbdSTim Haley continue; 2295e802abbdSTim Haley 2296da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2297da6c28aaSamw 2298da6c28aaSamw checkit = B_FALSE; 2299da6c28aaSamw 2300fa9e4066Sahrens switch (entry_type) { 2301fa9e4066Sahrens case ACE_OWNER: 2302da6c28aaSamw if (uid == fowner) 2303da6c28aaSamw checkit = B_TRUE; 2304fa9e4066Sahrens break; 2305da6c28aaSamw case OWNING_GROUP: 2306da6c28aaSamw who = gowner; 2307da6c28aaSamw /*FALLTHROUGH*/ 2308fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2309da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2310fa9e4066Sahrens break; 2311fa9e4066Sahrens case ACE_EVERYONE: 2312da6c28aaSamw checkit = B_TRUE; 2313fa9e4066Sahrens break; 2314fa9e4066Sahrens 2315fa9e4066Sahrens /* USER Entry */ 2316fa9e4066Sahrens default: 2317fa9e4066Sahrens if (entry_type == 0) { 2318da6c28aaSamw uid_t newid; 2319da6c28aaSamw 2320e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2321e0d35c44Smarks ZFS_ACE_USER); 2322da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2323da6c28aaSamw uid == newid) 2324da6c28aaSamw checkit = B_TRUE; 2325fa9e4066Sahrens break; 2326da6c28aaSamw } else { 2327fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2328fa9e4066Sahrens return (EIO); 2329fa9e4066Sahrens } 2330da6c28aaSamw } 2331da6c28aaSamw 2332da6c28aaSamw if (checkit) { 2333e802abbdSTim Haley if (type == DENY) { 2334e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2335e802abbdSTim Haley znode_t *, zp, 2336e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2337e802abbdSTim Haley uint32_t, mask_matched); 233890fafcf0Smarks deny_mask |= mask_matched; 2339e802abbdSTim Haley } else { 2340e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2341e802abbdSTim Haley znode_t *, zp, 2342e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2343e802abbdSTim Haley uint32_t, mask_matched); 2344e802abbdSTim Haley if (anyaccess) { 2345e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2346e802abbdSTim Haley zfs_acl_free(aclp); 2347e802abbdSTim Haley return (0); 2348da6c28aaSamw } 2349da6c28aaSamw } 2350e802abbdSTim Haley *working_mode &= ~mask_matched; 2351e802abbdSTim Haley } 2352fa9e4066Sahrens 235390fafcf0Smarks /* Are we done? */ 235490fafcf0Smarks if (*working_mode == 0) 2355fa9e4066Sahrens break; 2356fa9e4066Sahrens } 2357fa9e4066Sahrens 2358fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 235990fafcf0Smarks 236090fafcf0Smarks /* Put the found 'denies' back on the working mode */ 23617ed7e920Smarks if (deny_mask) { 236290fafcf0Smarks *working_mode |= deny_mask; 236390fafcf0Smarks return (EACCES); 23647ed7e920Smarks } else if (*working_mode) { 23657ed7e920Smarks return (-1); 23667ed7e920Smarks } 236790fafcf0Smarks 236890fafcf0Smarks return (0); 2369fa9e4066Sahrens } 2370fa9e4066Sahrens 2371e802abbdSTim Haley /* 2372e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2373e802abbdSTim Haley * care what access is granted. 2374e802abbdSTim Haley */ 2375e802abbdSTim Haley boolean_t 2376e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2377e802abbdSTim Haley { 2378e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2379e802abbdSTim Haley 2380e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2381e802abbdSTim Haley uid_t owner; 2382e802abbdSTim Haley 2383e802abbdSTim Haley owner = zfs_fuid_map_id(zp->z_zfsvfs, 2384e802abbdSTim Haley zp->z_phys->zp_uid, cr, ZFS_OWNER); 2385e802abbdSTim Haley 2386e802abbdSTim Haley return ( 2387e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VREAD) == 0 || 2388e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VWRITE) == 0 || 2389e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VEXEC) == 0 || 2390e02bc683SMark Shellenbaum secpolicy_vnode_chown(cr, owner) == 0 || 2391e802abbdSTim Haley secpolicy_vnode_setdac(cr, owner) == 0 || 2392e802abbdSTim Haley secpolicy_vnode_remove(cr) == 0); 2393e802abbdSTim Haley } 2394e802abbdSTim Haley return (B_TRUE); 2395e802abbdSTim Haley } 2396e802abbdSTim Haley 2397e802abbdSTim Haley static int 2398e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2399e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2400e802abbdSTim Haley { 2401e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2402e802abbdSTim Haley int err; 2403e802abbdSTim Haley 2404e802abbdSTim Haley *working_mode = v4_mode; 2405e802abbdSTim Haley *check_privs = B_TRUE; 2406e802abbdSTim Haley 2407e802abbdSTim Haley /* 2408e802abbdSTim Haley * Short circuit empty requests 2409e802abbdSTim Haley */ 2410e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2411e802abbdSTim Haley *working_mode = 0; 2412e802abbdSTim Haley return (0); 2413e802abbdSTim Haley } 2414e802abbdSTim Haley 2415e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2416e802abbdSTim Haley *check_privs = B_FALSE; 2417e802abbdSTim Haley return (err); 2418e802abbdSTim Haley } 2419e802abbdSTim Haley 2420e802abbdSTim Haley /* 2421e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2422e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2423e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2424e802abbdSTim Haley */ 2425e802abbdSTim Haley if (skipaclchk) { 2426e802abbdSTim Haley *working_mode = 0; 2427e802abbdSTim Haley return (0); 2428e802abbdSTim Haley } 2429e802abbdSTim Haley 2430e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2431e802abbdSTim Haley } 2432e802abbdSTim Haley 2433da6c28aaSamw static int 2434da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2435da6c28aaSamw cred_t *cr) 2436da6c28aaSamw { 2437da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2438da6c28aaSamw return (EACCES); 2439da6c28aaSamw 2440da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2441da6c28aaSamw check_privs, B_FALSE, cr)); 2442da6c28aaSamw } 2443fa9e4066Sahrens 2444*d47621a4STim Haley int 2445*d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2446*d47621a4STim Haley { 2447*d47621a4STim Haley boolean_t owner = B_FALSE; 2448*d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2449*d47621a4STim Haley boolean_t is_attr; 2450*d47621a4STim Haley uid_t fowner; 2451*d47621a4STim Haley uid_t gowner; 2452*d47621a4STim Haley uid_t uid = crgetuid(cr); 2453*d47621a4STim Haley int error; 2454*d47621a4STim Haley 2455*d47621a4STim Haley if (zdp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 2456*d47621a4STim Haley return (EACCES); 2457*d47621a4STim Haley 2458*d47621a4STim Haley is_attr = ((zdp->z_phys->zp_flags & ZFS_XATTR) && 2459*d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2460*d47621a4STim Haley if (is_attr) 2461*d47621a4STim Haley goto slow; 2462*d47621a4STim Haley 2463*d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2464*d47621a4STim Haley 2465*d47621a4STim Haley if (zdp->z_phys->zp_flags & ZFS_NO_EXECS_DENIED) { 2466*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2467*d47621a4STim Haley return (0); 2468*d47621a4STim Haley } 2469*d47621a4STim Haley 2470*d47621a4STim Haley if (FUID_INDEX(zdp->z_phys->zp_uid) != 0 || 2471*d47621a4STim Haley FUID_INDEX(zdp->z_phys->zp_gid) != 0) { 2472*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2473*d47621a4STim Haley goto slow; 2474*d47621a4STim Haley } 2475*d47621a4STim Haley 2476*d47621a4STim Haley fowner = (uid_t)zdp->z_phys->zp_uid; 2477*d47621a4STim Haley gowner = (uid_t)zdp->z_phys->zp_gid; 2478*d47621a4STim Haley 2479*d47621a4STim Haley if (uid == fowner) { 2480*d47621a4STim Haley owner = B_TRUE; 2481*d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXUSR) { 2482*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2483*d47621a4STim Haley return (0); 2484*d47621a4STim Haley } 2485*d47621a4STim Haley } 2486*d47621a4STim Haley if (groupmember(gowner, cr)) { 2487*d47621a4STim Haley groupmbr = B_TRUE; 2488*d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXGRP) { 2489*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2490*d47621a4STim Haley return (0); 2491*d47621a4STim Haley } 2492*d47621a4STim Haley } 2493*d47621a4STim Haley if (!owner && !groupmbr) { 2494*d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXOTH) { 2495*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2496*d47621a4STim Haley return (0); 2497*d47621a4STim Haley } 2498*d47621a4STim Haley } 2499*d47621a4STim Haley 2500*d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2501*d47621a4STim Haley 2502*d47621a4STim Haley slow: 2503*d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2504*d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2505*d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2506*d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2507*d47621a4STim Haley return (error); 2508*d47621a4STim Haley } 2509*d47621a4STim Haley 2510fa9e4066Sahrens /* 2511fa9e4066Sahrens * Determine whether Access should be granted/denied, invoking least 2512fa9e4066Sahrens * priv subsytem when a deny is determined. 2513fa9e4066Sahrens */ 2514fa9e4066Sahrens int 2515da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2516fa9e4066Sahrens { 2517da6c28aaSamw uint32_t working_mode; 2518fa9e4066Sahrens int error; 2519fa9e4066Sahrens int is_attr; 2520da6c28aaSamw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2521da6c28aaSamw boolean_t check_privs; 2522fa9e4066Sahrens znode_t *xzp; 2523fa9e4066Sahrens znode_t *check_zp = zp; 2524fa9e4066Sahrens 2525fa9e4066Sahrens is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) && 2526fa9e4066Sahrens (ZTOV(zp)->v_type == VDIR)); 2527fa9e4066Sahrens 2528fa9e4066Sahrens /* 2529fa9e4066Sahrens * If attribute then validate against base file 2530fa9e4066Sahrens */ 2531fa9e4066Sahrens if (is_attr) { 2532fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 2533fa9e4066Sahrens zp->z_phys->zp_parent, &xzp)) != 0) { 2534fa9e4066Sahrens return (error); 2535fa9e4066Sahrens } 2536da6c28aaSamw 2537fa9e4066Sahrens check_zp = xzp; 2538da6c28aaSamw 2539fa9e4066Sahrens /* 2540fa9e4066Sahrens * fixup mode to map to xattr perms 2541fa9e4066Sahrens */ 2542fa9e4066Sahrens 2543fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2544fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2545fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2546fa9e4066Sahrens } 2547fa9e4066Sahrens 2548fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2549fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2550fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2551fa9e4066Sahrens } 2552fa9e4066Sahrens } 2553fa9e4066Sahrens 2554da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2555da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2556da6c28aaSamw if (is_attr) 2557da6c28aaSamw VN_RELE(ZTOV(xzp)); 2558da6c28aaSamw return (0); 2559da6c28aaSamw } 2560fa9e4066Sahrens 2561e0d35c44Smarks if (error && !check_privs) { 2562fa9e4066Sahrens if (is_attr) 2563fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2564fa9e4066Sahrens return (error); 2565fa9e4066Sahrens } 2566fa9e4066Sahrens 2567da6c28aaSamw if (error && (flags & V_APPEND)) { 2568da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2569fa9e4066Sahrens } 2570fa9e4066Sahrens 2571da6c28aaSamw if (error && check_privs) { 2572da6c28aaSamw uid_t owner; 2573da6c28aaSamw mode_t checkmode = 0; 2574fa9e4066Sahrens 2575e0d35c44Smarks owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr, 2576e0d35c44Smarks ZFS_OWNER); 2577fa9e4066Sahrens 2578fa9e4066Sahrens /* 2579da6c28aaSamw * First check for implicit owner permission on 2580da6c28aaSamw * read_acl/read_attributes 2581fa9e4066Sahrens */ 2582fa9e4066Sahrens 2583da6c28aaSamw error = 0; 2584da6c28aaSamw ASSERT(working_mode != 0); 2585da6c28aaSamw 2586da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2587da6c28aaSamw owner == crgetuid(cr))) 2588da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2589da6c28aaSamw 2590da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 259147def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2592da6c28aaSamw checkmode |= VREAD; 2593da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 259447def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2595da6c28aaSamw checkmode |= VWRITE; 2596da6c28aaSamw if (working_mode & ACE_EXECUTE) 2597da6c28aaSamw checkmode |= VEXEC; 2598da6c28aaSamw 2599da6c28aaSamw if (checkmode) 2600da6c28aaSamw error = secpolicy_vnode_access(cr, ZTOV(check_zp), 2601da6c28aaSamw owner, checkmode); 2602da6c28aaSamw 2603da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2604e02bc683SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 2605da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2606da6c28aaSamw error = secpolicy_vnode_setdac(cr, owner); 2607da6c28aaSamw 2608da6c28aaSamw if (error == 0 && (working_mode & 2609da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2610da6c28aaSamw error = secpolicy_vnode_remove(cr); 2611da6c28aaSamw 261247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2613e02bc683SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 261447def0dcSMark Shellenbaum } 2615da6c28aaSamw if (error == 0) { 2616da6c28aaSamw /* 2617da6c28aaSamw * See if any bits other than those already checked 2618da6c28aaSamw * for are still present. If so then return EACCES 2619da6c28aaSamw */ 2620da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2621da6c28aaSamw error = EACCES; 2622da6c28aaSamw } 2623da6c28aaSamw } 2624da6c28aaSamw } 2625da6c28aaSamw 2626da6c28aaSamw if (is_attr) 2627da6c28aaSamw VN_RELE(ZTOV(xzp)); 2628da6c28aaSamw 2629da6c28aaSamw return (error); 2630fa9e4066Sahrens } 2631fa9e4066Sahrens 2632fa9e4066Sahrens /* 2633da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2634fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2635fa9e4066Sahrens */ 2636fa9e4066Sahrens int 2637da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2638da6c28aaSamw { 2639da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2640da6c28aaSamw } 2641da6c28aaSamw 2642da6c28aaSamw /* 2643da6c28aaSamw * Access function for secpolicy_vnode_setattr 2644da6c28aaSamw */ 2645da6c28aaSamw int 2646da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2647fa9e4066Sahrens { 2648fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2649fa9e4066Sahrens 2650da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2651fa9e4066Sahrens } 2652fa9e4066Sahrens 265347db7e74Smarks static int 265423d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 265523d5bb1fSmarks mode_t missing_perms, cred_t *cr) 265647db7e74Smarks { 265747db7e74Smarks int error; 2658da6c28aaSamw uid_t downer; 2659da6c28aaSamw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 266047db7e74Smarks 2661e0d35c44Smarks downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER); 2662da6c28aaSamw 266323d5bb1fSmarks error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms); 266447db7e74Smarks 266547db7e74Smarks if (error == 0) 266647db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 266747db7e74Smarks 266847db7e74Smarks return (error); 266947db7e74Smarks } 267047db7e74Smarks 2671fa9e4066Sahrens /* 2672fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2673fa9e4066Sahrens * consulting least priv subsystem. 2674fa9e4066Sahrens * 2675fa9e4066Sahrens * 2676fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2677fa9e4066Sahrens * ability to delete an object. 2678fa9e4066Sahrens * 2679fa9e4066Sahrens * ------------------------------------------------------- 2680fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2681fa9e4066Sahrens * | permissions | | 2682fa9e4066Sahrens * ------------------------------------------------------- 2683fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2684fa9e4066Sahrens * | | Delete | Delete | unspecified| 2685fa9e4066Sahrens * ------------------------------------------------------- 2686fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2687fa9e4066Sahrens * | DELETE_CHILD | | 2688fa9e4066Sahrens * ------------------------------------------------------- 2689fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2690fa9e4066Sahrens * | DELETE_CHILD | | | | 2691fa9e4066Sahrens * ------------------------------------------------------- 2692fa9e4066Sahrens * | ACL specifies | | | | 2693fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2694fa9e4066Sahrens * | write and | | | | 2695fa9e4066Sahrens * | execute | | | | 2696fa9e4066Sahrens * ------------------------------------------------------- 2697fa9e4066Sahrens * | ACL denies | | | | 2698fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2699fa9e4066Sahrens * | execute | | | | 2700fa9e4066Sahrens * ------------------------------------------------------- 2701fa9e4066Sahrens * ^ 2702fa9e4066Sahrens * | 2703fa9e4066Sahrens * No search privilege, can't even look up file? 2704fa9e4066Sahrens * 2705fa9e4066Sahrens */ 2706fa9e4066Sahrens int 2707fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2708fa9e4066Sahrens { 2709da6c28aaSamw uint32_t dzp_working_mode = 0; 2710da6c28aaSamw uint32_t zp_working_mode = 0; 2711fa9e4066Sahrens int dzp_error, zp_error; 271223d5bb1fSmarks mode_t missing_perms; 2713da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2714da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2715fa9e4066Sahrens 2716fa9e4066Sahrens /* 271723d5bb1fSmarks * We want specific DELETE permissions to 2718fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2719fa9e4066Sahrens * want an ACL such as this to mess us up. 272047db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2721fa9e4066Sahrens * 2722fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2723fa9e4066Sahrens * by secpolicy_vnode_access(). 272423d5bb1fSmarks * 272523d5bb1fSmarks * We will ask for all of the necessary permissions and then 272623d5bb1fSmarks * look at the working modes from the directory and target object 272723d5bb1fSmarks * to determine what was found. 2728fa9e4066Sahrens */ 2729fa9e4066Sahrens 2730da6c28aaSamw if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2731da6c28aaSamw return (EPERM); 2732fa9e4066Sahrens 273323d5bb1fSmarks /* 27347ed7e920Smarks * First row 273523d5bb1fSmarks * If the directory permissions allow the delete, we are done. 273623d5bb1fSmarks */ 27377ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 273823d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 273923d5bb1fSmarks return (0); 2740da6c28aaSamw 274123d5bb1fSmarks /* 274223d5bb1fSmarks * If target object has delete permission then we are done 274323d5bb1fSmarks */ 274423d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 274523d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 274623d5bb1fSmarks return (0); 274723d5bb1fSmarks 27487ed7e920Smarks ASSERT(dzp_error && zp_error); 27497ed7e920Smarks 275023d5bb1fSmarks if (!dzpcheck_privs) 2751fa9e4066Sahrens return (dzp_error); 27527ed7e920Smarks if (!zpcheck_privs) 275323d5bb1fSmarks return (zp_error); 2754fa9e4066Sahrens 2755fa9e4066Sahrens /* 2756fa9e4066Sahrens * Second row 27577ed7e920Smarks * 27587ed7e920Smarks * If directory returns EACCES then delete_child was denied 27597ed7e920Smarks * due to deny delete_child. In this case send the request through 27607ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 27617ed7e920Smarks * since that *could* allow the delete based on write/execute permission 27627ed7e920Smarks * and we want delete permissions to override write/execute. 2763fa9e4066Sahrens */ 2764fa9e4066Sahrens 276547db7e74Smarks if (dzp_error == EACCES) 27667ed7e920Smarks return (secpolicy_vnode_remove(cr)); 276747db7e74Smarks 276847db7e74Smarks /* 2769fa9e4066Sahrens * Third Row 277023d5bb1fSmarks * only need to see if we have write/execute on directory. 2771fa9e4066Sahrens */ 2772fa9e4066Sahrens 27737ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 27747ed7e920Smarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 277547db7e74Smarks return (zfs_sticky_remove_access(dzp, zp, cr)); 2776fa9e4066Sahrens 27777ed7e920Smarks if (!dzpcheck_privs) 27787ed7e920Smarks return (dzp_error); 27797ed7e920Smarks 2780fa9e4066Sahrens /* 27817ed7e920Smarks * Fourth row 2782fa9e4066Sahrens */ 2783fa9e4066Sahrens 27847ed7e920Smarks missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0; 27857ed7e920Smarks missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0; 27867ed7e920Smarks 27877ed7e920Smarks ASSERT(missing_perms); 2788fa9e4066Sahrens 278923d5bb1fSmarks return (zfs_delete_final_check(zp, dzp, missing_perms, cr)); 27907ed7e920Smarks 2791fa9e4066Sahrens } 2792fa9e4066Sahrens 2793fa9e4066Sahrens int 2794fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2795fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2796fa9e4066Sahrens { 2797fa9e4066Sahrens int add_perm; 2798fa9e4066Sahrens int error; 2799fa9e4066Sahrens 2800da6c28aaSamw if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 2801da6c28aaSamw return (EACCES); 2802da6c28aaSamw 2803fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2804fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2805fa9e4066Sahrens 2806fa9e4066Sahrens /* 2807fa9e4066Sahrens * Rename permissions are combination of delete permission + 2808fa9e4066Sahrens * add file/subdir permission. 2809fa9e4066Sahrens */ 2810fa9e4066Sahrens 2811fa9e4066Sahrens /* 2812fa9e4066Sahrens * first make sure we do the delete portion. 2813fa9e4066Sahrens * 2814fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2815fa9e4066Sahrens */ 2816fa9e4066Sahrens 2817fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2818fa9e4066Sahrens return (error); 2819fa9e4066Sahrens 2820fa9e4066Sahrens /* 2821fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2822fa9e4066Sahrens */ 2823fa9e4066Sahrens if (tzp) { 2824fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2825fa9e4066Sahrens return (error); 2826fa9e4066Sahrens } 2827fa9e4066Sahrens 2828fa9e4066Sahrens /* 2829fa9e4066Sahrens * Now check for add permissions 2830fa9e4066Sahrens */ 2831da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2832fa9e4066Sahrens 2833fa9e4066Sahrens return (error); 2834fa9e4066Sahrens } 2835