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) 92da6c28aaSamw 93da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 94da6c28aaSamw ZFS_ACL_OBJ_ACE) 95da6c28aaSamw 96*4929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) 97*4929fd5eSTim Haley 98da6c28aaSamw static uint16_t 99da6c28aaSamw zfs_ace_v0_get_type(void *acep) 100da6c28aaSamw { 101da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type); 102da6c28aaSamw } 103da6c28aaSamw 104da6c28aaSamw static uint16_t 105da6c28aaSamw zfs_ace_v0_get_flags(void *acep) 106da6c28aaSamw { 107da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags); 108da6c28aaSamw } 109fa9e4066Sahrens 110da6c28aaSamw static uint32_t 111da6c28aaSamw zfs_ace_v0_get_mask(void *acep) 112da6c28aaSamw { 113da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask); 114da6c28aaSamw } 115da6c28aaSamw 116da6c28aaSamw static uint64_t 117da6c28aaSamw zfs_ace_v0_get_who(void *acep) 118da6c28aaSamw { 119da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid); 120da6c28aaSamw } 121da6c28aaSamw 122da6c28aaSamw static void 123da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type) 124da6c28aaSamw { 125da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type; 126da6c28aaSamw } 127da6c28aaSamw 128da6c28aaSamw static void 129da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags) 130da6c28aaSamw { 131da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags; 132da6c28aaSamw } 133da6c28aaSamw 134da6c28aaSamw static void 135da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask) 136da6c28aaSamw { 137da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask; 138da6c28aaSamw } 139da6c28aaSamw 140da6c28aaSamw static void 141da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who) 142da6c28aaSamw { 143da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who; 144da6c28aaSamw } 145da6c28aaSamw 146da6c28aaSamw /*ARGSUSED*/ 147da6c28aaSamw static size_t 148da6c28aaSamw zfs_ace_v0_size(void *acep) 149da6c28aaSamw { 150da6c28aaSamw return (sizeof (zfs_oldace_t)); 151da6c28aaSamw } 152da6c28aaSamw 153da6c28aaSamw static size_t 154da6c28aaSamw zfs_ace_v0_abstract_size(void) 155da6c28aaSamw { 156da6c28aaSamw return (sizeof (zfs_oldace_t)); 157da6c28aaSamw } 158da6c28aaSamw 159da6c28aaSamw static int 160da6c28aaSamw zfs_ace_v0_mask_off(void) 161da6c28aaSamw { 162da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask)); 163da6c28aaSamw } 164da6c28aaSamw 165da6c28aaSamw /*ARGSUSED*/ 166da6c28aaSamw static int 167da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap) 168da6c28aaSamw { 169da6c28aaSamw *datap = NULL; 170da6c28aaSamw return (0); 171da6c28aaSamw } 172da6c28aaSamw 173da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = { 174da6c28aaSamw zfs_ace_v0_get_mask, 175da6c28aaSamw zfs_ace_v0_set_mask, 176da6c28aaSamw zfs_ace_v0_get_flags, 177da6c28aaSamw zfs_ace_v0_set_flags, 178da6c28aaSamw zfs_ace_v0_get_type, 179da6c28aaSamw zfs_ace_v0_set_type, 180da6c28aaSamw zfs_ace_v0_get_who, 181da6c28aaSamw zfs_ace_v0_set_who, 182da6c28aaSamw zfs_ace_v0_size, 183da6c28aaSamw zfs_ace_v0_abstract_size, 184da6c28aaSamw zfs_ace_v0_mask_off, 185da6c28aaSamw zfs_ace_v0_data 186da6c28aaSamw }; 187da6c28aaSamw 188da6c28aaSamw static uint16_t 189da6c28aaSamw zfs_ace_fuid_get_type(void *acep) 190da6c28aaSamw { 191da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type); 192da6c28aaSamw } 193da6c28aaSamw 194da6c28aaSamw static uint16_t 195da6c28aaSamw zfs_ace_fuid_get_flags(void *acep) 196da6c28aaSamw { 197da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags); 198da6c28aaSamw } 199da6c28aaSamw 200da6c28aaSamw static uint32_t 201da6c28aaSamw zfs_ace_fuid_get_mask(void *acep) 202da6c28aaSamw { 203da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask); 204da6c28aaSamw } 205da6c28aaSamw 206da6c28aaSamw static uint64_t 207da6c28aaSamw zfs_ace_fuid_get_who(void *args) 208da6c28aaSamw { 209da6c28aaSamw uint16_t entry_type; 210da6c28aaSamw zfs_ace_t *acep = args; 211da6c28aaSamw 212da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 213da6c28aaSamw 214da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 215da6c28aaSamw entry_type == ACE_EVERYONE) 216da6c28aaSamw return (-1); 217da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid); 218da6c28aaSamw } 219da6c28aaSamw 220da6c28aaSamw static void 221da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type) 222da6c28aaSamw { 223da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type; 224da6c28aaSamw } 225da6c28aaSamw 226da6c28aaSamw static void 227da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags) 228da6c28aaSamw { 229da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags; 230da6c28aaSamw } 231da6c28aaSamw 232da6c28aaSamw static void 233da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask) 234da6c28aaSamw { 235da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask; 236da6c28aaSamw } 237da6c28aaSamw 238da6c28aaSamw static void 239da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who) 240da6c28aaSamw { 241da6c28aaSamw zfs_ace_t *acep = arg; 242da6c28aaSamw 243da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 244da6c28aaSamw 245da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 246da6c28aaSamw entry_type == ACE_EVERYONE) 247da6c28aaSamw return; 248da6c28aaSamw acep->z_fuid = who; 249da6c28aaSamw } 250da6c28aaSamw 251da6c28aaSamw static size_t 252da6c28aaSamw zfs_ace_fuid_size(void *acep) 253da6c28aaSamw { 254da6c28aaSamw zfs_ace_hdr_t *zacep = acep; 255da6c28aaSamw uint16_t entry_type; 256da6c28aaSamw 257da6c28aaSamw switch (zacep->z_type) { 258da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 259da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 260da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 261da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 262da6c28aaSamw return (sizeof (zfs_object_ace_t)); 263da6c28aaSamw case ALLOW: 264da6c28aaSamw case DENY: 265da6c28aaSamw entry_type = 266da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS); 267da6c28aaSamw if (entry_type == ACE_OWNER || 2681ab99678SMark Shellenbaum entry_type == OWNING_GROUP || 269da6c28aaSamw entry_type == ACE_EVERYONE) 270da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 271da6c28aaSamw /*FALLTHROUGH*/ 272da6c28aaSamw default: 273da6c28aaSamw return (sizeof (zfs_ace_t)); 274da6c28aaSamw } 275da6c28aaSamw } 276da6c28aaSamw 277da6c28aaSamw static size_t 278da6c28aaSamw zfs_ace_fuid_abstract_size(void) 279da6c28aaSamw { 280da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 281da6c28aaSamw } 282da6c28aaSamw 283da6c28aaSamw static int 284da6c28aaSamw zfs_ace_fuid_mask_off(void) 285da6c28aaSamw { 286da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 287da6c28aaSamw } 288da6c28aaSamw 289da6c28aaSamw static int 290da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap) 291da6c28aaSamw { 292da6c28aaSamw zfs_ace_t *zacep = acep; 293da6c28aaSamw zfs_object_ace_t *zobjp; 294da6c28aaSamw 295da6c28aaSamw switch (zacep->z_hdr.z_type) { 296da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 297da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 298da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 299da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 300da6c28aaSamw zobjp = acep; 301da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t); 302da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t)); 303da6c28aaSamw default: 304da6c28aaSamw *datap = NULL; 305da6c28aaSamw return (0); 306da6c28aaSamw } 307da6c28aaSamw } 308da6c28aaSamw 309da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = { 310da6c28aaSamw zfs_ace_fuid_get_mask, 311da6c28aaSamw zfs_ace_fuid_set_mask, 312da6c28aaSamw zfs_ace_fuid_get_flags, 313da6c28aaSamw zfs_ace_fuid_set_flags, 314da6c28aaSamw zfs_ace_fuid_get_type, 315da6c28aaSamw zfs_ace_fuid_set_type, 316da6c28aaSamw zfs_ace_fuid_get_who, 317da6c28aaSamw zfs_ace_fuid_set_who, 318da6c28aaSamw zfs_ace_fuid_size, 319da6c28aaSamw zfs_ace_fuid_abstract_size, 320da6c28aaSamw zfs_ace_fuid_mask_off, 321da6c28aaSamw zfs_ace_fuid_data 322da6c28aaSamw }; 323da6c28aaSamw 324da6c28aaSamw static int 325da6c28aaSamw zfs_acl_version(int version) 326da6c28aaSamw { 327da6c28aaSamw if (version < ZPL_VERSION_FUID) 328da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 329da6c28aaSamw else 330da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 331da6c28aaSamw } 332da6c28aaSamw 333da6c28aaSamw static int 334da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 335da6c28aaSamw { 336da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 337da6c28aaSamw } 338fa9e4066Sahrens 339fa9e4066Sahrens static zfs_acl_t * 340da6c28aaSamw zfs_acl_alloc(int vers) 341fa9e4066Sahrens { 342fa9e4066Sahrens zfs_acl_t *aclp; 343fa9e4066Sahrens 344fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 345da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 346da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 347da6c28aaSamw aclp->z_version = vers; 348da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 349da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 350da6c28aaSamw else 351da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 352fa9e4066Sahrens return (aclp); 353fa9e4066Sahrens } 354fa9e4066Sahrens 355da6c28aaSamw static zfs_acl_node_t * 356da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 357da6c28aaSamw { 358da6c28aaSamw zfs_acl_node_t *aclnode; 359da6c28aaSamw 360da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 361da6c28aaSamw if (bytes) { 362da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 363da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 364da6c28aaSamw aclnode->z_allocsize = bytes; 365da6c28aaSamw aclnode->z_size = bytes; 366da6c28aaSamw } 367da6c28aaSamw 368da6c28aaSamw return (aclnode); 369da6c28aaSamw } 370da6c28aaSamw 371da6c28aaSamw static void 372da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 373da6c28aaSamw { 374da6c28aaSamw if (aclnode->z_allocsize) 375da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 376da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 377da6c28aaSamw } 378da6c28aaSamw 3792459a9eaSmarks static void 3802459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 381fa9e4066Sahrens { 382da6c28aaSamw zfs_acl_node_t *aclnode; 383da6c28aaSamw 384da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 385da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 386da6c28aaSamw zfs_acl_node_free(aclnode); 387fa9e4066Sahrens } 3882459a9eaSmarks aclp->z_acl_count = 0; 3892459a9eaSmarks aclp->z_acl_bytes = 0; 3902459a9eaSmarks } 391da6c28aaSamw 3922459a9eaSmarks void 3932459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 3942459a9eaSmarks { 3952459a9eaSmarks zfs_acl_release_nodes(aclp); 396da6c28aaSamw list_destroy(&aclp->z_acl); 397fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 398fa9e4066Sahrens } 399fa9e4066Sahrens 400da6c28aaSamw static boolean_t 401003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 402fa9e4066Sahrens { 403003c2582SMark Shellenbaum uint16_t entry_type; 404da6c28aaSamw 405003c2582SMark Shellenbaum switch (type) { 406003c2582SMark Shellenbaum case ALLOW: 407003c2582SMark Shellenbaum case DENY: 408003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 409003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 410003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 411003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 412003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 413003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 414003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 415da6c28aaSamw default: 416003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 417003c2582SMark Shellenbaum return (B_TRUE); 418da6c28aaSamw } 419003c2582SMark Shellenbaum return (B_FALSE); 420003c2582SMark Shellenbaum } 421fa9e4066Sahrens 422003c2582SMark Shellenbaum static boolean_t 423003c2582SMark Shellenbaum zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 424003c2582SMark Shellenbaum { 425169cdae2Smarks /* 426003c2582SMark Shellenbaum * first check type of entry 427169cdae2Smarks */ 428fa9e4066Sahrens 429003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 430da6c28aaSamw return (B_FALSE); 431da6c28aaSamw 432da6c28aaSamw switch (type) { 433da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 434da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 435da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 436da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 437da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 438da6c28aaSamw return (B_FALSE); 439da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 440da6c28aaSamw } 441da6c28aaSamw 442003c2582SMark Shellenbaum /* 443003c2582SMark Shellenbaum * next check inheritance level flags 444003c2582SMark Shellenbaum */ 445003c2582SMark Shellenbaum 446b249c65cSmarks if (obj_type == VDIR && 447b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 448da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 449da6c28aaSamw 450da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 451da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 452da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 453da6c28aaSamw return (B_FALSE); 454da6c28aaSamw } 455da6c28aaSamw } 456da6c28aaSamw 457da6c28aaSamw return (B_TRUE); 458da6c28aaSamw } 459da6c28aaSamw 460da6c28aaSamw static void * 461da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 462da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 463da6c28aaSamw { 464da6c28aaSamw zfs_acl_node_t *aclnode; 465da6c28aaSamw 466da6c28aaSamw if (start == NULL) { 467da6c28aaSamw aclnode = list_head(&aclp->z_acl); 468da6c28aaSamw if (aclnode == NULL) 469da6c28aaSamw return (NULL); 470da6c28aaSamw 471da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 472da6c28aaSamw aclp->z_curr_node = aclnode; 473da6c28aaSamw aclnode->z_ace_idx = 0; 474da6c28aaSamw } 475da6c28aaSamw 476da6c28aaSamw aclnode = aclp->z_curr_node; 477da6c28aaSamw 478da6c28aaSamw if (aclnode == NULL) 479da6c28aaSamw return (NULL); 480da6c28aaSamw 481da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 482da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 483da6c28aaSamw if (aclnode == NULL) 484da6c28aaSamw return (NULL); 485da6c28aaSamw else { 486da6c28aaSamw aclp->z_curr_node = aclnode; 487da6c28aaSamw aclnode->z_ace_idx = 0; 488da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 489da6c28aaSamw } 490da6c28aaSamw } 491da6c28aaSamw 492da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 493da6c28aaSamw void *acep = aclp->z_next_ace; 494003c2582SMark Shellenbaum size_t ace_size; 495003c2582SMark Shellenbaum 496003c2582SMark Shellenbaum /* 497003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 498003c2582SMark Shellenbaum */ 499003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 500003c2582SMark Shellenbaum 501003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 502003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 503003c2582SMark Shellenbaum return (NULL); 504003c2582SMark Shellenbaum } 505003c2582SMark Shellenbaum 506da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 507da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 508da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 509da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 510003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 511da6c28aaSamw aclnode->z_ace_idx++; 512da6c28aaSamw return ((void *)acep); 513da6c28aaSamw } 514da6c28aaSamw return (NULL); 515da6c28aaSamw } 516da6c28aaSamw 517da6c28aaSamw /*ARGSUSED*/ 518da6c28aaSamw static uint64_t 519da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 520da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 521da6c28aaSamw { 522da6c28aaSamw zfs_acl_t *aclp = datap; 523da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 524da6c28aaSamw uint64_t who; 525da6c28aaSamw 526da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 527da6c28aaSamw flags, type); 528da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 529da6c28aaSamw } 530da6c28aaSamw 531da6c28aaSamw static zfs_acl_node_t * 532da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 533da6c28aaSamw { 534da6c28aaSamw ASSERT(aclp->z_curr_node); 535da6c28aaSamw return (aclp->z_curr_node); 536da6c28aaSamw } 537da6c28aaSamw 538da6c28aaSamw /* 539da6c28aaSamw * Copy ACE to internal ZFS format. 540da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 541da6c28aaSamw * ACE FUIDs will be created later. 542da6c28aaSamw */ 543da6c28aaSamw int 54489459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 54589459e17SMark Shellenbaum void *datap, zfs_ace_t *z_acl, int aclcnt, size_t *size, 54689459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 547da6c28aaSamw { 548da6c28aaSamw int i; 549da6c28aaSamw uint16_t entry_type; 550da6c28aaSamw zfs_ace_t *aceptr = z_acl; 551da6c28aaSamw ace_t *acep = datap; 552da6c28aaSamw zfs_object_ace_t *zobjacep; 553da6c28aaSamw ace_object_t *aceobjp; 554da6c28aaSamw 555da6c28aaSamw for (i = 0; i != aclcnt; i++) { 556da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 557da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 558da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 559da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 560da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 5614c841f60Smarks entry_type != ACE_EVERYONE) { 56289459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 56389459e17SMark Shellenbaum cr, (entry_type == 0) ? 56489459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 5654c841f60Smarks } 5664c841f60Smarks 567da6c28aaSamw /* 568da6c28aaSamw * Make sure ACE is valid 569da6c28aaSamw */ 570da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 571da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 572da6c28aaSamw return (EINVAL); 573da6c28aaSamw 574da6c28aaSamw switch (acep->a_type) { 575da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 576da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 577da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 578da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 579da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 580da6c28aaSamw aceobjp = (ace_object_t *)acep; 581da6c28aaSamw 582da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 583da6c28aaSamw sizeof (aceobjp->a_obj_type)); 584da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 585da6c28aaSamw zobjacep->z_inherit_type, 586da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 587da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 588da6c28aaSamw break; 589da6c28aaSamw default: 590da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 591da6c28aaSamw } 592da6c28aaSamw 593da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 594da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 595da6c28aaSamw } 596da6c28aaSamw 597da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 598da6c28aaSamw 599da6c28aaSamw return (0); 600da6c28aaSamw } 601da6c28aaSamw 602da6c28aaSamw /* 603da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 604da6c28aaSamw */ 605da6c28aaSamw static void 606bda89588Sjp zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 607bda89588Sjp void *datap, int filter) 608da6c28aaSamw { 609da6c28aaSamw uint64_t who; 610da6c28aaSamw uint32_t access_mask; 611da6c28aaSamw uint16_t iflags, type; 612da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 613da6c28aaSamw ace_t *acep = datap; 614da6c28aaSamw ace_object_t *objacep; 615da6c28aaSamw zfs_object_ace_t *zobjacep; 616da6c28aaSamw size_t ace_size; 617da6c28aaSamw uint16_t entry_type; 618da6c28aaSamw 619da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 620da6c28aaSamw &who, &access_mask, &iflags, &type)) { 621da6c28aaSamw 622da6c28aaSamw switch (type) { 623da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 624da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 625da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 626da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 627da6c28aaSamw if (filter) { 628da6c28aaSamw continue; 629da6c28aaSamw } 630da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 631da6c28aaSamw objacep = (ace_object_t *)acep; 632da6c28aaSamw bcopy(zobjacep->z_object_type, 633da6c28aaSamw objacep->a_obj_type, 634da6c28aaSamw sizeof (zobjacep->z_object_type)); 635da6c28aaSamw bcopy(zobjacep->z_inherit_type, 636da6c28aaSamw objacep->a_inherit_obj_type, 637da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 638da6c28aaSamw ace_size = sizeof (ace_object_t); 639da6c28aaSamw break; 640da6c28aaSamw default: 641da6c28aaSamw ace_size = sizeof (ace_t); 642da6c28aaSamw break; 643da6c28aaSamw } 644da6c28aaSamw 645da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 646da6c28aaSamw if ((entry_type != ACE_OWNER && 6471ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 648e0d35c44Smarks entry_type != ACE_EVERYONE)) { 649e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 650e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 651e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 652e0d35c44Smarks } else { 653da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 654e0d35c44Smarks } 655da6c28aaSamw acep->a_access_mask = access_mask; 656da6c28aaSamw acep->a_flags = iflags; 657da6c28aaSamw acep->a_type = type; 658da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 659da6c28aaSamw } 660da6c28aaSamw } 661da6c28aaSamw 662da6c28aaSamw static int 663da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 664da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 665da6c28aaSamw { 666da6c28aaSamw int i; 667da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 668da6c28aaSamw 669da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 670da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 671da6c28aaSamw aceptr->z_type = acep[i].a_type; 672da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 673da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 674da6c28aaSamw /* 675da6c28aaSamw * Make sure ACE is valid 676da6c28aaSamw */ 677da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 678da6c28aaSamw aceptr->z_flags) != B_TRUE) 679da6c28aaSamw return (EINVAL); 680da6c28aaSamw } 681da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 682da6c28aaSamw return (0); 683da6c28aaSamw } 684da6c28aaSamw 685da6c28aaSamw /* 686da6c28aaSamw * convert old ACL format to new 687da6c28aaSamw */ 688da6c28aaSamw void 68989459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 690da6c28aaSamw { 691da6c28aaSamw zfs_oldace_t *oldaclp; 692da6c28aaSamw int i; 693da6c28aaSamw uint16_t type, iflags; 694da6c28aaSamw uint32_t access_mask; 695da6c28aaSamw uint64_t who; 696da6c28aaSamw void *cookie = NULL; 6972459a9eaSmarks zfs_acl_node_t *newaclnode; 698da6c28aaSamw 699da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 700da6c28aaSamw /* 701da6c28aaSamw * First create the ACE in a contiguous piece of memory 702da6c28aaSamw * for zfs_copy_ace_2_fuid(). 703da6c28aaSamw * 704da6c28aaSamw * We only convert an ACL once, so this won't happen 705da6c28aaSamw * everytime. 706da6c28aaSamw */ 707da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 708da6c28aaSamw KM_SLEEP); 709da6c28aaSamw i = 0; 710da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 711da6c28aaSamw &access_mask, &iflags, &type)) { 712da6c28aaSamw oldaclp[i].z_flags = iflags; 713da6c28aaSamw oldaclp[i].z_type = type; 714da6c28aaSamw oldaclp[i].z_fuid = who; 715da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 716da6c28aaSamw } 717da6c28aaSamw 718da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 719da6c28aaSamw sizeof (zfs_object_ace_t)); 720da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 72189459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 72289459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 72389459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 724da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 725da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 726da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 727da6c28aaSamw 728da6c28aaSamw /* 729da6c28aaSamw * Release all previous ACL nodes 730da6c28aaSamw */ 731da6c28aaSamw 7322459a9eaSmarks zfs_acl_release_nodes(aclp); 7332459a9eaSmarks 734da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 7352459a9eaSmarks 7362459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 7372459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 7382459a9eaSmarks 739fa9e4066Sahrens } 740fa9e4066Sahrens 741fa9e4066Sahrens /* 742fa9e4066Sahrens * Convert unix access mask to v4 access mask 743fa9e4066Sahrens */ 744fa9e4066Sahrens static uint32_t 745fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 746fa9e4066Sahrens { 747fa9e4066Sahrens uint32_t new_mask = 0; 748fa9e4066Sahrens 749da6c28aaSamw if (access_mask & S_IXOTH) 750da6c28aaSamw new_mask |= ACE_EXECUTE; 751da6c28aaSamw if (access_mask & S_IWOTH) 752da6c28aaSamw new_mask |= ACE_WRITE_DATA; 753da6c28aaSamw if (access_mask & S_IROTH) 754fa9e4066Sahrens new_mask |= ACE_READ_DATA; 755fa9e4066Sahrens return (new_mask); 756fa9e4066Sahrens } 757fa9e4066Sahrens 758fa9e4066Sahrens static void 759da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 760da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 761fa9e4066Sahrens { 762da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 763da6c28aaSamw 764da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 765da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 766da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 7671ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 768da6c28aaSamw type != ACE_EVERYONE)) 769da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 770fa9e4066Sahrens } 771fa9e4066Sahrens 772da6c28aaSamw /* 773da6c28aaSamw * Determine mode of file based on ACL. 774da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 775da6c28aaSamw */ 776fa9e4066Sahrens static uint64_t 77789459e17SMark Shellenbaum zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp) 778fa9e4066Sahrens { 779da6c28aaSamw int entry_type; 780da6c28aaSamw mode_t mode; 781da6c28aaSamw mode_t seen = 0; 782da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 783da6c28aaSamw uint64_t who; 784da6c28aaSamw uint16_t iflags, type; 785da6c28aaSamw uint32_t access_mask; 786d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 787da6c28aaSamw 788da6c28aaSamw mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 789fa9e4066Sahrens 790da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 791da6c28aaSamw &access_mask, &iflags, &type)) { 79229a0b737Smarks 793003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 794003c2582SMark Shellenbaum continue; 795003c2582SMark Shellenbaum 7961ab99678SMark Shellenbaum entry_type = (iflags & ACE_TYPE_FLAGS); 7971ab99678SMark Shellenbaum 79829a0b737Smarks /* 7991ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 80029a0b737Smarks */ 8011ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 8021ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 8031ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 80429a0b737Smarks continue; 80529a0b737Smarks 806fa9e4066Sahrens if (entry_type == ACE_OWNER) { 807da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 808fa9e4066Sahrens (!(seen & S_IRUSR))) { 809fa9e4066Sahrens seen |= S_IRUSR; 810da6c28aaSamw if (type == ALLOW) { 811fa9e4066Sahrens mode |= S_IRUSR; 812fa9e4066Sahrens } 813fa9e4066Sahrens } 814da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 815fa9e4066Sahrens (!(seen & S_IWUSR))) { 816fa9e4066Sahrens seen |= S_IWUSR; 817da6c28aaSamw if (type == ALLOW) { 818fa9e4066Sahrens mode |= S_IWUSR; 819fa9e4066Sahrens } 820fa9e4066Sahrens } 821da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 822fa9e4066Sahrens (!(seen & S_IXUSR))) { 823fa9e4066Sahrens seen |= S_IXUSR; 824da6c28aaSamw if (type == ALLOW) { 825fa9e4066Sahrens mode |= S_IXUSR; 826fa9e4066Sahrens } 827fa9e4066Sahrens } 828fa9e4066Sahrens } else if (entry_type == OWNING_GROUP) { 829da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 830fa9e4066Sahrens (!(seen & S_IRGRP))) { 831fa9e4066Sahrens seen |= S_IRGRP; 832da6c28aaSamw if (type == ALLOW) { 833fa9e4066Sahrens mode |= S_IRGRP; 834fa9e4066Sahrens } 835fa9e4066Sahrens } 836da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 837fa9e4066Sahrens (!(seen & S_IWGRP))) { 838fa9e4066Sahrens seen |= S_IWGRP; 839da6c28aaSamw if (type == ALLOW) { 840fa9e4066Sahrens mode |= S_IWGRP; 841fa9e4066Sahrens } 842fa9e4066Sahrens } 843da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 844fa9e4066Sahrens (!(seen & S_IXGRP))) { 845fa9e4066Sahrens seen |= S_IXGRP; 846da6c28aaSamw if (type == ALLOW) { 847fa9e4066Sahrens mode |= S_IXGRP; 848fa9e4066Sahrens } 849fa9e4066Sahrens } 850fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 851da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 852fa9e4066Sahrens if (!(seen & S_IRUSR)) { 853fa9e4066Sahrens seen |= S_IRUSR; 854da6c28aaSamw if (type == ALLOW) { 855fa9e4066Sahrens mode |= S_IRUSR; 856fa9e4066Sahrens } 857fa9e4066Sahrens } 858fa9e4066Sahrens if (!(seen & S_IRGRP)) { 859fa9e4066Sahrens seen |= S_IRGRP; 860da6c28aaSamw if (type == ALLOW) { 861fa9e4066Sahrens mode |= S_IRGRP; 862fa9e4066Sahrens } 863fa9e4066Sahrens } 864fa9e4066Sahrens if (!(seen & S_IROTH)) { 865fa9e4066Sahrens seen |= S_IROTH; 866da6c28aaSamw if (type == ALLOW) { 867fa9e4066Sahrens mode |= S_IROTH; 868fa9e4066Sahrens } 869fa9e4066Sahrens } 870fa9e4066Sahrens } 871da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 872fa9e4066Sahrens if (!(seen & S_IWUSR)) { 873fa9e4066Sahrens seen |= S_IWUSR; 874da6c28aaSamw if (type == ALLOW) { 875fa9e4066Sahrens mode |= S_IWUSR; 876fa9e4066Sahrens } 877fa9e4066Sahrens } 878fa9e4066Sahrens if (!(seen & S_IWGRP)) { 879fa9e4066Sahrens seen |= S_IWGRP; 880da6c28aaSamw if (type == ALLOW) { 881fa9e4066Sahrens mode |= S_IWGRP; 882fa9e4066Sahrens } 883fa9e4066Sahrens } 884fa9e4066Sahrens if (!(seen & S_IWOTH)) { 885fa9e4066Sahrens seen |= S_IWOTH; 886da6c28aaSamw if (type == ALLOW) { 887fa9e4066Sahrens mode |= S_IWOTH; 888fa9e4066Sahrens } 889fa9e4066Sahrens } 890fa9e4066Sahrens } 891da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 892fa9e4066Sahrens if (!(seen & S_IXUSR)) { 893fa9e4066Sahrens seen |= S_IXUSR; 894da6c28aaSamw if (type == ALLOW) { 895fa9e4066Sahrens mode |= S_IXUSR; 896fa9e4066Sahrens } 897fa9e4066Sahrens } 898fa9e4066Sahrens if (!(seen & S_IXGRP)) { 899fa9e4066Sahrens seen |= S_IXGRP; 900da6c28aaSamw if (type == ALLOW) { 901fa9e4066Sahrens mode |= S_IXGRP; 902fa9e4066Sahrens } 903fa9e4066Sahrens } 904fa9e4066Sahrens if (!(seen & S_IXOTH)) { 905fa9e4066Sahrens seen |= S_IXOTH; 906da6c28aaSamw if (type == ALLOW) { 907fa9e4066Sahrens mode |= S_IXOTH; 908fa9e4066Sahrens } 909fa9e4066Sahrens } 910fa9e4066Sahrens } 911d47621a4STim Haley } else { 912d47621a4STim Haley /* 913d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 914d47621a4STim Haley * USER ACE denies execute access to someone, 915d47621a4STim Haley * mode is not affected 916d47621a4STim Haley */ 917d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 918d47621a4STim Haley an_exec_denied = B_TRUE; 919fa9e4066Sahrens } 920fa9e4066Sahrens } 921d47621a4STim Haley 922*4929fd5eSTim Haley /* 923*4929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 924*4929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 925*4929fd5eSTim Haley * weren't allowed it. 926*4929fd5eSTim Haley */ 927*4929fd5eSTim Haley if (!an_exec_denied && 928*4929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 929*4929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 930d47621a4STim Haley an_exec_denied = B_TRUE; 931d47621a4STim Haley 932d47621a4STim Haley if (an_exec_denied) 933d47621a4STim Haley zp->z_phys->zp_flags &= ~ZFS_NO_EXECS_DENIED; 934d47621a4STim Haley else 935d47621a4STim Haley zp->z_phys->zp_flags |= ZFS_NO_EXECS_DENIED; 936d47621a4STim Haley 937fa9e4066Sahrens return (mode); 938fa9e4066Sahrens } 939fa9e4066Sahrens 940fa9e4066Sahrens static zfs_acl_t * 941da6c28aaSamw zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify) 942fa9e4066Sahrens { 943fa9e4066Sahrens zfs_acl_t *aclp; 944da6c28aaSamw zfs_acl_node_t *aclnode; 945da6c28aaSamw 946da6c28aaSamw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 947da6c28aaSamw 948da6c28aaSamw /* 949da6c28aaSamw * Version 0 to 1 znode_acl_phys has the size/count fields swapped. 950da6c28aaSamw * Version 0 didn't have a size field, only a count. 951da6c28aaSamw */ 952da6c28aaSamw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 953da6c28aaSamw aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_size; 954da6c28aaSamw aclp->z_acl_bytes = ZFS_ACL_SIZE(aclp->z_acl_count); 955da6c28aaSamw } else { 956da6c28aaSamw aclp->z_acl_count = zp->z_phys->zp_acl.z_acl_count; 957da6c28aaSamw aclp->z_acl_bytes = zp->z_phys->zp_acl.z_acl_size; 958da6c28aaSamw } 959da6c28aaSamw 960da6c28aaSamw aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0); 961da6c28aaSamw aclnode->z_ace_count = aclp->z_acl_count; 962da6c28aaSamw if (will_modify) { 963da6c28aaSamw bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata, 964da6c28aaSamw aclp->z_acl_bytes); 965da6c28aaSamw } else { 966da6c28aaSamw aclnode->z_size = aclp->z_acl_bytes; 967da6c28aaSamw aclnode->z_acldata = &zp->z_phys->zp_acl.z_ace_data[0]; 968da6c28aaSamw } 969fa9e4066Sahrens 970da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 971fa9e4066Sahrens 972fa9e4066Sahrens return (aclp); 973fa9e4066Sahrens } 974fa9e4066Sahrens 975fa9e4066Sahrens /* 976*4929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 977*4929fd5eSTim Haley * create a new acl and leave any cached acl in place. 978fa9e4066Sahrens */ 979ea8dc4b6Seschrock static int 980da6c28aaSamw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) 981fa9e4066Sahrens { 982fa9e4066Sahrens uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj; 983fa9e4066Sahrens zfs_acl_t *aclp; 984da6c28aaSamw size_t aclsize; 985da6c28aaSamw size_t acl_count; 986da6c28aaSamw zfs_acl_node_t *aclnode; 987ea8dc4b6Seschrock int error; 988fa9e4066Sahrens 989fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 990fa9e4066Sahrens 991*4929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 992d47621a4STim Haley *aclpp = zp->z_acl_cached; 993d47621a4STim Haley return (0); 994d47621a4STim Haley } 995d47621a4STim Haley 996ea8dc4b6Seschrock if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) { 997da6c28aaSamw *aclpp = zfs_acl_node_read_internal(zp, will_modify); 998*4929fd5eSTim Haley if (!will_modify) 999*4929fd5eSTim Haley zp->z_acl_cached = *aclpp; 1000ea8dc4b6Seschrock return (0); 1001ea8dc4b6Seschrock } 1002fa9e4066Sahrens 1003da6c28aaSamw aclp = zfs_acl_alloc(zp->z_phys->zp_acl.z_acl_version); 1004da6c28aaSamw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) { 1005da6c28aaSamw zfs_acl_phys_v0_t *zacl0 = 1006da6c28aaSamw (zfs_acl_phys_v0_t *)&zp->z_phys->zp_acl; 1007fa9e4066Sahrens 1008da6c28aaSamw aclsize = ZFS_ACL_SIZE(zacl0->z_acl_count); 1009da6c28aaSamw acl_count = zacl0->z_acl_count; 1010da6c28aaSamw } else { 1011da6c28aaSamw aclsize = zp->z_phys->zp_acl.z_acl_size; 1012da6c28aaSamw acl_count = zp->z_phys->zp_acl.z_acl_count; 1013da6c28aaSamw if (aclsize == 0) 1014da6c28aaSamw aclsize = acl_count * sizeof (zfs_ace_t); 1015da6c28aaSamw } 1016da6c28aaSamw aclnode = zfs_acl_node_alloc(aclsize); 1017da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1018ea8dc4b6Seschrock error = dmu_read(zp->z_zfsvfs->z_os, extacl, 0, 10197bfdf011SNeil Perrin aclsize, aclnode->z_acldata, DMU_READ_PREFETCH); 1020da6c28aaSamw aclnode->z_ace_count = acl_count; 1021da6c28aaSamw aclp->z_acl_count = acl_count; 1022da6c28aaSamw aclp->z_acl_bytes = aclsize; 1023da6c28aaSamw 1024ea8dc4b6Seschrock if (error != 0) { 1025ea8dc4b6Seschrock zfs_acl_free(aclp); 1026b87f3af3Sperrin /* convert checksum errors into IO errors */ 1027b87f3af3Sperrin if (error == ECKSUM) 1028b87f3af3Sperrin error = EIO; 1029ea8dc4b6Seschrock return (error); 1030ea8dc4b6Seschrock } 1031fa9e4066Sahrens 1032*4929fd5eSTim Haley *aclpp = aclp; 1033*4929fd5eSTim Haley if (!will_modify) 1034*4929fd5eSTim Haley zp->z_acl_cached = aclp; 1035ea8dc4b6Seschrock return (0); 1036fa9e4066Sahrens } 1037fa9e4066Sahrens 1038fa9e4066Sahrens /* 1039da6c28aaSamw * common code for setting ACLs. 1040fa9e4066Sahrens * 1041fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1042fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1043fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1044fa9e4066Sahrens */ 1045fa9e4066Sahrens int 104689459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1047fa9e4066Sahrens { 1048fa9e4066Sahrens int error; 1049fa9e4066Sahrens znode_phys_t *zphys = zp->z_phys; 1050da6c28aaSamw zfs_acl_phys_t *zacl = &zphys->zp_acl; 1051fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1052fa9e4066Sahrens uint64_t aoid = zphys->zp_acl.z_acl_extern_obj; 1053da6c28aaSamw uint64_t off = 0; 1054da6c28aaSamw dmu_object_type_t otype; 1055da6c28aaSamw zfs_acl_node_t *aclnode; 1056fa9e4066Sahrens 1057fa9e4066Sahrens dmu_buf_will_dirty(zp->z_dbuf, tx); 1058fa9e4066Sahrens 1059*4929fd5eSTim Haley if (zp->z_acl_cached) { 1060d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1061d47621a4STim Haley zp->z_acl_cached = NULL; 1062d47621a4STim Haley } 1063d47621a4STim Haley 106489459e17SMark Shellenbaum zphys->zp_mode = zfs_mode_compute(zp, aclp); 1065da6c28aaSamw 1066fa9e4066Sahrens /* 1067*4929fd5eSTim Haley * Decide which object type to use. If we are forced to 1068*4929fd5eSTim Haley * use old ACL format then transform ACL into zfs_oldace_t 1069da6c28aaSamw * layout. 1070fa9e4066Sahrens */ 1071da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1072da6c28aaSamw otype = DMU_OT_OLDACL; 1073da6c28aaSamw } else { 1074da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1075da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 107689459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1077da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1078da6c28aaSamw otype = DMU_OT_ACL; 1079da6c28aaSamw } 1080da6c28aaSamw 1081da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1082da6c28aaSamw /* 1083da6c28aaSamw * If ACL was previously external and we are now 1084da6c28aaSamw * converting to new ACL format then release old 1085da6c28aaSamw * ACL object and create a new one. 1086da6c28aaSamw */ 1087da6c28aaSamw if (aoid && aclp->z_version != zacl->z_acl_version) { 1088da6c28aaSamw error = dmu_object_free(zfsvfs->z_os, 1089da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, tx); 1090da6c28aaSamw if (error) 1091da6c28aaSamw return (error); 1092da6c28aaSamw aoid = 0; 1093da6c28aaSamw } 1094fa9e4066Sahrens if (aoid == 0) { 1095fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1096da6c28aaSamw otype, aclp->z_acl_bytes, 1097da6c28aaSamw otype == DMU_OT_ACL ? DMU_OT_SYSACL : DMU_OT_NONE, 1098da6c28aaSamw otype == DMU_OT_ACL ? DN_MAX_BONUSLEN : 0, tx); 1099fa9e4066Sahrens } else { 1100fa9e4066Sahrens (void) dmu_object_set_blocksize(zfsvfs->z_os, aoid, 1101da6c28aaSamw aclp->z_acl_bytes, 0, tx); 1102fa9e4066Sahrens } 1103fa9e4066Sahrens zphys->zp_acl.z_acl_extern_obj = aoid; 1104da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1105da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1106da6c28aaSamw if (aclnode->z_ace_count == 0) 1107da6c28aaSamw continue; 1108da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1109da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1110da6c28aaSamw off += aclnode->z_size; 1111da6c28aaSamw } 1112fa9e4066Sahrens } else { 1113da6c28aaSamw void *start = zacl->z_ace_data; 1114fa9e4066Sahrens /* 1115fa9e4066Sahrens * Migrating back embedded? 1116fa9e4066Sahrens */ 1117fa9e4066Sahrens if (zphys->zp_acl.z_acl_extern_obj) { 1118fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 11197106075aSmarks zp->z_phys->zp_acl.z_acl_extern_obj, tx); 1120fa9e4066Sahrens if (error) 1121fa9e4066Sahrens return (error); 1122fa9e4066Sahrens zphys->zp_acl.z_acl_extern_obj = 0; 1123fa9e4066Sahrens } 1124da6c28aaSamw 1125da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1126da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1127da6c28aaSamw if (aclnode->z_ace_count == 0) 1128da6c28aaSamw continue; 1129da6c28aaSamw bcopy(aclnode->z_acldata, start, aclnode->z_size); 1130da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1131da6c28aaSamw } 1132fa9e4066Sahrens } 1133de122929Smarks 1134da6c28aaSamw /* 1135da6c28aaSamw * If Old version then swap count/bytes to match old 1136da6c28aaSamw * layout of znode_acl_phys_t. 1137da6c28aaSamw */ 1138da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1139da6c28aaSamw zphys->zp_acl.z_acl_size = aclp->z_acl_count; 1140da6c28aaSamw zphys->zp_acl.z_acl_count = aclp->z_acl_bytes; 1141da6c28aaSamw } else { 1142da6c28aaSamw zphys->zp_acl.z_acl_size = aclp->z_acl_bytes; 1143da6c28aaSamw zphys->zp_acl.z_acl_count = aclp->z_acl_count; 1144de122929Smarks } 1145fa9e4066Sahrens 1146da6c28aaSamw zphys->zp_acl.z_acl_version = aclp->z_version; 1147da6c28aaSamw 1148da6c28aaSamw /* 1149da6c28aaSamw * Replace ACL wide bits, but first clear them. 1150da6c28aaSamw */ 1151da6c28aaSamw zp->z_phys->zp_flags &= ~ZFS_ACL_WIDE_FLAGS; 1152da6c28aaSamw 1153da6c28aaSamw zp->z_phys->zp_flags |= aclp->z_hints; 1154fa9e4066Sahrens 1155da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 1156da6c28aaSamw zp->z_phys->zp_flags |= ZFS_ACL_TRIVIAL; 1157da6c28aaSamw 1158fa9e4066Sahrens return (0); 1159fa9e4066Sahrens } 1160fa9e4066Sahrens 1161fa9e4066Sahrens /* 1162fa9e4066Sahrens * Update access mask for prepended ACE 1163fa9e4066Sahrens * 1164fa9e4066Sahrens * This applies the "groupmask" value for aclmode property. 1165fa9e4066Sahrens */ 1166fa9e4066Sahrens static void 1167da6c28aaSamw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, 1168da6c28aaSamw mode_t mode, uint64_t owner) 1169fa9e4066Sahrens { 1170fa9e4066Sahrens int rmask, wmask, xmask; 1171fa9e4066Sahrens int user_ace; 1172da6c28aaSamw uint16_t aceflags; 1173da6c28aaSamw uint32_t origmask, acepmask; 1174da6c28aaSamw uint64_t fuid; 1175da6c28aaSamw 1176da6c28aaSamw aceflags = aclp->z_ops.ace_flags_get(acep); 1177da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1178da6c28aaSamw origmask = aclp->z_ops.ace_mask_get(origacep); 1179da6c28aaSamw acepmask = aclp->z_ops.ace_mask_get(acep); 1180fa9e4066Sahrens 1181da6c28aaSamw user_ace = (!(aceflags & 1182fa9e4066Sahrens (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); 1183fa9e4066Sahrens 1184da6c28aaSamw if (user_ace && (fuid == owner)) { 1185fa9e4066Sahrens rmask = S_IRUSR; 1186fa9e4066Sahrens wmask = S_IWUSR; 1187fa9e4066Sahrens xmask = S_IXUSR; 1188fa9e4066Sahrens } else { 1189fa9e4066Sahrens rmask = S_IRGRP; 1190fa9e4066Sahrens wmask = S_IWGRP; 1191fa9e4066Sahrens xmask = S_IXGRP; 1192fa9e4066Sahrens } 1193fa9e4066Sahrens 1194da6c28aaSamw if (origmask & ACE_READ_DATA) { 1195da6c28aaSamw if (mode & rmask) { 1196da6c28aaSamw acepmask &= ~ACE_READ_DATA; 1197da6c28aaSamw } else { 1198da6c28aaSamw acepmask |= ACE_READ_DATA; 1199da6c28aaSamw } 1200fa9e4066Sahrens } 1201fa9e4066Sahrens 1202da6c28aaSamw if (origmask & ACE_WRITE_DATA) { 1203da6c28aaSamw if (mode & wmask) { 1204da6c28aaSamw acepmask &= ~ACE_WRITE_DATA; 1205da6c28aaSamw } else { 1206da6c28aaSamw acepmask |= ACE_WRITE_DATA; 1207da6c28aaSamw } 1208fa9e4066Sahrens } 1209fa9e4066Sahrens 1210da6c28aaSamw if (origmask & ACE_APPEND_DATA) { 1211da6c28aaSamw if (mode & wmask) { 1212da6c28aaSamw acepmask &= ~ACE_APPEND_DATA; 1213da6c28aaSamw } else { 1214da6c28aaSamw acepmask |= ACE_APPEND_DATA; 1215da6c28aaSamw } 1216fa9e4066Sahrens } 1217fa9e4066Sahrens 1218da6c28aaSamw if (origmask & ACE_EXECUTE) { 1219da6c28aaSamw if (mode & xmask) { 1220da6c28aaSamw acepmask &= ~ACE_EXECUTE; 1221da6c28aaSamw } else { 1222da6c28aaSamw acepmask |= ACE_EXECUTE; 1223da6c28aaSamw } 1224fa9e4066Sahrens } 1225da6c28aaSamw aclp->z_ops.ace_mask_set(acep, acepmask); 1226fa9e4066Sahrens } 1227fa9e4066Sahrens 1228fa9e4066Sahrens /* 1229fa9e4066Sahrens * Apply mode to canonical six ACEs. 1230fa9e4066Sahrens */ 1231fa9e4066Sahrens static void 1232fa9e4066Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode) 1233fa9e4066Sahrens { 1234da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1235da6c28aaSamw void *acep; 1236da6c28aaSamw int maskoff = aclp->z_ops.ace_mask_off(); 1237da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1238fa9e4066Sahrens 1239da6c28aaSamw ASSERT(aclnode != NULL); 1240da6c28aaSamw 1241da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1242da6c28aaSamw aclnode->z_size - (abstract_size * 6)); 1243fa9e4066Sahrens 1244fa9e4066Sahrens /* 1245fa9e4066Sahrens * Fixup final ACEs to match the mode 1246fa9e4066Sahrens */ 1247fa9e4066Sahrens 1248da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1249da6c28aaSamw (mode & 0700) >> 6); /* owner@ */ 1250da6c28aaSamw 1251da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1252da6c28aaSamw 1253da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1254da6c28aaSamw (mode & 0070) >> 3); /* group@ */ 1255da6c28aaSamw 1256da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1257da6c28aaSamw adjust_ace_pair_common(acep, maskoff, 1258da6c28aaSamw abstract_size, mode); /* everyone@ */ 1259fa9e4066Sahrens } 1260fa9e4066Sahrens 1261fa9e4066Sahrens 1262fa9e4066Sahrens static int 1263da6c28aaSamw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny, 1264da6c28aaSamw int entry_type, int accessmask) 1265fa9e4066Sahrens { 1266da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1267da6c28aaSamw uint16_t type = aclp->z_ops.ace_type_get(acep); 1268da6c28aaSamw uint16_t flags = aclp->z_ops.ace_flags_get(acep); 1269da6c28aaSamw 1270da6c28aaSamw return (mask == accessmask && type == allow_deny && 1271da6c28aaSamw ((flags & ACE_TYPE_FLAGS) == entry_type)); 1272fa9e4066Sahrens } 1273fa9e4066Sahrens 1274fa9e4066Sahrens /* 1275fa9e4066Sahrens * Can prepended ACE be reused? 1276fa9e4066Sahrens */ 1277fa9e4066Sahrens static int 1278da6c28aaSamw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep) 1279fa9e4066Sahrens { 1280fa9e4066Sahrens int okay_masks; 1281da6c28aaSamw uint16_t prevtype; 1282da6c28aaSamw uint16_t prevflags; 1283da6c28aaSamw uint16_t flags; 1284da6c28aaSamw uint32_t mask, prevmask; 1285fa9e4066Sahrens 1286da6c28aaSamw if (prevacep == NULL) 1287fa9e4066Sahrens return (B_FALSE); 1288fa9e4066Sahrens 1289da6c28aaSamw prevtype = aclp->z_ops.ace_type_get(prevacep); 1290da6c28aaSamw prevflags = aclp->z_ops.ace_flags_get(prevacep); 1291da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1292da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1293da6c28aaSamw prevmask = aclp->z_ops.ace_mask_get(prevacep); 1294da6c28aaSamw 1295da6c28aaSamw if (prevtype != DENY) 1296fa9e4066Sahrens return (B_FALSE); 1297fa9e4066Sahrens 1298da6c28aaSamw if (prevflags != (flags & ACE_IDENTIFIER_GROUP)) 1299fa9e4066Sahrens return (B_FALSE); 1300fa9e4066Sahrens 1301da6c28aaSamw okay_masks = (mask & OKAY_MASK_BITS); 1302fa9e4066Sahrens 1303da6c28aaSamw if (prevmask & ~okay_masks) 1304fa9e4066Sahrens return (B_FALSE); 1305fa9e4066Sahrens 1306fa9e4066Sahrens return (B_TRUE); 1307fa9e4066Sahrens } 1308fa9e4066Sahrens 1309da6c28aaSamw 1310fa9e4066Sahrens /* 1311da6c28aaSamw * Insert new ACL node into chain of zfs_acl_node_t's 1312da6c28aaSamw * 1313da6c28aaSamw * This will result in two possible results. 1314da6c28aaSamw * 1. If the ACL is currently just a single zfs_acl_node and 1315da6c28aaSamw * we are prepending the entry then current acl node will have 1316da6c28aaSamw * a new node inserted above it. 1317da6c28aaSamw * 1318da6c28aaSamw * 2. If we are inserting in the middle of current acl node then 1319da6c28aaSamw * the current node will be split in two and new node will be inserted 1320da6c28aaSamw * in between the two split nodes. 1321fa9e4066Sahrens */ 1322da6c28aaSamw static zfs_acl_node_t * 1323da6c28aaSamw zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep) 1324da6c28aaSamw { 1325da6c28aaSamw zfs_acl_node_t *newnode; 1326da6c28aaSamw zfs_acl_node_t *trailernode = NULL; 1327da6c28aaSamw zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp); 1328da6c28aaSamw int curr_idx = aclp->z_curr_node->z_ace_idx; 1329da6c28aaSamw int trailer_count; 1330da6c28aaSamw size_t oldsize; 1331da6c28aaSamw 1332da6c28aaSamw newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep)); 1333da6c28aaSamw newnode->z_ace_count = 1; 1334da6c28aaSamw 1335da6c28aaSamw oldsize = currnode->z_size; 1336da6c28aaSamw 1337da6c28aaSamw if (curr_idx != 1) { 1338da6c28aaSamw trailernode = zfs_acl_node_alloc(0); 1339da6c28aaSamw trailernode->z_acldata = acep; 1340da6c28aaSamw 1341da6c28aaSamw trailer_count = currnode->z_ace_count - curr_idx + 1; 1342da6c28aaSamw currnode->z_ace_count = curr_idx - 1; 1343da6c28aaSamw currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata; 1344da6c28aaSamw trailernode->z_size = oldsize - currnode->z_size; 1345da6c28aaSamw trailernode->z_ace_count = trailer_count; 1346fa9e4066Sahrens } 1347fa9e4066Sahrens 1348da6c28aaSamw aclp->z_acl_count += 1; 1349da6c28aaSamw aclp->z_acl_bytes += aclp->z_ops.ace_size(acep); 1350da6c28aaSamw 1351da6c28aaSamw if (curr_idx == 1) 1352da6c28aaSamw list_insert_before(&aclp->z_acl, currnode, newnode); 1353da6c28aaSamw else 1354da6c28aaSamw list_insert_after(&aclp->z_acl, currnode, newnode); 1355da6c28aaSamw if (trailernode) { 1356da6c28aaSamw list_insert_after(&aclp->z_acl, newnode, trailernode); 1357da6c28aaSamw aclp->z_curr_node = trailernode; 1358da6c28aaSamw trailernode->z_ace_idx = 1; 1359fa9e4066Sahrens } 1360fa9e4066Sahrens 1361da6c28aaSamw return (newnode); 1362fa9e4066Sahrens } 1363fa9e4066Sahrens 1364fa9e4066Sahrens /* 1365fa9e4066Sahrens * Prepend deny ACE 1366fa9e4066Sahrens */ 1367da6c28aaSamw static void * 136889459e17SMark Shellenbaum zfs_acl_prepend_deny(uint64_t uid, zfs_acl_t *aclp, void *acep, 1369fa9e4066Sahrens mode_t mode) 1370fa9e4066Sahrens { 1371da6c28aaSamw zfs_acl_node_t *aclnode; 1372da6c28aaSamw void *newacep; 1373da6c28aaSamw uint64_t fuid; 1374da6c28aaSamw uint16_t flags; 1375da6c28aaSamw 1376da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1377da6c28aaSamw newacep = aclnode->z_acldata; 1378da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1379da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1380da6c28aaSamw zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS)); 138189459e17SMark Shellenbaum zfs_acl_prepend_fixup(aclp, newacep, acep, mode, uid); 1382da6c28aaSamw 1383da6c28aaSamw return (newacep); 1384fa9e4066Sahrens } 1385fa9e4066Sahrens 1386fa9e4066Sahrens /* 1387fa9e4066Sahrens * Split an inherited ACE into inherit_only ACE 1388fa9e4066Sahrens * and original ACE with inheritance flags stripped off. 1389fa9e4066Sahrens */ 1390fa9e4066Sahrens static void 1391da6c28aaSamw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep) 1392fa9e4066Sahrens { 1393da6c28aaSamw zfs_acl_node_t *aclnode; 1394569e6c63Smarks zfs_acl_node_t *currnode; 1395da6c28aaSamw void *newacep; 1396da6c28aaSamw uint16_t type, flags; 1397da6c28aaSamw uint32_t mask; 1398da6c28aaSamw uint64_t fuid; 1399da6c28aaSamw 1400da6c28aaSamw type = aclp->z_ops.ace_type_get(acep); 1401da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1402da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1403da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1404da6c28aaSamw 1405da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1406da6c28aaSamw newacep = aclnode->z_acldata; 1407da6c28aaSamw 1408da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1409da6c28aaSamw aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE); 1410da6c28aaSamw aclp->z_ops.ace_mask_set(newacep, mask); 1411da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1412da6c28aaSamw aclp->z_ops.ace_who_set(newacep, fuid); 1413da6c28aaSamw aclp->z_next_ace = acep; 1414da6c28aaSamw flags &= ~ALL_INHERIT; 1415da6c28aaSamw aclp->z_ops.ace_flags_set(acep, flags); 1416569e6c63Smarks currnode = zfs_acl_curr_node(aclp); 1417569e6c63Smarks ASSERT(currnode->z_ace_idx >= 1); 1418da6c28aaSamw currnode->z_ace_idx -= 1; 1419fa9e4066Sahrens } 1420fa9e4066Sahrens 1421fa9e4066Sahrens /* 1422fa9e4066Sahrens * Are ACES started at index i, the canonical six ACES? 1423fa9e4066Sahrens */ 1424fa9e4066Sahrens static int 1425da6c28aaSamw zfs_have_canonical_six(zfs_acl_t *aclp) 1426fa9e4066Sahrens { 1427da6c28aaSamw void *acep; 1428da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1429da6c28aaSamw int i = 0; 1430da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1431da6c28aaSamw 1432da6c28aaSamw ASSERT(aclnode != NULL); 1433da6c28aaSamw 1434da6c28aaSamw if (aclnode->z_ace_count < 6) 1435da6c28aaSamw return (0); 1436fa9e4066Sahrens 1437da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1438da6c28aaSamw aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6)); 1439da6c28aaSamw 1440da6c28aaSamw if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1441fa9e4066Sahrens DENY, ACE_OWNER, 0) && 1442da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1443da6c28aaSamw ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) && 1444da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY, 1445da6c28aaSamw OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep + 1446da6c28aaSamw (abstract_size * i++), 1447da6c28aaSamw ALLOW, OWNING_GROUP, 0) && 1448da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1449fa9e4066Sahrens DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) && 1450da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1451da6c28aaSamw ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) { 1452fa9e4066Sahrens return (1); 1453fa9e4066Sahrens } else { 1454fa9e4066Sahrens return (0); 1455fa9e4066Sahrens } 1456fa9e4066Sahrens } 1457fa9e4066Sahrens 1458da6c28aaSamw 1459fa9e4066Sahrens /* 1460fa9e4066Sahrens * Apply step 1g, to group entries 1461fa9e4066Sahrens * 1462fa9e4066Sahrens * Need to deal with corner case where group may have 1463fa9e4066Sahrens * greater permissions than owner. If so then limit 1464fa9e4066Sahrens * group permissions, based on what extra permissions 1465fa9e4066Sahrens * group has. 1466fa9e4066Sahrens */ 1467fa9e4066Sahrens static void 1468da6c28aaSamw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep, 1469da6c28aaSamw mode_t mode) 1470fa9e4066Sahrens { 1471da6c28aaSamw uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep); 1472da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1473da6c28aaSamw uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep); 1474fa9e4066Sahrens mode_t extramode = (mode >> 3) & 07; 1475fa9e4066Sahrens mode_t ownermode = (mode >> 6); 1476fa9e4066Sahrens 1477da6c28aaSamw if (prevflags & ACE_IDENTIFIER_GROUP) { 1478fa9e4066Sahrens 1479fa9e4066Sahrens extramode &= ~ownermode; 1480fa9e4066Sahrens 1481fa9e4066Sahrens if (extramode) { 1482da6c28aaSamw if (extramode & S_IROTH) { 1483da6c28aaSamw prevmask &= ~ACE_READ_DATA; 1484da6c28aaSamw mask &= ~ACE_READ_DATA; 1485fa9e4066Sahrens } 1486da6c28aaSamw if (extramode & S_IWOTH) { 1487da6c28aaSamw prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1488da6c28aaSamw mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1489fa9e4066Sahrens } 1490da6c28aaSamw if (extramode & S_IXOTH) { 1491da6c28aaSamw prevmask &= ~ACE_EXECUTE; 1492da6c28aaSamw mask &= ~ACE_EXECUTE; 1493fa9e4066Sahrens } 1494fa9e4066Sahrens } 1495fa9e4066Sahrens } 1496da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1497da6c28aaSamw aclp->z_ops.ace_mask_set(prevacep, prevmask); 1498fa9e4066Sahrens } 1499fa9e4066Sahrens 1500fa9e4066Sahrens /* 1501fa9e4066Sahrens * Apply the chmod algorithm as described 1502fa9e4066Sahrens * in PSARC/2002/240 1503fa9e4066Sahrens */ 15044c841f60Smarks static void 150589459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t uid, 150689459e17SMark Shellenbaum uint64_t mode, zfs_acl_t *aclp) 1507fa9e4066Sahrens { 1508da6c28aaSamw void *acep = NULL, *prevacep = NULL; 1509da6c28aaSamw uint64_t who; 1510fa9e4066Sahrens int i; 1511fa9e4066Sahrens int entry_type; 1512fa9e4066Sahrens int reuse_deny; 1513fa9e4066Sahrens int need_canonical_six = 1; 1514da6c28aaSamw uint16_t iflags, type; 1515da6c28aaSamw uint32_t access_mask; 1516fa9e4066Sahrens 15172459a9eaSmarks /* 15182459a9eaSmarks * If discard then just discard all ACL nodes which 15192459a9eaSmarks * represent the ACEs. 15202459a9eaSmarks * 15212459a9eaSmarks * New owner@/group@/everone@ ACEs will be added 15222459a9eaSmarks * later. 15232459a9eaSmarks */ 15242459a9eaSmarks if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 15252459a9eaSmarks zfs_acl_release_nodes(aclp); 15262459a9eaSmarks 1527da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1528da6c28aaSamw &iflags, &type)) { 1529fa9e4066Sahrens 1530da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 1531da6c28aaSamw iflags = (iflags & ALL_INHERIT); 1532da6c28aaSamw 1533da6c28aaSamw if ((type != ALLOW && type != DENY) || 1534de122929Smarks (iflags & ACE_INHERIT_ONLY_ACE)) { 1535de122929Smarks if (iflags) 1536da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1537da6c28aaSamw switch (type) { 1538da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1539da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1540da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1541da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1542da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1543da6c28aaSamw break; 1544da6c28aaSamw } 1545da6c28aaSamw goto nextace; 1546fa9e4066Sahrens } 1547fa9e4066Sahrens 1548fa9e4066Sahrens /* 1549fa9e4066Sahrens * Need to split ace into two? 1550fa9e4066Sahrens */ 1551de122929Smarks if ((iflags & (ACE_FILE_INHERIT_ACE| 1552fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE)) && 1553de122929Smarks (!(iflags & ACE_INHERIT_ONLY_ACE))) { 1554da6c28aaSamw zfs_acl_split_ace(aclp, acep); 1555da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1556da6c28aaSamw goto nextace; 1557fa9e4066Sahrens } 1558fa9e4066Sahrens 1559fa9e4066Sahrens if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 1560fa9e4066Sahrens (entry_type == OWNING_GROUP)) { 1561da6c28aaSamw access_mask &= ~OGE_CLEAR; 1562da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 1563da6c28aaSamw goto nextace; 1564fa9e4066Sahrens } else { 1565da6c28aaSamw reuse_deny = B_TRUE; 1566da6c28aaSamw if (type == ALLOW) { 1567fa9e4066Sahrens 1568fa9e4066Sahrens /* 1569fa9e4066Sahrens * Check preceding ACE if any, to see 1570fa9e4066Sahrens * if we need to prepend a DENY ACE. 1571fa9e4066Sahrens * This is only applicable when the acl_mode 1572fa9e4066Sahrens * property == groupmask. 1573fa9e4066Sahrens */ 1574e9dbad6fSeschrock if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) { 1575fa9e4066Sahrens 1576da6c28aaSamw reuse_deny = zfs_reuse_deny(aclp, acep, 1577da6c28aaSamw prevacep); 1578fa9e4066Sahrens 1579e0d35c44Smarks if (!reuse_deny) { 1580da6c28aaSamw prevacep = 158189459e17SMark Shellenbaum zfs_acl_prepend_deny(uid, 1582da6c28aaSamw aclp, acep, mode); 1583fa9e4066Sahrens } else { 1584fa9e4066Sahrens zfs_acl_prepend_fixup( 1585da6c28aaSamw aclp, prevacep, 158689459e17SMark Shellenbaum acep, mode, uid); 1587fa9e4066Sahrens } 1588da6c28aaSamw zfs_fixup_group_entries(aclp, acep, 1589da6c28aaSamw prevacep, mode); 1590fa9e4066Sahrens } 1591fa9e4066Sahrens } 1592fa9e4066Sahrens } 1593da6c28aaSamw nextace: 1594da6c28aaSamw prevacep = acep; 1595fa9e4066Sahrens } 1596fa9e4066Sahrens 1597fa9e4066Sahrens /* 1598fa9e4066Sahrens * Check out last six aces, if we have six. 1599fa9e4066Sahrens */ 1600fa9e4066Sahrens 1601fa9e4066Sahrens if (aclp->z_acl_count >= 6) { 1602da6c28aaSamw if (zfs_have_canonical_six(aclp)) { 1603fa9e4066Sahrens need_canonical_six = 0; 1604fa9e4066Sahrens } 1605fa9e4066Sahrens } 1606fa9e4066Sahrens 1607fa9e4066Sahrens if (need_canonical_six) { 1608da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1609da6c28aaSamw void *zacep; 1610da6c28aaSamw zfs_acl_node_t *aclnode = 1611da6c28aaSamw zfs_acl_node_alloc(abstract_size * 6); 1612da6c28aaSamw 1613da6c28aaSamw aclnode->z_size = abstract_size * 6; 1614da6c28aaSamw aclnode->z_ace_count = 6; 1615da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1616da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1617da6c28aaSamw 1618da6c28aaSamw zacep = aclnode->z_acldata; 1619da6c28aaSamw 1620da6c28aaSamw i = 0; 1621da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1622da6c28aaSamw 0, DENY, -1, ACE_OWNER); 1623da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1624da6c28aaSamw OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER); 1625da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1626da6c28aaSamw DENY, -1, OWNING_GROUP); 1627da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1628da6c28aaSamw ALLOW, -1, OWNING_GROUP); 1629da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1630da6c28aaSamw EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE); 1631da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1632da6c28aaSamw EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE); 1633fa9e4066Sahrens aclp->z_acl_count += 6; 1634fa9e4066Sahrens } 1635fa9e4066Sahrens 1636fa9e4066Sahrens zfs_acl_fixup_canonical_six(aclp, mode); 1637fa9e4066Sahrens } 1638fa9e4066Sahrens 1639fa9e4066Sahrens int 16404c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1641fa9e4066Sahrens { 1642fa9e4066Sahrens int error; 1643fa9e4066Sahrens 16444c841f60Smarks mutex_enter(&zp->z_lock); 1645fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 16464c841f60Smarks *aclp = NULL; 16474c841f60Smarks error = zfs_acl_node_read(zp, aclp, B_TRUE); 164889459e17SMark Shellenbaum if (error == 0) { 164989459e17SMark Shellenbaum (*aclp)->z_hints = zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS; 165089459e17SMark Shellenbaum zfs_acl_chmod(zp->z_zfsvfs, zp->z_phys->zp_uid, mode, *aclp); 165189459e17SMark Shellenbaum } 1652fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 16534c841f60Smarks mutex_exit(&zp->z_lock); 1654fa9e4066Sahrens return (error); 1655fa9e4066Sahrens } 1656fa9e4066Sahrens 1657fa9e4066Sahrens /* 1658fa9e4066Sahrens * strip off write_owner and write_acl 1659fa9e4066Sahrens */ 1660fa9e4066Sahrens static void 1661b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1662fa9e4066Sahrens { 1663da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1664da6c28aaSamw 1665b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1666da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1667b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1668da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1669da6c28aaSamw } 1670da6c28aaSamw } 1671da6c28aaSamw 1672da6c28aaSamw /* 1673da6c28aaSamw * Should ACE be inherited? 1674da6c28aaSamw */ 1675da6c28aaSamw static int 167689459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1677da6c28aaSamw { 1678da6c28aaSamw int iflags = (acep_flags & 0xf); 1679da6c28aaSamw 1680da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1681da6c28aaSamw return (1); 1682da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1683da6c28aaSamw return (!((vtype == VDIR) && 1684da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1685da6c28aaSamw return (0); 1686fa9e4066Sahrens } 1687fa9e4066Sahrens 1688fa9e4066Sahrens /* 1689fa9e4066Sahrens * inherit inheritable ACEs from parent 1690fa9e4066Sahrens */ 1691fa9e4066Sahrens static zfs_acl_t * 169289459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 169389459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1694fa9e4066Sahrens { 1695da6c28aaSamw void *pacep; 1696da6c28aaSamw void *acep, *acep2; 1697da6c28aaSamw zfs_acl_node_t *aclnode, *aclnode2; 1698fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1699da6c28aaSamw uint64_t who; 1700da6c28aaSamw uint32_t access_mask; 1701da6c28aaSamw uint16_t iflags, newflags, type; 1702da6c28aaSamw size_t ace_size; 1703da6c28aaSamw void *data1, *data2; 1704da6c28aaSamw size_t data1sz, data2sz; 170589459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 170689459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1707d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1708d0f3f37eSMark Shellenbaum 1709d0f3f37eSMark Shellenbaum passthrough_x = 1710d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1711d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1712d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1713d0f3f37eSMark Shellenbaum noallow = 1714d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1715da6c28aaSamw 1716b3d141f8Smarks *need_chmod = B_TRUE; 1717da6c28aaSamw pacep = NULL; 1718003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 1719d0f3f37eSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD) 1720d0f3f37eSMark Shellenbaum return (aclp); 1721d0f3f37eSMark Shellenbaum while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1722d0f3f37eSMark Shellenbaum &access_mask, &iflags, &type)) { 1723fa9e4066Sahrens 1724d0f3f37eSMark Shellenbaum /* 1725d0f3f37eSMark Shellenbaum * don't inherit bogus ACEs 1726d0f3f37eSMark Shellenbaum */ 1727d0f3f37eSMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1728d0f3f37eSMark Shellenbaum continue; 1729003c2582SMark Shellenbaum 1730d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1731d0f3f37eSMark Shellenbaum continue; 1732fa9e4066Sahrens 1733d0f3f37eSMark Shellenbaum ace_size = aclp->z_ops.ace_size(pacep); 1734169cdae2Smarks 173589459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1736d0f3f37eSMark Shellenbaum continue; 1737b3d141f8Smarks 1738d0f3f37eSMark Shellenbaum /* 1739d0f3f37eSMark Shellenbaum * If owner@, group@, or everyone@ inheritable 1740d0f3f37eSMark Shellenbaum * then zfs_acl_chmod() isn't needed. 1741d0f3f37eSMark Shellenbaum */ 1742d0f3f37eSMark Shellenbaum if (passthrough && 1743d0f3f37eSMark Shellenbaum ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1744d0f3f37eSMark Shellenbaum ((iflags & OWNING_GROUP) == 1745d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1746d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1747d0f3f37eSMark Shellenbaum *need_chmod = B_FALSE; 1748d0f3f37eSMark Shellenbaum 1749d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1750d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1751d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1752d0f3f37eSMark Shellenbaum } 1753d0f3f37eSMark Shellenbaum } 1754d0f3f37eSMark Shellenbaum 1755d0f3f37eSMark Shellenbaum aclnode = zfs_acl_node_alloc(ace_size); 1756d0f3f37eSMark Shellenbaum list_insert_tail(&aclp->z_acl, aclnode); 1757d0f3f37eSMark Shellenbaum acep = aclnode->z_acldata; 1758d0f3f37eSMark Shellenbaum 1759d0f3f37eSMark Shellenbaum zfs_set_ace(aclp, acep, access_mask, type, 1760d0f3f37eSMark Shellenbaum who, iflags|ACE_INHERITED_ACE); 1761d0f3f37eSMark Shellenbaum 1762d0f3f37eSMark Shellenbaum /* 1763d0f3f37eSMark Shellenbaum * Copy special opaque data if any 1764d0f3f37eSMark Shellenbaum */ 1765d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1766d0f3f37eSMark Shellenbaum VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1767d0f3f37eSMark Shellenbaum &data2)) == data1sz); 1768d0f3f37eSMark Shellenbaum bcopy(data1, data2, data2sz); 1769d0f3f37eSMark Shellenbaum } 1770d0f3f37eSMark Shellenbaum aclp->z_acl_count++; 1771d0f3f37eSMark Shellenbaum aclnode->z_ace_count++; 1772d0f3f37eSMark Shellenbaum aclp->z_acl_bytes += aclnode->z_size; 1773d0f3f37eSMark Shellenbaum newflags = aclp->z_ops.ace_flags_get(acep); 1774d0f3f37eSMark Shellenbaum 1775d0f3f37eSMark Shellenbaum if (vdir) 1776d0f3f37eSMark Shellenbaum aclp->z_hints |= ZFS_INHERIT_ACE; 1777d0f3f37eSMark Shellenbaum 1778d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1779d0f3f37eSMark Shellenbaum newflags &= ~ALL_INHERIT; 1780d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep, 1781d0f3f37eSMark Shellenbaum newflags|ACE_INHERITED_ACE); 1782d0f3f37eSMark Shellenbaum zfs_restricted_update(zfsvfs, aclp, acep); 1783d0f3f37eSMark Shellenbaum continue; 1784d0f3f37eSMark Shellenbaum } 1785d0f3f37eSMark Shellenbaum 1786d0f3f37eSMark Shellenbaum ASSERT(vdir); 1787d0f3f37eSMark Shellenbaum 1788d0f3f37eSMark Shellenbaum newflags = aclp->z_ops.ace_flags_get(acep); 1789d0f3f37eSMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE | 1790d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) != 1791d0f3f37eSMark Shellenbaum ACE_FILE_INHERIT_ACE) { 1792d0f3f37eSMark Shellenbaum aclnode2 = zfs_acl_node_alloc(ace_size); 1793d0f3f37eSMark Shellenbaum list_insert_tail(&aclp->z_acl, aclnode2); 1794d0f3f37eSMark Shellenbaum acep2 = aclnode2->z_acldata; 1795d0f3f37eSMark Shellenbaum zfs_set_ace(aclp, acep2, 1796d0f3f37eSMark Shellenbaum access_mask, type, who, 1797d0f3f37eSMark Shellenbaum iflags|ACE_INHERITED_ACE); 1798d0f3f37eSMark Shellenbaum newflags |= ACE_INHERIT_ONLY_ACE; 1799d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep, newflags); 1800d0f3f37eSMark Shellenbaum newflags &= ~ALL_INHERIT; 1801d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep2, 1802d0f3f37eSMark Shellenbaum newflags|ACE_INHERITED_ACE); 1803b3d141f8Smarks 1804b3d141f8Smarks /* 1805b3d141f8Smarks * Copy special opaque data if any 1806b3d141f8Smarks */ 1807d0f3f37eSMark Shellenbaum if ((data1sz = aclp->z_ops.ace_data(acep, 1808b3d141f8Smarks &data1)) != 0) { 1809d0f3f37eSMark Shellenbaum VERIFY((data2sz = 1810d0f3f37eSMark Shellenbaum aclp->z_ops.ace_data(acep2, 1811b3d141f8Smarks &data2)) == data1sz); 1812d0f3f37eSMark Shellenbaum bcopy(data1, data2, data1sz); 1813b3d141f8Smarks } 1814b3d141f8Smarks aclp->z_acl_count++; 1815d0f3f37eSMark Shellenbaum aclnode2->z_ace_count++; 1816b3d141f8Smarks aclp->z_acl_bytes += aclnode->z_size; 1817d0f3f37eSMark Shellenbaum zfs_restricted_update(zfsvfs, aclp, acep2); 1818d0f3f37eSMark Shellenbaum } else { 1819d0f3f37eSMark Shellenbaum newflags |= ACE_INHERIT_ONLY_ACE; 1820d0f3f37eSMark Shellenbaum aclp->z_ops.ace_flags_set(acep, 1821d0f3f37eSMark Shellenbaum newflags|ACE_INHERITED_ACE); 1822fa9e4066Sahrens } 1823fa9e4066Sahrens } 1824fa9e4066Sahrens return (aclp); 1825fa9e4066Sahrens } 1826fa9e4066Sahrens 1827fa9e4066Sahrens /* 1828fa9e4066Sahrens * Create file system object initial permissions 1829fa9e4066Sahrens * including inheritable ACEs. 1830fa9e4066Sahrens */ 183189459e17SMark Shellenbaum int 183289459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 183389459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1834fa9e4066Sahrens { 1835fa9e4066Sahrens int error; 183689459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1837da6c28aaSamw zfs_acl_t *paclp; 1838e0d35c44Smarks gid_t gid; 1839b3d141f8Smarks boolean_t need_chmod = B_TRUE; 1840da6c28aaSamw 184189459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 184289459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1843fa9e4066Sahrens 184489459e17SMark Shellenbaum if (vsecp) 184589459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 184689459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 184789459e17SMark Shellenbaum return (error); 1848fa9e4066Sahrens 1849fa9e4066Sahrens /* 1850fa9e4066Sahrens * Determine uid and gid. 1851fa9e4066Sahrens */ 1852fa9e4066Sahrens if ((flag & (IS_ROOT_NODE | IS_REPLAY)) || 1853fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 185489459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 185589459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 185689459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 185789459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 185889459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 185989459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1860e0d35c44Smarks gid = vap->va_gid; 1861fa9e4066Sahrens } else { 186289459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 186389459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 186489459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1865e0d35c44Smarks if (vap->va_mask & AT_GID) { 186689459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 186789459e17SMark Shellenbaum (uint64_t)vap->va_gid, 186889459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1869e0d35c44Smarks gid = vap->va_gid; 187089459e17SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_phys->zp_gid && 1871e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1872e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 187389459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1874e0d35c44Smarks } 187589459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 187689459e17SMark Shellenbaum if (dzp->z_phys->zp_mode & S_ISGID) { 187789459e17SMark Shellenbaum acl_ids->z_fgid = dzp->z_phys->zp_gid; 187889459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1879e0d35c44Smarks cr, ZFS_GROUP); 1880e0d35c44Smarks } else { 188189459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 188289459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1883e0d35c44Smarks gid = crgetgid(cr); 1884e0d35c44Smarks } 1885da6c28aaSamw } 1886fa9e4066Sahrens } 1887fa9e4066Sahrens 1888fa9e4066Sahrens /* 1889fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1890fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1891fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1892fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1893fa9e4066Sahrens */ 1894fa9e4066Sahrens 189589459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_phys->zp_mode & S_ISGID) && 189689459e17SMark Shellenbaum (vap->va_type == VDIR)) { 189789459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1898e0d35c44Smarks } else { 189989459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1900fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 190189459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1902fa9e4066Sahrens } 1903fa9e4066Sahrens 190489459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 190589459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 190689459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && 190789459e17SMark Shellenbaum (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)) && 190889459e17SMark Shellenbaum !(dzp->z_phys->zp_flags & ZFS_XATTR)) { 190989459e17SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 191089459e17SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE)); 191189459e17SMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 191289459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 191389459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 1914da6c28aaSamw } else { 191589459e17SMark Shellenbaum acl_ids->z_aclp = 191689459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 191789459e17SMark Shellenbaum } 191889459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 191989459e17SMark Shellenbaum if (need_chmod) { 192089459e17SMark Shellenbaum acl_ids->z_aclp->z_hints = (vap->va_type == VDIR) ? 192189459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 192289459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs, acl_ids->z_fuid, 192389459e17SMark Shellenbaum acl_ids->z_mode, acl_ids->z_aclp); 1924da6c28aaSamw } 1925fa9e4066Sahrens } 1926da6c28aaSamw 192789459e17SMark Shellenbaum return (0); 192889459e17SMark Shellenbaum } 1929fa9e4066Sahrens 193089459e17SMark Shellenbaum /* 193189459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 193289459e17SMark Shellenbaum */ 193389459e17SMark Shellenbaum void 193489459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 193589459e17SMark Shellenbaum { 193689459e17SMark Shellenbaum if (acl_ids->z_aclp) 193789459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 193889459e17SMark Shellenbaum if (acl_ids->z_fuidp) 193989459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 194089459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 194189459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 1942fa9e4066Sahrens } 1943fa9e4066Sahrens 194414843421SMatthew Ahrens boolean_t 194514843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 194614843421SMatthew Ahrens { 194714843421SMatthew Ahrens return (zfs_usergroup_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 194814843421SMatthew Ahrens zfs_usergroup_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 194914843421SMatthew Ahrens } 195089459e17SMark Shellenbaum 1951fa9e4066Sahrens /* 1952fa9e4066Sahrens * Retrieve a files ACL 1953fa9e4066Sahrens */ 1954fa9e4066Sahrens int 1955da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1956fa9e4066Sahrens { 1957fa9e4066Sahrens zfs_acl_t *aclp; 1958da6c28aaSamw ulong_t mask; 1959fa9e4066Sahrens int error; 1960da6c28aaSamw int count = 0; 1961da6c28aaSamw int largeace = 0; 1962fa9e4066Sahrens 1963da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1964da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1965da6c28aaSamw 1966da6c28aaSamw if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 1967da6c28aaSamw return (error); 1968fa9e4066Sahrens 1969fa9e4066Sahrens if (mask == 0) 1970fa9e4066Sahrens return (ENOSYS); 1971fa9e4066Sahrens 1972fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1973fa9e4066Sahrens 1974da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 1975ea8dc4b6Seschrock if (error != 0) { 1976ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1977ea8dc4b6Seschrock return (error); 1978ea8dc4b6Seschrock } 1979ea8dc4b6Seschrock 1980da6c28aaSamw /* 1981da6c28aaSamw * Scan ACL to determine number of ACEs 1982da6c28aaSamw */ 1983da6c28aaSamw if ((zp->z_phys->zp_flags & ZFS_ACL_OBJ_ACE) && 1984da6c28aaSamw !(mask & VSA_ACE_ALLTYPES)) { 1985da6c28aaSamw void *zacep = NULL; 1986da6c28aaSamw uint64_t who; 1987da6c28aaSamw uint32_t access_mask; 1988da6c28aaSamw uint16_t type, iflags; 1989da6c28aaSamw 1990da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1991da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1992da6c28aaSamw switch (type) { 1993da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1994da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1995da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1996da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1997da6c28aaSamw largeace++; 1998da6c28aaSamw continue; 1999da6c28aaSamw default: 2000da6c28aaSamw count++; 2001da6c28aaSamw } 2002da6c28aaSamw } 2003da6c28aaSamw vsecp->vsa_aclcnt = count; 2004da6c28aaSamw } else 2005da6c28aaSamw count = aclp->z_acl_count; 2006fa9e4066Sahrens 2007fa9e4066Sahrens if (mask & VSA_ACECNT) { 2008da6c28aaSamw vsecp->vsa_aclcnt = count; 2009fa9e4066Sahrens } 2010fa9e4066Sahrens 2011fa9e4066Sahrens if (mask & VSA_ACE) { 2012da6c28aaSamw size_t aclsz; 2013da6c28aaSamw 2014da6c28aaSamw zfs_acl_node_t *aclnode = list_head(&aclp->z_acl); 2015da6c28aaSamw 2016da6c28aaSamw aclsz = count * sizeof (ace_t) + 2017da6c28aaSamw sizeof (ace_object_t) * largeace; 2018da6c28aaSamw 2019da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 2020da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 2021da6c28aaSamw 2022da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 2023bda89588Sjp zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 2024da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 2025da6c28aaSamw else { 2026da6c28aaSamw bcopy(aclnode->z_acldata, vsecp->vsa_aclentp, 2027da6c28aaSamw count * sizeof (ace_t)); 2028da6c28aaSamw } 2029da6c28aaSamw } 2030da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 2031da6c28aaSamw vsecp->vsa_aclflags = 0; 2032da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_DEFAULTED) 2033da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 2034da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_PROTECTED) 2035da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 2036da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_ACL_AUTO_INHERIT) 2037da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 2038fa9e4066Sahrens } 2039fa9e4066Sahrens 2040fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2041fa9e4066Sahrens 2042fa9e4066Sahrens return (0); 2043fa9e4066Sahrens } 2044fa9e4066Sahrens 2045da6c28aaSamw int 2046da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 204789459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 2048da6c28aaSamw { 2049da6c28aaSamw zfs_acl_t *aclp; 2050da6c28aaSamw zfs_acl_node_t *aclnode; 2051da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 2052da6c28aaSamw int error; 2053da6c28aaSamw 2054da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 2055da6c28aaSamw return (EINVAL); 2056da6c28aaSamw 2057da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 2058da6c28aaSamw 2059da6c28aaSamw aclp->z_hints = 0; 2060da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 2061da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 2062da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 2063da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 2064da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 2065da6c28aaSamw zfs_acl_free(aclp); 2066da6c28aaSamw zfs_acl_node_free(aclnode); 2067da6c28aaSamw return (error); 2068da6c28aaSamw } 2069da6c28aaSamw } else { 207089459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 2071da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 207289459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 2073da6c28aaSamw zfs_acl_free(aclp); 2074da6c28aaSamw zfs_acl_node_free(aclnode); 2075da6c28aaSamw return (error); 2076da6c28aaSamw } 2077da6c28aaSamw } 2078da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 2079da6c28aaSamw aclnode->z_ace_count = aclcnt; 2080da6c28aaSamw aclp->z_acl_count = aclcnt; 2081da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 2082da6c28aaSamw 2083da6c28aaSamw /* 2084da6c28aaSamw * If flags are being set then add them to z_hints 2085da6c28aaSamw */ 2086da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 2087da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 2088da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 2089da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 2090da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 2091da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 2092da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 2093da6c28aaSamw } 2094da6c28aaSamw 2095da6c28aaSamw *zaclp = aclp; 2096da6c28aaSamw 2097da6c28aaSamw return (0); 2098da6c28aaSamw } 2099da6c28aaSamw 2100fa9e4066Sahrens /* 2101fa9e4066Sahrens * Set a files ACL 2102fa9e4066Sahrens */ 2103fa9e4066Sahrens int 2104da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 2105fa9e4066Sahrens { 2106fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2107fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 2108fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 2109fa9e4066Sahrens dmu_tx_t *tx; 2110fa9e4066Sahrens int error; 2111fa9e4066Sahrens zfs_acl_t *aclp; 2112da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 211389459e17SMark Shellenbaum boolean_t fuid_dirtied; 2114fa9e4066Sahrens 2115fa9e4066Sahrens if (mask == 0) 21167106075aSmarks return (ENOSYS); 2117fa9e4066Sahrens 2118da6c28aaSamw if (zp->z_phys->zp_flags & ZFS_IMMUTABLE) 2119da6c28aaSamw return (EPERM); 2120da6c28aaSamw 2121da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 2122da6c28aaSamw return (error); 2123da6c28aaSamw 212489459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 212589459e17SMark Shellenbaum &aclp); 2126da6c28aaSamw if (error) 2127da6c28aaSamw return (error); 2128da6c28aaSamw 2129da6c28aaSamw /* 2130da6c28aaSamw * If ACL wide flags aren't being set then preserve any 2131da6c28aaSamw * existing flags. 2132da6c28aaSamw */ 2133da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 2134da6c28aaSamw aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS); 2135da6c28aaSamw } 2136fa9e4066Sahrens top: 2137fa9e4066Sahrens mutex_enter(&zp->z_lock); 2138fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2139fa9e4066Sahrens 2140fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 2141fa9e4066Sahrens dmu_tx_hold_bonus(tx, zp->z_id); 2142fa9e4066Sahrens 2143fa9e4066Sahrens if (zp->z_phys->zp_acl.z_acl_extern_obj) { 2144da6c28aaSamw /* Are we upgrading ACL? */ 2145da6c28aaSamw if (zfsvfs->z_version <= ZPL_VERSION_FUID && 2146da6c28aaSamw zp->z_phys->zp_acl.z_acl_version == 2147da6c28aaSamw ZFS_ACL_VERSION_INITIAL) { 2148da6c28aaSamw dmu_tx_hold_free(tx, 2149da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, 2150da6c28aaSamw 0, DMU_OBJECT_END); 2151da6c28aaSamw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 21524c841f60Smarks 0, aclp->z_acl_bytes); 2153da6c28aaSamw } else { 2154da6c28aaSamw dmu_tx_hold_write(tx, 2155da6c28aaSamw zp->z_phys->zp_acl.z_acl_extern_obj, 2156da6c28aaSamw 0, aclp->z_acl_bytes); 2157da6c28aaSamw } 2158da6c28aaSamw } else if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 2159da6c28aaSamw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 2160da6c28aaSamw } 216189459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 216214843421SMatthew Ahrens if (fuid_dirtied) 216314843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 2164fa9e4066Sahrens 21651209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 2166fa9e4066Sahrens if (error) { 2167fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2168fa9e4066Sahrens mutex_exit(&zp->z_lock); 2169fa9e4066Sahrens 21701209a471SNeil Perrin if (error == ERESTART) { 21718a2f1b91Sahrens dmu_tx_wait(tx); 21728a2f1b91Sahrens dmu_tx_abort(tx); 2173fa9e4066Sahrens goto top; 2174fa9e4066Sahrens } 21758a2f1b91Sahrens dmu_tx_abort(tx); 2176da6c28aaSamw zfs_acl_free(aclp); 2177fa9e4066Sahrens return (error); 2178fa9e4066Sahrens } 2179fa9e4066Sahrens 218089459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2181fa9e4066Sahrens ASSERT(error == 0); 2182*4929fd5eSTim Haley zp->z_acl_cached = aclp; 2183fa9e4066Sahrens 218489459e17SMark Shellenbaum if (fuid_dirtied) 218589459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 218689459e17SMark Shellenbaum 218789459e17SMark Shellenbaum zfs_time_stamper_locked(zp, STATE_CHANGED, tx); 2188da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2189da6c28aaSamw 2190da6c28aaSamw if (fuidp) 2191da6c28aaSamw zfs_fuid_info_free(fuidp); 2192fa9e4066Sahrens dmu_tx_commit(tx); 2193fa9e4066Sahrens done: 2194fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2195fa9e4066Sahrens mutex_exit(&zp->z_lock); 2196fa9e4066Sahrens 2197fa9e4066Sahrens return (error); 2198fa9e4066Sahrens } 2199fa9e4066Sahrens 2200da6c28aaSamw /* 2201e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2202e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2203e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2204da6c28aaSamw */ 2205fa9e4066Sahrens static int 2206e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2207fa9e4066Sahrens { 2208fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2209fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2210f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2211f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2212fa9e4066Sahrens return (EROFS); 2213fa9e4066Sahrens } 2214fa9e4066Sahrens 2215da6c28aaSamw /* 2216da6c28aaSamw * Only check for READONLY on non-directories. 2217da6c28aaSamw */ 2218da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2219da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 2220da6c28aaSamw (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2221da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 2222da6c28aaSamw (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) { 2223da6c28aaSamw return (EPERM); 2224da6c28aaSamw } 2225da6c28aaSamw 2226da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 2227da6c28aaSamw (zp->z_phys->zp_flags & ZFS_NOUNLINK)) { 2228da6c28aaSamw return (EPERM); 2229da6c28aaSamw } 2230da6c28aaSamw 2231da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 2232da6c28aaSamw (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) { 2233da6c28aaSamw return (EACCES); 2234da6c28aaSamw } 2235da6c28aaSamw 2236e802abbdSTim Haley return (0); 2237e802abbdSTim Haley } 2238e802abbdSTim Haley 2239e802abbdSTim Haley /* 2240e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2241e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2242e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2243e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2244e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2245e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2246e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2247e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2248e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2249e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2250e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2251e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2252e802abbdSTim Haley * accesses. Returns: 2253e802abbdSTim Haley * 0 if all AoI granted 2254e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2255e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2256e802abbdSTim Haley * 2257e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2258e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2259e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2260e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2261e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2262e802abbdSTim Haley * is used in this manner. 2263e802abbdSTim Haley */ 2264e802abbdSTim Haley static int 2265e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2266e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2267e802abbdSTim Haley { 2268e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2269e802abbdSTim Haley zfs_acl_t *aclp; 2270e802abbdSTim Haley int error; 2271e802abbdSTim Haley uid_t uid = crgetuid(cr); 2272e802abbdSTim Haley uint64_t who; 2273e802abbdSTim Haley uint16_t type, iflags; 2274e802abbdSTim Haley uint16_t entry_type; 2275e802abbdSTim Haley uint32_t access_mask; 2276e802abbdSTim Haley uint32_t deny_mask = 0; 2277e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2278e802abbdSTim Haley boolean_t checkit; 2279e802abbdSTim Haley uid_t fowner; 2280e802abbdSTim Haley uid_t gowner; 2281da6c28aaSamw 2282bda89588Sjp zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 2283da6c28aaSamw 2284fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2285fa9e4066Sahrens 2286da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 2287ea8dc4b6Seschrock if (error != 0) { 2288ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2289ea8dc4b6Seschrock return (error); 2290ea8dc4b6Seschrock } 2291ea8dc4b6Seschrock 2292da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2293da6c28aaSamw &iflags, &type)) { 2294e802abbdSTim Haley uint32_t mask_matched; 2295fa9e4066Sahrens 2296003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2297003c2582SMark Shellenbaum continue; 2298003c2582SMark Shellenbaum 2299b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2300da6c28aaSamw continue; 2301fa9e4066Sahrens 2302e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2303e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2304e802abbdSTim Haley if (!mask_matched) 2305e802abbdSTim Haley continue; 2306e802abbdSTim Haley 2307da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2308169cdae2Smarks 2309da6c28aaSamw checkit = B_FALSE; 2310fa9e4066Sahrens 2311fa9e4066Sahrens switch (entry_type) { 2312fa9e4066Sahrens case ACE_OWNER: 2313da6c28aaSamw if (uid == fowner) 2314da6c28aaSamw checkit = B_TRUE; 2315fa9e4066Sahrens break; 2316da6c28aaSamw case OWNING_GROUP: 2317da6c28aaSamw who = gowner; 2318da6c28aaSamw /*FALLTHROUGH*/ 2319fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2320da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2321fa9e4066Sahrens break; 2322fa9e4066Sahrens case ACE_EVERYONE: 2323da6c28aaSamw checkit = B_TRUE; 2324fa9e4066Sahrens break; 2325fa9e4066Sahrens 2326fa9e4066Sahrens /* USER Entry */ 2327fa9e4066Sahrens default: 2328fa9e4066Sahrens if (entry_type == 0) { 2329da6c28aaSamw uid_t newid; 2330da6c28aaSamw 2331e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2332e0d35c44Smarks ZFS_ACE_USER); 2333da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2334da6c28aaSamw uid == newid) 2335da6c28aaSamw checkit = B_TRUE; 2336fa9e4066Sahrens break; 2337da6c28aaSamw } else { 2338da6c28aaSamw mutex_exit(&zp->z_acl_lock); 2339da6c28aaSamw return (EIO); 2340da6c28aaSamw } 2341da6c28aaSamw } 2342da6c28aaSamw 2343da6c28aaSamw if (checkit) { 2344e802abbdSTim Haley if (type == DENY) { 2345e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2346e802abbdSTim Haley znode_t *, zp, 2347e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2348e802abbdSTim Haley uint32_t, mask_matched); 2349e802abbdSTim Haley deny_mask |= mask_matched; 2350e802abbdSTim Haley } else { 2351e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2352e802abbdSTim Haley znode_t *, zp, 2353e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2354e802abbdSTim Haley uint32_t, mask_matched); 2355e802abbdSTim Haley if (anyaccess) { 2356e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2357e802abbdSTim Haley return (0); 2358e802abbdSTim Haley } 2359fa9e4066Sahrens } 2360e802abbdSTim Haley *working_mode &= ~mask_matched; 2361fa9e4066Sahrens } 2362fa9e4066Sahrens 236390fafcf0Smarks /* Are we done? */ 236490fafcf0Smarks if (*working_mode == 0) 2365fa9e4066Sahrens break; 2366fa9e4066Sahrens } 2367fa9e4066Sahrens 2368fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 236990fafcf0Smarks 237090fafcf0Smarks /* Put the found 'denies' back on the working mode */ 23717ed7e920Smarks if (deny_mask) { 23727ed7e920Smarks *working_mode |= deny_mask; 237390fafcf0Smarks return (EACCES); 23747ed7e920Smarks } else if (*working_mode) { 23757ed7e920Smarks return (-1); 23767ed7e920Smarks } 237790fafcf0Smarks 237890fafcf0Smarks return (0); 2379fa9e4066Sahrens } 2380fa9e4066Sahrens 2381e802abbdSTim Haley /* 2382e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2383e802abbdSTim Haley * care what access is granted. 2384e802abbdSTim Haley */ 2385e802abbdSTim Haley boolean_t 2386e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2387e802abbdSTim Haley { 2388e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2389e802abbdSTim Haley 2390e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2391e802abbdSTim Haley uid_t owner; 2392e802abbdSTim Haley 2393e802abbdSTim Haley owner = zfs_fuid_map_id(zp->z_zfsvfs, 2394e802abbdSTim Haley zp->z_phys->zp_uid, cr, ZFS_OWNER); 2395e802abbdSTim Haley 2396e802abbdSTim Haley return ( 2397e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VREAD) == 0 || 2398e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VWRITE) == 0 || 2399e802abbdSTim Haley secpolicy_vnode_access(cr, ZTOV(zp), owner, VEXEC) == 0 || 2400e02bc683SMark Shellenbaum secpolicy_vnode_chown(cr, owner) == 0 || 2401e802abbdSTim Haley secpolicy_vnode_setdac(cr, owner) == 0 || 2402e802abbdSTim Haley secpolicy_vnode_remove(cr) == 0); 2403e802abbdSTim Haley } 2404e802abbdSTim Haley return (B_TRUE); 2405e802abbdSTim Haley } 2406e802abbdSTim Haley 2407e802abbdSTim Haley static int 2408e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2409e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2410e802abbdSTim Haley { 2411e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2412e802abbdSTim Haley int err; 2413e802abbdSTim Haley 2414e802abbdSTim Haley *working_mode = v4_mode; 2415e802abbdSTim Haley *check_privs = B_TRUE; 2416e802abbdSTim Haley 2417e802abbdSTim Haley /* 2418e802abbdSTim Haley * Short circuit empty requests 2419e802abbdSTim Haley */ 2420e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2421e802abbdSTim Haley *working_mode = 0; 2422e802abbdSTim Haley return (0); 2423e802abbdSTim Haley } 2424e802abbdSTim Haley 2425e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2426e802abbdSTim Haley *check_privs = B_FALSE; 2427e802abbdSTim Haley return (err); 2428e802abbdSTim Haley } 2429e802abbdSTim Haley 2430e802abbdSTim Haley /* 2431e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2432e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2433e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2434e802abbdSTim Haley */ 2435e802abbdSTim Haley if (skipaclchk) { 2436e802abbdSTim Haley *working_mode = 0; 2437e802abbdSTim Haley return (0); 2438e802abbdSTim Haley } 2439e802abbdSTim Haley 2440e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2441e802abbdSTim Haley } 2442e802abbdSTim Haley 2443da6c28aaSamw static int 2444da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2445da6c28aaSamw cred_t *cr) 2446da6c28aaSamw { 2447da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2448da6c28aaSamw return (EACCES); 2449da6c28aaSamw 2450da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2451da6c28aaSamw check_privs, B_FALSE, cr)); 2452da6c28aaSamw } 2453fa9e4066Sahrens 2454d47621a4STim Haley int 2455d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2456d47621a4STim Haley { 2457d47621a4STim Haley boolean_t owner = B_FALSE; 2458d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2459d47621a4STim Haley boolean_t is_attr; 2460d47621a4STim Haley uid_t fowner; 2461d47621a4STim Haley uid_t gowner; 2462d47621a4STim Haley uid_t uid = crgetuid(cr); 2463d47621a4STim Haley int error; 2464d47621a4STim Haley 2465d47621a4STim Haley if (zdp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 2466d47621a4STim Haley return (EACCES); 2467d47621a4STim Haley 2468d47621a4STim Haley is_attr = ((zdp->z_phys->zp_flags & ZFS_XATTR) && 2469d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2470d47621a4STim Haley if (is_attr) 2471d47621a4STim Haley goto slow; 2472d47621a4STim Haley 2473d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2474d47621a4STim Haley 2475d47621a4STim Haley if (zdp->z_phys->zp_flags & ZFS_NO_EXECS_DENIED) { 2476d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2477d47621a4STim Haley return (0); 2478d47621a4STim Haley } 2479d47621a4STim Haley 2480d47621a4STim Haley if (FUID_INDEX(zdp->z_phys->zp_uid) != 0 || 2481d47621a4STim Haley FUID_INDEX(zdp->z_phys->zp_gid) != 0) { 2482d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2483d47621a4STim Haley goto slow; 2484d47621a4STim Haley } 2485d47621a4STim Haley 2486d47621a4STim Haley fowner = (uid_t)zdp->z_phys->zp_uid; 2487d47621a4STim Haley gowner = (uid_t)zdp->z_phys->zp_gid; 2488d47621a4STim Haley 2489d47621a4STim Haley if (uid == fowner) { 2490d47621a4STim Haley owner = B_TRUE; 2491d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXUSR) { 2492d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2493d47621a4STim Haley return (0); 2494d47621a4STim Haley } 2495d47621a4STim Haley } 2496d47621a4STim Haley if (groupmember(gowner, cr)) { 2497d47621a4STim Haley groupmbr = B_TRUE; 2498d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXGRP) { 2499d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2500d47621a4STim Haley return (0); 2501d47621a4STim Haley } 2502d47621a4STim Haley } 2503d47621a4STim Haley if (!owner && !groupmbr) { 2504d47621a4STim Haley if (zdp->z_phys->zp_mode & S_IXOTH) { 2505d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2506d47621a4STim Haley return (0); 2507d47621a4STim Haley } 2508d47621a4STim Haley } 2509d47621a4STim Haley 2510d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2511d47621a4STim Haley 2512d47621a4STim Haley slow: 2513d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2514d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2515d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2516d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2517d47621a4STim Haley return (error); 2518d47621a4STim Haley } 2519d47621a4STim Haley 2520fa9e4066Sahrens /* 2521fa9e4066Sahrens * Determine whether Access should be granted/denied, invoking least 2522fa9e4066Sahrens * priv subsytem when a deny is determined. 2523fa9e4066Sahrens */ 2524fa9e4066Sahrens int 2525da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2526fa9e4066Sahrens { 2527da6c28aaSamw uint32_t working_mode; 2528da6c28aaSamw int error; 2529da6c28aaSamw int is_attr; 2530da6c28aaSamw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2531da6c28aaSamw boolean_t check_privs; 2532da6c28aaSamw znode_t *xzp; 2533da6c28aaSamw znode_t *check_zp = zp; 2534fa9e4066Sahrens 2535fa9e4066Sahrens is_attr = ((zp->z_phys->zp_flags & ZFS_XATTR) && 2536fa9e4066Sahrens (ZTOV(zp)->v_type == VDIR)); 2537fa9e4066Sahrens 2538fa9e4066Sahrens /* 2539fa9e4066Sahrens * If attribute then validate against base file 2540fa9e4066Sahrens */ 2541fa9e4066Sahrens if (is_attr) { 2542fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 2543fa9e4066Sahrens zp->z_phys->zp_parent, &xzp)) != 0) { 2544fa9e4066Sahrens return (error); 2545fa9e4066Sahrens } 2546da6c28aaSamw 2547fa9e4066Sahrens check_zp = xzp; 2548da6c28aaSamw 2549fa9e4066Sahrens /* 2550fa9e4066Sahrens * fixup mode to map to xattr perms 2551fa9e4066Sahrens */ 2552fa9e4066Sahrens 2553fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2554fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2555fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2556fa9e4066Sahrens } 2557fa9e4066Sahrens 2558fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2559fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2560fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2561fa9e4066Sahrens } 2562fa9e4066Sahrens } 2563fa9e4066Sahrens 2564da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2565da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2566da6c28aaSamw if (is_attr) 2567da6c28aaSamw VN_RELE(ZTOV(xzp)); 2568da6c28aaSamw return (0); 2569da6c28aaSamw } 2570fa9e4066Sahrens 2571e0d35c44Smarks if (error && !check_privs) { 2572fa9e4066Sahrens if (is_attr) 2573fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2574fa9e4066Sahrens return (error); 2575fa9e4066Sahrens } 2576fa9e4066Sahrens 2577da6c28aaSamw if (error && (flags & V_APPEND)) { 2578da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2579da6c28aaSamw } 2580da6c28aaSamw 2581da6c28aaSamw if (error && check_privs) { 2582da6c28aaSamw uid_t owner; 2583da6c28aaSamw mode_t checkmode = 0; 2584da6c28aaSamw 2585e0d35c44Smarks owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, cr, 2586e0d35c44Smarks ZFS_OWNER); 2587da6c28aaSamw 2588da6c28aaSamw /* 2589da6c28aaSamw * First check for implicit owner permission on 2590da6c28aaSamw * read_acl/read_attributes 2591da6c28aaSamw */ 2592da6c28aaSamw 2593da6c28aaSamw error = 0; 2594da6c28aaSamw ASSERT(working_mode != 0); 2595da6c28aaSamw 2596da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2597da6c28aaSamw owner == crgetuid(cr))) 2598da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2599da6c28aaSamw 2600da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 260147def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2602da6c28aaSamw checkmode |= VREAD; 2603da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 260447def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2605da6c28aaSamw checkmode |= VWRITE; 2606da6c28aaSamw if (working_mode & ACE_EXECUTE) 2607da6c28aaSamw checkmode |= VEXEC; 2608da6c28aaSamw 2609da6c28aaSamw if (checkmode) 2610da6c28aaSamw error = secpolicy_vnode_access(cr, ZTOV(check_zp), 2611da6c28aaSamw owner, checkmode); 2612da6c28aaSamw 2613da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2614e02bc683SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 2615da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2616da6c28aaSamw error = secpolicy_vnode_setdac(cr, owner); 2617da6c28aaSamw 2618da6c28aaSamw if (error == 0 && (working_mode & 2619da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2620da6c28aaSamw error = secpolicy_vnode_remove(cr); 2621da6c28aaSamw 262247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2623e02bc683SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 262447def0dcSMark Shellenbaum } 2625da6c28aaSamw if (error == 0) { 2626da6c28aaSamw /* 2627da6c28aaSamw * See if any bits other than those already checked 2628da6c28aaSamw * for are still present. If so then return EACCES 2629da6c28aaSamw */ 2630da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2631da6c28aaSamw error = EACCES; 2632da6c28aaSamw } 2633da6c28aaSamw } 2634fa9e4066Sahrens } 2635fa9e4066Sahrens 2636fa9e4066Sahrens if (is_attr) 2637fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2638fa9e4066Sahrens 2639fa9e4066Sahrens return (error); 2640fa9e4066Sahrens } 2641fa9e4066Sahrens 2642fa9e4066Sahrens /* 2643da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2644da6c28aaSamw * native ACL format and call zfs_zaccess() 2645fa9e4066Sahrens */ 2646fa9e4066Sahrens int 2647da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2648fa9e4066Sahrens { 2649da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2650fa9e4066Sahrens } 2651fa9e4066Sahrens 2652fa9e4066Sahrens /* 2653da6c28aaSamw * Access function for secpolicy_vnode_setattr 2654fa9e4066Sahrens */ 2655fa9e4066Sahrens int 2656da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2657fa9e4066Sahrens { 2658fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2659fa9e4066Sahrens 2660da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2661fa9e4066Sahrens } 2662fa9e4066Sahrens 266347db7e74Smarks static int 266423d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 266523d5bb1fSmarks mode_t missing_perms, cred_t *cr) 266647db7e74Smarks { 266747db7e74Smarks int error; 2668da6c28aaSamw uid_t downer; 2669da6c28aaSamw zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2670da6c28aaSamw 2671e0d35c44Smarks downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER); 267247db7e74Smarks 267323d5bb1fSmarks error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms); 267447db7e74Smarks 267547db7e74Smarks if (error == 0) 267647db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 267747db7e74Smarks 267847db7e74Smarks return (error); 267947db7e74Smarks } 268047db7e74Smarks 2681fa9e4066Sahrens /* 2682fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2683fa9e4066Sahrens * consulting least priv subsystem. 2684fa9e4066Sahrens * 2685fa9e4066Sahrens * 2686fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2687fa9e4066Sahrens * ability to delete an object. 2688fa9e4066Sahrens * 2689fa9e4066Sahrens * ------------------------------------------------------- 2690fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2691fa9e4066Sahrens * | permissions | | 2692fa9e4066Sahrens * ------------------------------------------------------- 2693fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2694fa9e4066Sahrens * | | Delete | Delete | unspecified| 2695fa9e4066Sahrens * ------------------------------------------------------- 2696fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2697fa9e4066Sahrens * | DELETE_CHILD | | 2698fa9e4066Sahrens * ------------------------------------------------------- 2699fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2700fa9e4066Sahrens * | DELETE_CHILD | | | | 2701fa9e4066Sahrens * ------------------------------------------------------- 2702fa9e4066Sahrens * | ACL specifies | | | | 2703fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2704fa9e4066Sahrens * | write and | | | | 2705fa9e4066Sahrens * | execute | | | | 2706fa9e4066Sahrens * ------------------------------------------------------- 2707fa9e4066Sahrens * | ACL denies | | | | 2708fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2709fa9e4066Sahrens * | execute | | | | 2710fa9e4066Sahrens * ------------------------------------------------------- 2711fa9e4066Sahrens * ^ 2712fa9e4066Sahrens * | 2713fa9e4066Sahrens * No search privilege, can't even look up file? 2714fa9e4066Sahrens * 2715fa9e4066Sahrens */ 2716fa9e4066Sahrens int 2717fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2718fa9e4066Sahrens { 2719da6c28aaSamw uint32_t dzp_working_mode = 0; 2720da6c28aaSamw uint32_t zp_working_mode = 0; 2721fa9e4066Sahrens int dzp_error, zp_error; 272223d5bb1fSmarks mode_t missing_perms; 2723da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2724da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2725fa9e4066Sahrens 2726fa9e4066Sahrens /* 272723d5bb1fSmarks * We want specific DELETE permissions to 2728fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2729fa9e4066Sahrens * want an ACL such as this to mess us up. 273047db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2731fa9e4066Sahrens * 2732fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2733fa9e4066Sahrens * by secpolicy_vnode_access(). 273423d5bb1fSmarks * 273523d5bb1fSmarks * We will ask for all of the necessary permissions and then 273623d5bb1fSmarks * look at the working modes from the directory and target object 273723d5bb1fSmarks * to determine what was found. 2738fa9e4066Sahrens */ 2739fa9e4066Sahrens 2740da6c28aaSamw if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2741da6c28aaSamw return (EPERM); 2742da6c28aaSamw 274323d5bb1fSmarks /* 27447ed7e920Smarks * First row 274523d5bb1fSmarks * If the directory permissions allow the delete, we are done. 274623d5bb1fSmarks */ 27477ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 274823d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 274923d5bb1fSmarks return (0); 2750fa9e4066Sahrens 275123d5bb1fSmarks /* 275223d5bb1fSmarks * If target object has delete permission then we are done 275323d5bb1fSmarks */ 275423d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 275523d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 275623d5bb1fSmarks return (0); 275723d5bb1fSmarks 27587ed7e920Smarks ASSERT(dzp_error && zp_error); 27597ed7e920Smarks 276023d5bb1fSmarks if (!dzpcheck_privs) 2761fa9e4066Sahrens return (dzp_error); 27627ed7e920Smarks if (!zpcheck_privs) 276323d5bb1fSmarks return (zp_error); 2764fa9e4066Sahrens 2765fa9e4066Sahrens /* 2766fa9e4066Sahrens * Second row 27677ed7e920Smarks * 27687ed7e920Smarks * If directory returns EACCES then delete_child was denied 27697ed7e920Smarks * due to deny delete_child. In this case send the request through 27707ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 27717ed7e920Smarks * since that *could* allow the delete based on write/execute permission 27727ed7e920Smarks * and we want delete permissions to override write/execute. 277347db7e74Smarks */ 277447db7e74Smarks 277547db7e74Smarks if (dzp_error == EACCES) 27767ed7e920Smarks return (secpolicy_vnode_remove(cr)); 277747db7e74Smarks 2778fa9e4066Sahrens /* 2779fa9e4066Sahrens * Third Row 278023d5bb1fSmarks * only need to see if we have write/execute on directory. 2781fa9e4066Sahrens */ 2782fa9e4066Sahrens 27837ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 27847ed7e920Smarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 278547db7e74Smarks return (zfs_sticky_remove_access(dzp, zp, cr)); 2786fa9e4066Sahrens 27877ed7e920Smarks if (!dzpcheck_privs) 27887ed7e920Smarks return (dzp_error); 27897ed7e920Smarks 2790fa9e4066Sahrens /* 27917ed7e920Smarks * Fourth row 2792fa9e4066Sahrens */ 2793fa9e4066Sahrens 27947ed7e920Smarks missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0; 27957ed7e920Smarks missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0; 27967ed7e920Smarks 27977ed7e920Smarks ASSERT(missing_perms); 2798fa9e4066Sahrens 279923d5bb1fSmarks return (zfs_delete_final_check(zp, dzp, missing_perms, cr)); 28007ed7e920Smarks 2801fa9e4066Sahrens } 2802fa9e4066Sahrens 2803fa9e4066Sahrens int 2804fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2805fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2806fa9e4066Sahrens { 2807fa9e4066Sahrens int add_perm; 2808fa9e4066Sahrens int error; 2809fa9e4066Sahrens 2810da6c28aaSamw if (szp->z_phys->zp_flags & ZFS_AV_QUARANTINED) 2811da6c28aaSamw return (EACCES); 2812da6c28aaSamw 2813fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2814fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2815fa9e4066Sahrens 2816fa9e4066Sahrens /* 2817fa9e4066Sahrens * Rename permissions are combination of delete permission + 2818fa9e4066Sahrens * add file/subdir permission. 2819fa9e4066Sahrens */ 2820fa9e4066Sahrens 2821fa9e4066Sahrens /* 2822fa9e4066Sahrens * first make sure we do the delete portion. 2823fa9e4066Sahrens * 2824fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2825fa9e4066Sahrens */ 2826fa9e4066Sahrens 2827fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2828fa9e4066Sahrens return (error); 2829fa9e4066Sahrens 2830fa9e4066Sahrens /* 2831fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2832fa9e4066Sahrens */ 2833fa9e4066Sahrens if (tzp) { 2834fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2835fa9e4066Sahrens return (error); 2836fa9e4066Sahrens } 2837fa9e4066Sahrens 2838fa9e4066Sahrens /* 2839fa9e4066Sahrens * Now check for add permissions 2840fa9e4066Sahrens */ 2841da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2842fa9e4066Sahrens 2843fa9e4066Sahrens return (error); 2844fa9e4066Sahrens } 2845