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 /* 2227dd1e87SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23fa9e4066Sahrens */ 24fa9e4066Sahrens 25fa9e4066Sahrens #include <sys/types.h> 26fa9e4066Sahrens #include <sys/param.h> 27fa9e4066Sahrens #include <sys/time.h> 28fa9e4066Sahrens #include <sys/systm.h> 29fa9e4066Sahrens #include <sys/sysmacros.h> 30fa9e4066Sahrens #include <sys/resource.h> 31fa9e4066Sahrens #include <sys/vfs.h> 32fa9e4066Sahrens #include <sys/vnode.h> 33da6c28aaSamw #include <sys/sid.h> 34fa9e4066Sahrens #include <sys/file.h> 35fa9e4066Sahrens #include <sys/stat.h> 36fa9e4066Sahrens #include <sys/kmem.h> 37fa9e4066Sahrens #include <sys/cmn_err.h> 38fa9e4066Sahrens #include <sys/errno.h> 39fa9e4066Sahrens #include <sys/unistd.h> 40169cdae2Smarks #include <sys/sdt.h> 41fa9e4066Sahrens #include <sys/fs/zfs.h> 42fa9e4066Sahrens #include <sys/mode.h> 43fa9e4066Sahrens #include <sys/policy.h> 44fa9e4066Sahrens #include <sys/zfs_znode.h> 45da6c28aaSamw #include <sys/zfs_fuid.h> 46fa9e4066Sahrens #include <sys/zfs_acl.h> 47fa9e4066Sahrens #include <sys/zfs_dir.h> 48fa9e4066Sahrens #include <sys/zfs_vfsops.h> 49fa9e4066Sahrens #include <sys/dmu.h> 50da6c28aaSamw #include <sys/dnode.h> 51fa9e4066Sahrens #include <sys/zap.h> 520a586ceaSMark Shellenbaum #include <sys/sa.h> 53fa9e4066Sahrens #include "fs/fs_subr.h" 54fa9e4066Sahrens #include <acl/acl_common.h> 55fa9e4066Sahrens 56fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 57fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 58da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 59003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW 60fa9e4066Sahrens 61fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 62fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 63fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 64fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 65fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 66fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 67fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 68da6c28aaSamw 69da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 70da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 71da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 72da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 73da6c28aaSamw 74f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS) 75f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \ 76f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD) 77f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS) 78fa9e4066Sahrens 79fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 80fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 81fa9e4066Sahrens 82fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 83fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 84fa9e4066Sahrens 85fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \ 86da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE) 87fa9e4066Sahrens 88b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER) 89fa9e4066Sahrens 90da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\ 91da6c28aaSamw ZFS_ACL_PROTECTED) 92fa9e4066Sahrens 93da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 94da6c28aaSamw ZFS_ACL_OBJ_ACE) 95da6c28aaSamw 964929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) 974929fd5eSTim 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 } 109da6c28aaSamw 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 3240a586ceaSMark Shellenbaum /* 3250a586ceaSMark Shellenbaum * The following three functions are provided for compatibility with 3260a586ceaSMark Shellenbaum * older ZPL version in order to determine if the file use to have 3270a586ceaSMark Shellenbaum * an external ACL and what version of ACL previously existed on the 3280a586ceaSMark Shellenbaum * file. Would really be nice to not need this, sigh. 3290a586ceaSMark Shellenbaum */ 3300a586ceaSMark Shellenbaum 3310a586ceaSMark Shellenbaum uint64_t 3320a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp) 3330a586ceaSMark Shellenbaum { 3340a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 3350a586ceaSMark Shellenbaum 3360a586ceaSMark Shellenbaum if (zp->z_is_sa) 3370a586ceaSMark Shellenbaum return (0); 3380a586ceaSMark Shellenbaum 3390a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 3400a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))); 3410a586ceaSMark Shellenbaum 3420a586ceaSMark Shellenbaum return (acl_phys.z_acl_extern_obj); 3430a586ceaSMark Shellenbaum } 3440a586ceaSMark Shellenbaum 3450a586ceaSMark Shellenbaum /* 3460a586ceaSMark Shellenbaum * Determine size of ACL in bytes 3470a586ceaSMark Shellenbaum * 3480a586ceaSMark Shellenbaum * This is more complicated than it should be since we have to deal 3490a586ceaSMark Shellenbaum * with old external ACLs. 3500a586ceaSMark Shellenbaum */ 3510a586ceaSMark Shellenbaum static int 3520a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount, 3530a586ceaSMark Shellenbaum zfs_acl_phys_t *aclphys) 3540a586ceaSMark Shellenbaum { 3550a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs; 3560a586ceaSMark Shellenbaum uint64_t acl_count; 3570a586ceaSMark Shellenbaum int size; 3580a586ceaSMark Shellenbaum int error; 3590a586ceaSMark Shellenbaum 3600a586ceaSMark Shellenbaum if (zp->z_is_sa) { 3610a586ceaSMark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs), 3620a586ceaSMark Shellenbaum &size)) != 0) 3630a586ceaSMark Shellenbaum return (error); 3640a586ceaSMark Shellenbaum *aclsize = size; 3650a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs), 3660a586ceaSMark Shellenbaum &acl_count, sizeof (acl_count))) != 0) 3670a586ceaSMark Shellenbaum return (error); 3680a586ceaSMark Shellenbaum *aclcount = acl_count; 3690a586ceaSMark Shellenbaum } else { 3700a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 3710a586ceaSMark Shellenbaum aclphys, sizeof (*aclphys))) != 0) 3720a586ceaSMark Shellenbaum return (error); 3730a586ceaSMark Shellenbaum 3740a586ceaSMark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) { 3750a586ceaSMark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size); 3760a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_size; 3770a586ceaSMark Shellenbaum } else { 3780a586ceaSMark Shellenbaum *aclsize = aclphys->z_acl_size; 3790a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_count; 3800a586ceaSMark Shellenbaum } 3810a586ceaSMark Shellenbaum } 3820a586ceaSMark Shellenbaum return (0); 3830a586ceaSMark Shellenbaum } 3840a586ceaSMark Shellenbaum 3850a586ceaSMark Shellenbaum int 3860a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp) 3870a586ceaSMark Shellenbaum { 3880a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 3890a586ceaSMark Shellenbaum 3900a586ceaSMark Shellenbaum if (zp->z_is_sa) { 3910a586ceaSMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 3920a586ceaSMark Shellenbaum } else { 3930a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(zp->z_sa_hdl, 3940a586ceaSMark Shellenbaum SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 3950a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))); 3960a586ceaSMark Shellenbaum return (acl_phys.z_acl_version); 3970a586ceaSMark Shellenbaum } 3980a586ceaSMark Shellenbaum } 3990a586ceaSMark Shellenbaum 400da6c28aaSamw static int 401da6c28aaSamw zfs_acl_version(int version) 402da6c28aaSamw { 403da6c28aaSamw if (version < ZPL_VERSION_FUID) 404da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 405da6c28aaSamw else 406da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 407da6c28aaSamw } 408da6c28aaSamw 409da6c28aaSamw static int 410da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 411da6c28aaSamw { 412da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 413da6c28aaSamw } 414fa9e4066Sahrens 4150a586ceaSMark Shellenbaum zfs_acl_t * 416da6c28aaSamw zfs_acl_alloc(int vers) 417fa9e4066Sahrens { 418fa9e4066Sahrens zfs_acl_t *aclp; 419fa9e4066Sahrens 420fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 421da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 422da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 423da6c28aaSamw aclp->z_version = vers; 424da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 425da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 426da6c28aaSamw else 427da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 428fa9e4066Sahrens return (aclp); 429fa9e4066Sahrens } 430fa9e4066Sahrens 4310a586ceaSMark Shellenbaum zfs_acl_node_t * 432da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 433da6c28aaSamw { 434da6c28aaSamw zfs_acl_node_t *aclnode; 435da6c28aaSamw 436da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 437da6c28aaSamw if (bytes) { 438da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 439da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 440da6c28aaSamw aclnode->z_allocsize = bytes; 441da6c28aaSamw aclnode->z_size = bytes; 442da6c28aaSamw } 443da6c28aaSamw 444da6c28aaSamw return (aclnode); 445da6c28aaSamw } 446da6c28aaSamw 447da6c28aaSamw static void 448da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 449da6c28aaSamw { 450da6c28aaSamw if (aclnode->z_allocsize) 451da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 452da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 453da6c28aaSamw } 454da6c28aaSamw 4552459a9eaSmarks static void 4562459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 457fa9e4066Sahrens { 458da6c28aaSamw zfs_acl_node_t *aclnode; 459da6c28aaSamw 460da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 461da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 462da6c28aaSamw zfs_acl_node_free(aclnode); 463fa9e4066Sahrens } 4642459a9eaSmarks aclp->z_acl_count = 0; 4652459a9eaSmarks aclp->z_acl_bytes = 0; 4662459a9eaSmarks } 467da6c28aaSamw 4682459a9eaSmarks void 4692459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 4702459a9eaSmarks { 4712459a9eaSmarks zfs_acl_release_nodes(aclp); 472da6c28aaSamw list_destroy(&aclp->z_acl); 473fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 474fa9e4066Sahrens } 475fa9e4066Sahrens 476da6c28aaSamw static boolean_t 477003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 478003c2582SMark Shellenbaum { 479003c2582SMark Shellenbaum uint16_t entry_type; 480003c2582SMark Shellenbaum 481003c2582SMark Shellenbaum switch (type) { 482003c2582SMark Shellenbaum case ALLOW: 483003c2582SMark Shellenbaum case DENY: 484003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 485003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 486003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 487003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 488003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 489003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 490003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 491003c2582SMark Shellenbaum default: 492003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 493003c2582SMark Shellenbaum return (B_TRUE); 494003c2582SMark Shellenbaum } 495003c2582SMark Shellenbaum return (B_FALSE); 496003c2582SMark Shellenbaum } 497003c2582SMark Shellenbaum 498003c2582SMark Shellenbaum static boolean_t 499da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 500fa9e4066Sahrens { 501da6c28aaSamw /* 502da6c28aaSamw * first check type of entry 503da6c28aaSamw */ 504da6c28aaSamw 505003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 506da6c28aaSamw return (B_FALSE); 507da6c28aaSamw 508da6c28aaSamw switch (type) { 509da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 510da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 511da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 512da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 513da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 514da6c28aaSamw return (B_FALSE); 515da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 516da6c28aaSamw } 517da6c28aaSamw 518003c2582SMark Shellenbaum /* 519003c2582SMark Shellenbaum * next check inheritance level flags 520003c2582SMark Shellenbaum */ 521003c2582SMark Shellenbaum 522b249c65cSmarks if (obj_type == VDIR && 523b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 524da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 525da6c28aaSamw 526da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 527da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 528da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 529da6c28aaSamw return (B_FALSE); 530da6c28aaSamw } 531da6c28aaSamw } 532da6c28aaSamw 533da6c28aaSamw return (B_TRUE); 534da6c28aaSamw } 535da6c28aaSamw 536da6c28aaSamw static void * 537da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 538da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 539da6c28aaSamw { 540da6c28aaSamw zfs_acl_node_t *aclnode; 541da6c28aaSamw 5420a586ceaSMark Shellenbaum ASSERT(aclp); 5430a586ceaSMark Shellenbaum 544da6c28aaSamw if (start == NULL) { 545da6c28aaSamw aclnode = list_head(&aclp->z_acl); 546da6c28aaSamw if (aclnode == NULL) 547da6c28aaSamw return (NULL); 548da6c28aaSamw 549da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 550da6c28aaSamw aclp->z_curr_node = aclnode; 551da6c28aaSamw aclnode->z_ace_idx = 0; 552da6c28aaSamw } 553da6c28aaSamw 554da6c28aaSamw aclnode = aclp->z_curr_node; 555da6c28aaSamw 556da6c28aaSamw if (aclnode == NULL) 557da6c28aaSamw return (NULL); 558da6c28aaSamw 559da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 560da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 561da6c28aaSamw if (aclnode == NULL) 562da6c28aaSamw return (NULL); 563da6c28aaSamw else { 564da6c28aaSamw aclp->z_curr_node = aclnode; 565da6c28aaSamw aclnode->z_ace_idx = 0; 566da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 567da6c28aaSamw } 568da6c28aaSamw } 569da6c28aaSamw 570da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 571da6c28aaSamw void *acep = aclp->z_next_ace; 572003c2582SMark Shellenbaum size_t ace_size; 573003c2582SMark Shellenbaum 574003c2582SMark Shellenbaum /* 575003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 576003c2582SMark Shellenbaum */ 577003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 578003c2582SMark Shellenbaum 579003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 580003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 581003c2582SMark Shellenbaum return (NULL); 582003c2582SMark Shellenbaum } 583003c2582SMark Shellenbaum 584da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 585da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 586da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 587da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 588003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 589da6c28aaSamw aclnode->z_ace_idx++; 5900a586ceaSMark Shellenbaum 591da6c28aaSamw return ((void *)acep); 592da6c28aaSamw } 593da6c28aaSamw return (NULL); 594da6c28aaSamw } 595da6c28aaSamw 596da6c28aaSamw /*ARGSUSED*/ 597da6c28aaSamw static uint64_t 598da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 599da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 600da6c28aaSamw { 601da6c28aaSamw zfs_acl_t *aclp = datap; 602da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 603da6c28aaSamw uint64_t who; 604da6c28aaSamw 605da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 606da6c28aaSamw flags, type); 607da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 608da6c28aaSamw } 609da6c28aaSamw 610da6c28aaSamw static zfs_acl_node_t * 611da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 612da6c28aaSamw { 613da6c28aaSamw ASSERT(aclp->z_curr_node); 614da6c28aaSamw return (aclp->z_curr_node); 615da6c28aaSamw } 616da6c28aaSamw 617da6c28aaSamw /* 618da6c28aaSamw * Copy ACE to internal ZFS format. 619da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 620da6c28aaSamw * ACE FUIDs will be created later. 621da6c28aaSamw */ 622da6c28aaSamw int 62389459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 6240a586ceaSMark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size, 62589459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 626da6c28aaSamw { 627da6c28aaSamw int i; 628da6c28aaSamw uint16_t entry_type; 629da6c28aaSamw zfs_ace_t *aceptr = z_acl; 630da6c28aaSamw ace_t *acep = datap; 631da6c28aaSamw zfs_object_ace_t *zobjacep; 632da6c28aaSamw ace_object_t *aceobjp; 633da6c28aaSamw 634da6c28aaSamw for (i = 0; i != aclcnt; i++) { 635da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 636da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 637da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 638da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 639da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 6404c841f60Smarks entry_type != ACE_EVERYONE) { 64189459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 64289459e17SMark Shellenbaum cr, (entry_type == 0) ? 64389459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 6444c841f60Smarks } 6454c841f60Smarks 646da6c28aaSamw /* 647da6c28aaSamw * Make sure ACE is valid 648da6c28aaSamw */ 649da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 650da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 651da6c28aaSamw return (EINVAL); 652da6c28aaSamw 653da6c28aaSamw switch (acep->a_type) { 654da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 655da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 656da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 657da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 658da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 659da6c28aaSamw aceobjp = (ace_object_t *)acep; 660da6c28aaSamw 661da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 662da6c28aaSamw sizeof (aceobjp->a_obj_type)); 663da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 664da6c28aaSamw zobjacep->z_inherit_type, 665da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 666da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 667da6c28aaSamw break; 668da6c28aaSamw default: 669da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 670da6c28aaSamw } 671da6c28aaSamw 672da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 673da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 674da6c28aaSamw } 675da6c28aaSamw 676da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 677da6c28aaSamw 678da6c28aaSamw return (0); 679da6c28aaSamw } 680da6c28aaSamw 681da6c28aaSamw /* 682da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 683da6c28aaSamw */ 684da6c28aaSamw static void 685bda89588Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 686bda89588Sjp151216 void *datap, int filter) 687da6c28aaSamw { 688da6c28aaSamw uint64_t who; 689da6c28aaSamw uint32_t access_mask; 690da6c28aaSamw uint16_t iflags, type; 691da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 692da6c28aaSamw ace_t *acep = datap; 693da6c28aaSamw ace_object_t *objacep; 694da6c28aaSamw zfs_object_ace_t *zobjacep; 695da6c28aaSamw size_t ace_size; 696da6c28aaSamw uint16_t entry_type; 697da6c28aaSamw 698da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 699da6c28aaSamw &who, &access_mask, &iflags, &type)) { 700da6c28aaSamw 701da6c28aaSamw switch (type) { 702da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 703da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 704da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 705da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 706da6c28aaSamw if (filter) { 707da6c28aaSamw continue; 708da6c28aaSamw } 709da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 710da6c28aaSamw objacep = (ace_object_t *)acep; 711da6c28aaSamw bcopy(zobjacep->z_object_type, 712da6c28aaSamw objacep->a_obj_type, 713da6c28aaSamw sizeof (zobjacep->z_object_type)); 714da6c28aaSamw bcopy(zobjacep->z_inherit_type, 715da6c28aaSamw objacep->a_inherit_obj_type, 716da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 717da6c28aaSamw ace_size = sizeof (ace_object_t); 718da6c28aaSamw break; 719da6c28aaSamw default: 720da6c28aaSamw ace_size = sizeof (ace_t); 721da6c28aaSamw break; 722da6c28aaSamw } 723da6c28aaSamw 724da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 725da6c28aaSamw if ((entry_type != ACE_OWNER && 7261ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 727e0d35c44Smarks entry_type != ACE_EVERYONE)) { 728e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 729e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 730e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 731e0d35c44Smarks } else { 732da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 733e0d35c44Smarks } 734da6c28aaSamw acep->a_access_mask = access_mask; 735da6c28aaSamw acep->a_flags = iflags; 736da6c28aaSamw acep->a_type = type; 737da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 738da6c28aaSamw } 739da6c28aaSamw } 740da6c28aaSamw 741da6c28aaSamw static int 742da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 743da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 744da6c28aaSamw { 745da6c28aaSamw int i; 746da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 747da6c28aaSamw 748da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 749da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 750da6c28aaSamw aceptr->z_type = acep[i].a_type; 751da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 752da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 753da6c28aaSamw /* 754da6c28aaSamw * Make sure ACE is valid 755da6c28aaSamw */ 756da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 757da6c28aaSamw aceptr->z_flags) != B_TRUE) 758da6c28aaSamw return (EINVAL); 759da6c28aaSamw } 760da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 761da6c28aaSamw return (0); 762da6c28aaSamw } 763da6c28aaSamw 764da6c28aaSamw /* 765da6c28aaSamw * convert old ACL format to new 766da6c28aaSamw */ 767da6c28aaSamw void 76889459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 769da6c28aaSamw { 770da6c28aaSamw zfs_oldace_t *oldaclp; 771da6c28aaSamw int i; 772da6c28aaSamw uint16_t type, iflags; 773da6c28aaSamw uint32_t access_mask; 774da6c28aaSamw uint64_t who; 775da6c28aaSamw void *cookie = NULL; 7762459a9eaSmarks zfs_acl_node_t *newaclnode; 777da6c28aaSamw 778da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 779da6c28aaSamw /* 780da6c28aaSamw * First create the ACE in a contiguous piece of memory 781da6c28aaSamw * for zfs_copy_ace_2_fuid(). 782da6c28aaSamw * 783da6c28aaSamw * We only convert an ACL once, so this won't happen 784da6c28aaSamw * everytime. 785da6c28aaSamw */ 786da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 787da6c28aaSamw KM_SLEEP); 788da6c28aaSamw i = 0; 789da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 790da6c28aaSamw &access_mask, &iflags, &type)) { 791da6c28aaSamw oldaclp[i].z_flags = iflags; 792da6c28aaSamw oldaclp[i].z_type = type; 793da6c28aaSamw oldaclp[i].z_fuid = who; 794da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 795da6c28aaSamw } 796da6c28aaSamw 797da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 798da6c28aaSamw sizeof (zfs_object_ace_t)); 799da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 80089459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 80189459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 80289459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 803da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 804da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 805da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 806da6c28aaSamw 807da6c28aaSamw /* 808da6c28aaSamw * Release all previous ACL nodes 809da6c28aaSamw */ 810da6c28aaSamw 8112459a9eaSmarks zfs_acl_release_nodes(aclp); 8122459a9eaSmarks 813da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 8142459a9eaSmarks 8152459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 8162459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 8172459a9eaSmarks 818fa9e4066Sahrens } 819fa9e4066Sahrens 820fa9e4066Sahrens /* 821fa9e4066Sahrens * Convert unix access mask to v4 access mask 822fa9e4066Sahrens */ 823fa9e4066Sahrens static uint32_t 824fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 825fa9e4066Sahrens { 826fa9e4066Sahrens uint32_t new_mask = 0; 827fa9e4066Sahrens 828da6c28aaSamw if (access_mask & S_IXOTH) 829da6c28aaSamw new_mask |= ACE_EXECUTE; 830da6c28aaSamw if (access_mask & S_IWOTH) 831da6c28aaSamw new_mask |= ACE_WRITE_DATA; 832da6c28aaSamw if (access_mask & S_IROTH) 833fa9e4066Sahrens new_mask |= ACE_READ_DATA; 834fa9e4066Sahrens return (new_mask); 835fa9e4066Sahrens } 836fa9e4066Sahrens 837fa9e4066Sahrens static void 838da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 839da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 840fa9e4066Sahrens { 841da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 842da6c28aaSamw 843da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 844da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 845da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 8461ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 847da6c28aaSamw type != ACE_EVERYONE)) 848da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 849fa9e4066Sahrens } 850fa9e4066Sahrens 851da6c28aaSamw /* 852da6c28aaSamw * Determine mode of file based on ACL. 853da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 854da6c28aaSamw */ 8550a586ceaSMark Shellenbaum uint64_t 85627dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp, 85727dd1e87SMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid) 858fa9e4066Sahrens { 859fa9e4066Sahrens int entry_type; 860da6c28aaSamw mode_t mode; 861fa9e4066Sahrens mode_t seen = 0; 862da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 863da6c28aaSamw uint64_t who; 864da6c28aaSamw uint16_t iflags, type; 865da6c28aaSamw uint32_t access_mask; 866d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 867fa9e4066Sahrens 8680a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 869da6c28aaSamw 870da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 871da6c28aaSamw &access_mask, &iflags, &type)) { 87229a0b737Smarks 873003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 874003c2582SMark Shellenbaum continue; 875003c2582SMark Shellenbaum 876e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 877e6032be1Smarks 8781ab99678SMark Shellenbaum /* 8791ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 8801ab99678SMark Shellenbaum */ 8811ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 8821ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 8831ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 8841ab99678SMark Shellenbaum continue; 8851ab99678SMark Shellenbaum 88627dd1e87SMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 && 88727dd1e87SMark Shellenbaum who == fuid)) { 888da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 889fa9e4066Sahrens (!(seen & S_IRUSR))) { 890fa9e4066Sahrens seen |= S_IRUSR; 891da6c28aaSamw if (type == ALLOW) { 892fa9e4066Sahrens mode |= S_IRUSR; 893fa9e4066Sahrens } 894fa9e4066Sahrens } 895da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 896fa9e4066Sahrens (!(seen & S_IWUSR))) { 897fa9e4066Sahrens seen |= S_IWUSR; 898da6c28aaSamw if (type == ALLOW) { 899fa9e4066Sahrens mode |= S_IWUSR; 900fa9e4066Sahrens } 901fa9e4066Sahrens } 902da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 903fa9e4066Sahrens (!(seen & S_IXUSR))) { 904fa9e4066Sahrens seen |= S_IXUSR; 905da6c28aaSamw if (type == ALLOW) { 906fa9e4066Sahrens mode |= S_IXUSR; 907fa9e4066Sahrens } 908fa9e4066Sahrens } 90927dd1e87SMark Shellenbaum } else if (entry_type == OWNING_GROUP || 91027dd1e87SMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) { 911da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 912fa9e4066Sahrens (!(seen & S_IRGRP))) { 913fa9e4066Sahrens seen |= S_IRGRP; 914da6c28aaSamw if (type == ALLOW) { 915fa9e4066Sahrens mode |= S_IRGRP; 916fa9e4066Sahrens } 917fa9e4066Sahrens } 918da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 919fa9e4066Sahrens (!(seen & S_IWGRP))) { 920fa9e4066Sahrens seen |= S_IWGRP; 921da6c28aaSamw if (type == ALLOW) { 922fa9e4066Sahrens mode |= S_IWGRP; 923fa9e4066Sahrens } 924fa9e4066Sahrens } 925da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 926fa9e4066Sahrens (!(seen & S_IXGRP))) { 927fa9e4066Sahrens seen |= S_IXGRP; 928da6c28aaSamw if (type == ALLOW) { 929fa9e4066Sahrens mode |= S_IXGRP; 930fa9e4066Sahrens } 931fa9e4066Sahrens } 932fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 933da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 934fa9e4066Sahrens if (!(seen & S_IRUSR)) { 935fa9e4066Sahrens seen |= S_IRUSR; 936da6c28aaSamw if (type == ALLOW) { 937fa9e4066Sahrens mode |= S_IRUSR; 938fa9e4066Sahrens } 939fa9e4066Sahrens } 940fa9e4066Sahrens if (!(seen & S_IRGRP)) { 941fa9e4066Sahrens seen |= S_IRGRP; 942da6c28aaSamw if (type == ALLOW) { 943fa9e4066Sahrens mode |= S_IRGRP; 944fa9e4066Sahrens } 945fa9e4066Sahrens } 946fa9e4066Sahrens if (!(seen & S_IROTH)) { 947fa9e4066Sahrens seen |= S_IROTH; 948da6c28aaSamw if (type == ALLOW) { 949fa9e4066Sahrens mode |= S_IROTH; 950fa9e4066Sahrens } 951fa9e4066Sahrens } 952fa9e4066Sahrens } 953da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 954fa9e4066Sahrens if (!(seen & S_IWUSR)) { 955fa9e4066Sahrens seen |= S_IWUSR; 956da6c28aaSamw if (type == ALLOW) { 957fa9e4066Sahrens mode |= S_IWUSR; 958fa9e4066Sahrens } 959fa9e4066Sahrens } 960fa9e4066Sahrens if (!(seen & S_IWGRP)) { 961fa9e4066Sahrens seen |= S_IWGRP; 962da6c28aaSamw if (type == ALLOW) { 963fa9e4066Sahrens mode |= S_IWGRP; 964fa9e4066Sahrens } 965fa9e4066Sahrens } 966fa9e4066Sahrens if (!(seen & S_IWOTH)) { 967fa9e4066Sahrens seen |= S_IWOTH; 968da6c28aaSamw if (type == ALLOW) { 969fa9e4066Sahrens mode |= S_IWOTH; 970fa9e4066Sahrens } 971fa9e4066Sahrens } 972fa9e4066Sahrens } 973da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 974fa9e4066Sahrens if (!(seen & S_IXUSR)) { 975fa9e4066Sahrens seen |= S_IXUSR; 976da6c28aaSamw if (type == ALLOW) { 977fa9e4066Sahrens mode |= S_IXUSR; 978fa9e4066Sahrens } 979fa9e4066Sahrens } 980fa9e4066Sahrens if (!(seen & S_IXGRP)) { 981fa9e4066Sahrens seen |= S_IXGRP; 982da6c28aaSamw if (type == ALLOW) { 983fa9e4066Sahrens mode |= S_IXGRP; 984fa9e4066Sahrens } 985fa9e4066Sahrens } 986fa9e4066Sahrens if (!(seen & S_IXOTH)) { 987fa9e4066Sahrens seen |= S_IXOTH; 988da6c28aaSamw if (type == ALLOW) { 989fa9e4066Sahrens mode |= S_IXOTH; 990fa9e4066Sahrens } 991fa9e4066Sahrens } 992fa9e4066Sahrens } 993d47621a4STim Haley } else { 994d47621a4STim Haley /* 995d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 996d47621a4STim Haley * USER ACE denies execute access to someone, 997d47621a4STim Haley * mode is not affected 998d47621a4STim Haley */ 999d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 1000d47621a4STim Haley an_exec_denied = B_TRUE; 1001fa9e4066Sahrens } 1002fa9e4066Sahrens } 1003d47621a4STim Haley 10044929fd5eSTim Haley /* 10054929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 10064929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 10074929fd5eSTim Haley * weren't allowed it. 10084929fd5eSTim Haley */ 10094929fd5eSTim Haley if (!an_exec_denied && 10104929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 10114929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 1012d47621a4STim Haley an_exec_denied = B_TRUE; 1013d47621a4STim Haley 1014d47621a4STim Haley if (an_exec_denied) 10150a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED; 1016d47621a4STim Haley else 10170a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED; 1018d47621a4STim Haley 1019fa9e4066Sahrens return (mode); 1020fa9e4066Sahrens } 1021fa9e4066Sahrens 1022fa9e4066Sahrens /* 10234929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 10244929fd5eSTim Haley * create a new acl and leave any cached acl in place. 1025fa9e4066Sahrens */ 1026ea8dc4b6Seschrock static int 1027da6c28aaSamw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) 1028fa9e4066Sahrens { 1029fa9e4066Sahrens zfs_acl_t *aclp; 10300a586ceaSMark Shellenbaum int aclsize; 10310a586ceaSMark Shellenbaum int acl_count; 1032da6c28aaSamw zfs_acl_node_t *aclnode; 10330a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl; 10340a586ceaSMark Shellenbaum int version; 1035ea8dc4b6Seschrock int error; 1036fa9e4066Sahrens 1037fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 1038fa9e4066Sahrens 10394929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 1040d47621a4STim Haley *aclpp = zp->z_acl_cached; 1041d47621a4STim Haley return (0); 1042d47621a4STim Haley } 1043d47621a4STim Haley 10440a586ceaSMark Shellenbaum version = ZNODE_ACL_VERSION(zp); 1045fa9e4066Sahrens 10460a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize, 10470a586ceaSMark Shellenbaum &acl_count, &znode_acl)) != 0) 10480a586ceaSMark Shellenbaum return (error); 1049fa9e4066Sahrens 10500a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version); 10510a586ceaSMark Shellenbaum 1052da6c28aaSamw aclp->z_acl_count = acl_count; 1053da6c28aaSamw aclp->z_acl_bytes = aclsize; 1054da6c28aaSamw 10550a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize); 10560a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count; 10570a586ceaSMark Shellenbaum aclnode->z_size = aclsize; 10580a586ceaSMark Shellenbaum 10590a586ceaSMark Shellenbaum if (!zp->z_is_sa) { 10600a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) { 10610a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os, 10620a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size, 10630a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH); 10640a586ceaSMark Shellenbaum } else { 10650a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata, 10660a586ceaSMark Shellenbaum aclnode->z_size); 10670a586ceaSMark Shellenbaum } 10680a586ceaSMark Shellenbaum } else { 10690a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs), 10700a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size); 10710a586ceaSMark Shellenbaum } 10720a586ceaSMark Shellenbaum 1073ea8dc4b6Seschrock if (error != 0) { 1074ea8dc4b6Seschrock zfs_acl_free(aclp); 10750a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode); 1076b87f3af3Sperrin /* convert checksum errors into IO errors */ 1077b87f3af3Sperrin if (error == ECKSUM) 1078b87f3af3Sperrin error = EIO; 1079ea8dc4b6Seschrock return (error); 1080ea8dc4b6Seschrock } 1081fa9e4066Sahrens 10820a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode); 10830a586ceaSMark Shellenbaum 10844929fd5eSTim Haley *aclpp = aclp; 10854929fd5eSTim Haley if (!will_modify) 10864929fd5eSTim Haley zp->z_acl_cached = aclp; 1087ea8dc4b6Seschrock return (0); 1088fa9e4066Sahrens } 1089fa9e4066Sahrens 10900a586ceaSMark Shellenbaum /*ARGSUSED*/ 10910a586ceaSMark Shellenbaum void 10920a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, 10930a586ceaSMark Shellenbaum boolean_t start, void *userdata) 10940a586ceaSMark Shellenbaum { 10950a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata; 10960a586ceaSMark Shellenbaum 10970a586ceaSMark Shellenbaum if (start) { 10980a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl); 10990a586ceaSMark Shellenbaum } else { 11000a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, 11010a586ceaSMark Shellenbaum cb->cb_acl_node); 11020a586ceaSMark Shellenbaum } 11030a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata; 11040a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size; 11050a586ceaSMark Shellenbaum } 11060a586ceaSMark Shellenbaum 110727dd1e87SMark Shellenbaum 110827dd1e87SMark Shellenbaum static int 110927dd1e87SMark Shellenbaum zfs_acl_get_owner_fuids(znode_t *zp, uint64_t *fuid, uint64_t *fgid) 111027dd1e87SMark Shellenbaum { 111127dd1e87SMark Shellenbaum int count = 0; 111227dd1e87SMark Shellenbaum sa_bulk_attr_t bulk[2]; 111327dd1e87SMark Shellenbaum int error; 111427dd1e87SMark Shellenbaum 111527dd1e87SMark Shellenbaum if (IS_EPHEMERAL(zp->z_uid) || IS_EPHEMERAL(zp->z_gid)) { 111627dd1e87SMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zp->z_zfsvfs), NULL, 111727dd1e87SMark Shellenbaum &fuid, sizeof (fuid)); 111827dd1e87SMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zp->z_zfsvfs), NULL, 111927dd1e87SMark Shellenbaum &fgid, sizeof (fuid)); 112027dd1e87SMark Shellenbaum if ((error = sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) != 0) { 112127dd1e87SMark Shellenbaum return (error); 112227dd1e87SMark Shellenbaum } 112327dd1e87SMark Shellenbaum } else { 112427dd1e87SMark Shellenbaum *fuid = zp->z_uid; 112527dd1e87SMark Shellenbaum *fgid = zp->z_gid; 112627dd1e87SMark Shellenbaum } 112727dd1e87SMark Shellenbaum return (0); 112827dd1e87SMark Shellenbaum } 112927dd1e87SMark Shellenbaum 113027dd1e87SMark Shellenbaum int 113127dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp) 113227dd1e87SMark Shellenbaum { 113327dd1e87SMark Shellenbaum int error; 113427dd1e87SMark Shellenbaum zfs_acl_t *aclp; 113527dd1e87SMark Shellenbaum uint64_t fuid, fgid; 113627dd1e87SMark Shellenbaum 113727dd1e87SMark Shellenbaum if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0) 113827dd1e87SMark Shellenbaum return (error); 113927dd1e87SMark Shellenbaum 114027dd1e87SMark Shellenbaum mutex_enter(&zp->z_acl_lock); 114127dd1e87SMark Shellenbaum if ((error = zfs_acl_node_read(zp, &aclp, B_FALSE)) == 0) 114227dd1e87SMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp, 114327dd1e87SMark Shellenbaum &zp->z_pflags, fuid, fgid); 114427dd1e87SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 114527dd1e87SMark Shellenbaum return (error); 114627dd1e87SMark Shellenbaum } 114727dd1e87SMark Shellenbaum 1148fa9e4066Sahrens /* 1149da6c28aaSamw * common code for setting ACLs. 1150fa9e4066Sahrens * 1151fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1152fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1153fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1154fa9e4066Sahrens */ 1155fa9e4066Sahrens int 115689459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1157fa9e4066Sahrens { 1158fa9e4066Sahrens int error; 1159fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1160da6c28aaSamw dmu_object_type_t otype; 11610a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 }; 11620a586ceaSMark Shellenbaum uint64_t mode; 11630a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5]; 11640a586ceaSMark Shellenbaum uint64_t ctime[2]; 11650a586ceaSMark Shellenbaum int count = 0; 116627dd1e87SMark Shellenbaum uint64_t fuid, fgid; 1167fa9e4066Sahrens 11680a586ceaSMark Shellenbaum mode = zp->z_mode; 116927dd1e87SMark Shellenbaum 117027dd1e87SMark Shellenbaum if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0) 117127dd1e87SMark Shellenbaum return (error); 117227dd1e87SMark Shellenbaum 117327dd1e87SMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, fuid, fgid); 11740a586ceaSMark Shellenbaum 11750a586ceaSMark Shellenbaum zp->z_mode = mode; 11760a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, 11770a586ceaSMark Shellenbaum &mode, sizeof (mode)); 11780a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, 11790a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags)); 11800a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, 11810a586ceaSMark Shellenbaum &ctime, sizeof (ctime)); 1182fa9e4066Sahrens 11834929fd5eSTim Haley if (zp->z_acl_cached) { 1184d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1185d47621a4STim Haley zp->z_acl_cached = NULL; 1186d47621a4STim Haley } 1187d47621a4STim Haley 1188fa9e4066Sahrens /* 11890a586ceaSMark Shellenbaum * Upgrade needed? 1190fa9e4066Sahrens */ 1191da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1192da6c28aaSamw otype = DMU_OT_OLDACL; 1193da6c28aaSamw } else { 1194da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1195da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 119689459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1197da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1198da6c28aaSamw otype = DMU_OT_ACL; 1199da6c28aaSamw } 1200da6c28aaSamw 12010a586ceaSMark Shellenbaum /* 12020a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format 12030a586ceaSMark Shellenbaum * as well as newer (preferred) SA format. 12040a586ceaSMark Shellenbaum */ 12050a586ceaSMark Shellenbaum 12060a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */ 12070a586ceaSMark Shellenbaum locate.cb_aclp = aclp; 12080a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs), 12090a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes); 12100a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), 12110a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t)); 12120a586ceaSMark Shellenbaum } else { /* Painful legacy way */ 12130a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode; 12140a586ceaSMark Shellenbaum uint64_t off = 0; 12150a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 12160a586ceaSMark Shellenbaum uint64_t aoid; 12170a586ceaSMark Shellenbaum 12180a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 12190a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0) 12200a586ceaSMark Shellenbaum return (error); 12210a586ceaSMark Shellenbaum 12220a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj; 12230a586ceaSMark Shellenbaum 1224da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1225da6c28aaSamw /* 1226da6c28aaSamw * If ACL was previously external and we are now 1227da6c28aaSamw * converting to new ACL format then release old 1228da6c28aaSamw * ACL object and create a new one. 1229da6c28aaSamw */ 12300a586ceaSMark Shellenbaum if (aoid && 12310a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) { 12320a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx); 1233da6c28aaSamw if (error) 1234da6c28aaSamw return (error); 1235da6c28aaSamw aoid = 0; 1236da6c28aaSamw } 1237fa9e4066Sahrens if (aoid == 0) { 1238fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1239da6c28aaSamw otype, aclp->z_acl_bytes, 12400a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12410a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE, 12420a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12430a586ceaSMark Shellenbaum DN_MAX_BONUSLEN : 0, tx); 1244fa9e4066Sahrens } else { 12450a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os, 12460a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx); 1247fa9e4066Sahrens } 12480a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid; 1249da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1250da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1251da6c28aaSamw if (aclnode->z_ace_count == 0) 1252da6c28aaSamw continue; 1253da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1254da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1255da6c28aaSamw off += aclnode->z_size; 1256da6c28aaSamw } 1257fa9e4066Sahrens } else { 12580a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data; 1259fa9e4066Sahrens /* 1260fa9e4066Sahrens * Migrating back embedded? 1261fa9e4066Sahrens */ 12620a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) { 1263fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 12640a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx); 1265fa9e4066Sahrens if (error) 1266fa9e4066Sahrens return (error); 12670a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0; 1268fa9e4066Sahrens } 1269da6c28aaSamw 1270da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1271da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1272da6c28aaSamw if (aclnode->z_ace_count == 0) 1273da6c28aaSamw continue; 12740a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start, 12750a586ceaSMark Shellenbaum aclnode->z_size); 1276da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1277da6c28aaSamw } 1278fa9e4066Sahrens } 1279da6c28aaSamw /* 1280da6c28aaSamw * If Old version then swap count/bytes to match old 1281da6c28aaSamw * layout of znode_acl_phys_t. 1282da6c28aaSamw */ 1283da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 12840a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count; 12850a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes; 1286da6c28aaSamw } else { 12870a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes; 12880a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count; 1289da6c28aaSamw } 12900a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version; 1291da6c28aaSamw 12920a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL, 12930a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys)); 12940a586ceaSMark Shellenbaum } 1295da6c28aaSamw 1296da6c28aaSamw /* 1297da6c28aaSamw * Replace ACL wide bits, but first clear them. 1298da6c28aaSamw */ 12990a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS; 1300da6c28aaSamw 13010a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints; 1302da6c28aaSamw 1303da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 13040a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL; 1305fa9e4066Sahrens 13060a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE); 13070a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); 1308fa9e4066Sahrens } 1309fa9e4066Sahrens 1310fa9e4066Sahrens /* 1311fa9e4066Sahrens * Update access mask for prepended ACE 1312fa9e4066Sahrens * 1313fa9e4066Sahrens * This applies the "groupmask" value for aclmode property. 1314fa9e4066Sahrens */ 1315fa9e4066Sahrens static void 1316da6c28aaSamw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, 1317da6c28aaSamw mode_t mode, uint64_t owner) 1318fa9e4066Sahrens { 1319fa9e4066Sahrens int rmask, wmask, xmask; 1320fa9e4066Sahrens int user_ace; 1321da6c28aaSamw uint16_t aceflags; 1322da6c28aaSamw uint32_t origmask, acepmask; 1323da6c28aaSamw uint64_t fuid; 1324fa9e4066Sahrens 1325da6c28aaSamw aceflags = aclp->z_ops.ace_flags_get(acep); 1326da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1327da6c28aaSamw origmask = aclp->z_ops.ace_mask_get(origacep); 1328da6c28aaSamw acepmask = aclp->z_ops.ace_mask_get(acep); 1329da6c28aaSamw 1330da6c28aaSamw user_ace = (!(aceflags & 1331fa9e4066Sahrens (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); 1332fa9e4066Sahrens 1333da6c28aaSamw if (user_ace && (fuid == owner)) { 1334fa9e4066Sahrens rmask = S_IRUSR; 1335fa9e4066Sahrens wmask = S_IWUSR; 1336fa9e4066Sahrens xmask = S_IXUSR; 1337fa9e4066Sahrens } else { 1338fa9e4066Sahrens rmask = S_IRGRP; 1339fa9e4066Sahrens wmask = S_IWGRP; 1340fa9e4066Sahrens xmask = S_IXGRP; 1341fa9e4066Sahrens } 1342fa9e4066Sahrens 1343da6c28aaSamw if (origmask & ACE_READ_DATA) { 1344da6c28aaSamw if (mode & rmask) { 1345da6c28aaSamw acepmask &= ~ACE_READ_DATA; 1346da6c28aaSamw } else { 1347da6c28aaSamw acepmask |= ACE_READ_DATA; 1348da6c28aaSamw } 1349fa9e4066Sahrens } 1350fa9e4066Sahrens 1351da6c28aaSamw if (origmask & ACE_WRITE_DATA) { 1352da6c28aaSamw if (mode & wmask) { 1353da6c28aaSamw acepmask &= ~ACE_WRITE_DATA; 1354da6c28aaSamw } else { 1355da6c28aaSamw acepmask |= ACE_WRITE_DATA; 1356da6c28aaSamw } 1357fa9e4066Sahrens } 1358fa9e4066Sahrens 1359da6c28aaSamw if (origmask & ACE_APPEND_DATA) { 1360da6c28aaSamw if (mode & wmask) { 1361da6c28aaSamw acepmask &= ~ACE_APPEND_DATA; 1362da6c28aaSamw } else { 1363da6c28aaSamw acepmask |= ACE_APPEND_DATA; 1364da6c28aaSamw } 1365fa9e4066Sahrens } 1366fa9e4066Sahrens 1367da6c28aaSamw if (origmask & ACE_EXECUTE) { 1368da6c28aaSamw if (mode & xmask) { 1369da6c28aaSamw acepmask &= ~ACE_EXECUTE; 1370da6c28aaSamw } else { 1371da6c28aaSamw acepmask |= ACE_EXECUTE; 1372fa9e4066Sahrens } 1373fa9e4066Sahrens } 1374da6c28aaSamw aclp->z_ops.ace_mask_set(acep, acepmask); 1375da6c28aaSamw } 1376fa9e4066Sahrens 1377fa9e4066Sahrens static void 137827dd1e87SMark Shellenbaum zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp) 1379fa9e4066Sahrens { 138027dd1e87SMark Shellenbaum void *acep = NULL; 1381da6c28aaSamw uint64_t who; 138227dd1e87SMark Shellenbaum int new_count, new_bytes; 138327dd1e87SMark Shellenbaum int ace_size; 1384fa9e4066Sahrens int entry_type; 1385da6c28aaSamw uint16_t iflags, type; 1386da6c28aaSamw uint32_t access_mask; 138727dd1e87SMark Shellenbaum zfs_acl_node_t *newnode; 138827dd1e87SMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size(); 138927dd1e87SMark Shellenbaum void *zacep; 139027dd1e87SMark Shellenbaum uint32_t owner, group, everyone; 139127dd1e87SMark Shellenbaum uint32_t deny1, deny2, allow0; 1392fa9e4066Sahrens 139327dd1e87SMark Shellenbaum new_count = new_bytes = 0; 139427dd1e87SMark Shellenbaum 139527dd1e87SMark Shellenbaum acl_trivial_access_masks((mode_t)mode, &allow0, &deny1, &deny2, 139627dd1e87SMark Shellenbaum &owner, &group, &everyone); 139727dd1e87SMark Shellenbaum 139827dd1e87SMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes); 139927dd1e87SMark Shellenbaum 140027dd1e87SMark Shellenbaum zacep = newnode->z_acldata; 140127dd1e87SMark Shellenbaum if (allow0) { 140227dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, allow0, ALLOW, -1, ACE_OWNER); 140327dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 140427dd1e87SMark Shellenbaum new_count++; 140527dd1e87SMark Shellenbaum new_bytes += abstract_size; 140627dd1e87SMark Shellenbaum } if (deny1) { 140727dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, deny1, DENY, -1, ACE_OWNER); 140827dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 140927dd1e87SMark Shellenbaum new_count++; 141027dd1e87SMark Shellenbaum new_bytes += abstract_size; 141127dd1e87SMark Shellenbaum } 141227dd1e87SMark Shellenbaum if (deny2) { 141327dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, deny2, DENY, -1, OWNING_GROUP); 141427dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 141527dd1e87SMark Shellenbaum new_count++; 141627dd1e87SMark Shellenbaum new_bytes += abstract_size; 141727dd1e87SMark Shellenbaum } 14182459a9eaSmarks 1419da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1420da6c28aaSamw &iflags, &type)) { 142127dd1e87SMark Shellenbaum uint16_t inherit_flags; 1422fa9e4066Sahrens 1423da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 142427dd1e87SMark Shellenbaum inherit_flags = (iflags & ALL_INHERIT); 142527dd1e87SMark Shellenbaum 142627dd1e87SMark Shellenbaum if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 142727dd1e87SMark Shellenbaum (entry_type == OWNING_GROUP)) && 142827dd1e87SMark Shellenbaum ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) { 142927dd1e87SMark Shellenbaum continue; 143027dd1e87SMark Shellenbaum } 1431da6c28aaSamw 1432da6c28aaSamw if ((type != ALLOW && type != DENY) || 143327dd1e87SMark Shellenbaum (inherit_flags & ACE_INHERIT_ONLY_ACE)) { 143427dd1e87SMark Shellenbaum if (inherit_flags) 1435da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1436da6c28aaSamw switch (type) { 1437da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1438da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1439da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1440da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1441da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1442da6c28aaSamw break; 1443fa9e4066Sahrens } 1444fa9e4066Sahrens } else { 1445fa9e4066Sahrens 1446fa9e4066Sahrens /* 144727dd1e87SMark Shellenbaum * Limit permissions to be no greater than 144827dd1e87SMark Shellenbaum * group permissions 1449fa9e4066Sahrens */ 145027dd1e87SMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) { 145127dd1e87SMark Shellenbaum if (!(mode & S_IRGRP)) 145227dd1e87SMark Shellenbaum access_mask &= ~ACE_READ_DATA; 145327dd1e87SMark Shellenbaum if (!(mode & S_IWGRP)) 145427dd1e87SMark Shellenbaum access_mask &= 145527dd1e87SMark Shellenbaum ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 145627dd1e87SMark Shellenbaum if (!(mode & S_IXGRP)) 145727dd1e87SMark Shellenbaum access_mask &= ~ACE_EXECUTE; 145827dd1e87SMark Shellenbaum access_mask &= 145927dd1e87SMark Shellenbaum ~(ACE_WRITE_OWNER|ACE_WRITE_ACL| 146027dd1e87SMark Shellenbaum ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS); 1461fa9e4066Sahrens } 1462fa9e4066Sahrens } 146327dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags); 146427dd1e87SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 146527dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size); 146627dd1e87SMark Shellenbaum new_count++; 146727dd1e87SMark Shellenbaum new_bytes += ace_size; 1468fa9e4066Sahrens } 146927dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, owner, 0, -1, ACE_OWNER); 147027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 147127dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, group, 0, -1, OWNING_GROUP); 147227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 147327dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, everyone, 0, -1, ACE_EVERYONE); 1474fa9e4066Sahrens 147527dd1e87SMark Shellenbaum new_count += 3; 147627dd1e87SMark Shellenbaum new_bytes += abstract_size * 3; 147727dd1e87SMark Shellenbaum zfs_acl_release_nodes(aclp); 147827dd1e87SMark Shellenbaum aclp->z_acl_count = new_count; 147927dd1e87SMark Shellenbaum aclp->z_acl_bytes = new_bytes; 148027dd1e87SMark Shellenbaum newnode->z_ace_count = new_count; 148127dd1e87SMark Shellenbaum newnode->z_size = new_bytes; 148227dd1e87SMark Shellenbaum list_insert_tail(&aclp->z_acl, newnode); 1483fa9e4066Sahrens } 1484fa9e4066Sahrens 1485fa9e4066Sahrens int 14864c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1487fa9e4066Sahrens { 14884c841f60Smarks mutex_enter(&zp->z_lock); 1489fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 149027dd1e87SMark Shellenbaum *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); 14910a586ceaSMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; 149227dd1e87SMark Shellenbaum zfs_acl_chmod(zp->z_zfsvfs, mode, *aclp); 1493fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 14944c841f60Smarks mutex_exit(&zp->z_lock); 149527dd1e87SMark Shellenbaum ASSERT(*aclp); 149627dd1e87SMark Shellenbaum return (0); 1497fa9e4066Sahrens } 1498fa9e4066Sahrens 1499fa9e4066Sahrens /* 1500fa9e4066Sahrens * strip off write_owner and write_acl 1501fa9e4066Sahrens */ 1502fa9e4066Sahrens static void 1503b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1504fa9e4066Sahrens { 1505da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1506da6c28aaSamw 1507b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1508da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1509b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1510da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1511da6c28aaSamw } 1512da6c28aaSamw } 1513da6c28aaSamw 1514da6c28aaSamw /* 1515da6c28aaSamw * Should ACE be inherited? 1516da6c28aaSamw */ 1517da6c28aaSamw static int 151889459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1519da6c28aaSamw { 1520da6c28aaSamw int iflags = (acep_flags & 0xf); 1521da6c28aaSamw 1522da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1523da6c28aaSamw return (1); 1524da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1525da6c28aaSamw return (!((vtype == VDIR) && 1526da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1527da6c28aaSamw return (0); 1528fa9e4066Sahrens } 1529fa9e4066Sahrens 1530fa9e4066Sahrens /* 1531fa9e4066Sahrens * inherit inheritable ACEs from parent 1532fa9e4066Sahrens */ 1533fa9e4066Sahrens static zfs_acl_t * 153489459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 153589459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1536fa9e4066Sahrens { 1537da6c28aaSamw void *pacep; 153827dd1e87SMark Shellenbaum void *acep; 153927dd1e87SMark Shellenbaum zfs_acl_node_t *aclnode; 1540fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1541da6c28aaSamw uint64_t who; 1542da6c28aaSamw uint32_t access_mask; 1543da6c28aaSamw uint16_t iflags, newflags, type; 1544da6c28aaSamw size_t ace_size; 1545da6c28aaSamw void *data1, *data2; 1546da6c28aaSamw size_t data1sz, data2sz; 154789459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 154889459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1549d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1550d0f3f37eSMark Shellenbaum 1551d0f3f37eSMark Shellenbaum passthrough_x = 1552d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1553d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1554d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1555d0f3f37eSMark Shellenbaum noallow = 1556d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1557fa9e4066Sahrens 1558b3d141f8Smarks *need_chmod = B_TRUE; 1559da6c28aaSamw pacep = NULL; 1560003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 15610a586ceaSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK) 1562d0f3f37eSMark Shellenbaum return (aclp); 1563da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1564da6c28aaSamw &access_mask, &iflags, &type)) { 1565fa9e4066Sahrens 1566003c2582SMark Shellenbaum /* 1567003c2582SMark Shellenbaum * don't inherit bogus ACEs 1568003c2582SMark Shellenbaum */ 1569003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1570003c2582SMark Shellenbaum continue; 1571003c2582SMark Shellenbaum 1572d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1573fa9e4066Sahrens continue; 1574fa9e4066Sahrens 1575da6c28aaSamw ace_size = aclp->z_ops.ace_size(pacep); 1576fa9e4066Sahrens 157789459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1578b3d141f8Smarks continue; 1579fa9e4066Sahrens 1580b3d141f8Smarks /* 1581b3d141f8Smarks * If owner@, group@, or everyone@ inheritable 1582b3d141f8Smarks * then zfs_acl_chmod() isn't needed. 1583b3d141f8Smarks */ 1584d0f3f37eSMark Shellenbaum if (passthrough && 1585b3d141f8Smarks ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1586b3d141f8Smarks ((iflags & OWNING_GROUP) == 1587d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1588d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1589b3d141f8Smarks *need_chmod = B_FALSE; 1590c694df91SMark Shellenbaum } 1591b3d141f8Smarks 1592d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1593d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1594d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1595d0f3f37eSMark Shellenbaum } 1596d0f3f37eSMark Shellenbaum 1597b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1598da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1599da6c28aaSamw acep = aclnode->z_acldata; 1600d0f3f37eSMark Shellenbaum 1601da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1602da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1603169cdae2Smarks 1604fa9e4066Sahrens /* 1605da6c28aaSamw * Copy special opaque data if any 1606fa9e4066Sahrens */ 1607d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1608b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1609da6c28aaSamw &data2)) == data1sz); 1610da6c28aaSamw bcopy(data1, data2, data2sz); 1611da6c28aaSamw } 161227dd1e87SMark Shellenbaum 1613da6c28aaSamw aclp->z_acl_count++; 1614da6c28aaSamw aclnode->z_ace_count++; 1615da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1616da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1617b3d141f8Smarks 1618d0f3f37eSMark Shellenbaum if (vdir) 1619b3d141f8Smarks aclp->z_hints |= ZFS_INHERIT_ACE; 1620b3d141f8Smarks 1621d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1622da6c28aaSamw newflags &= ~ALL_INHERIT; 1623da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1624da6c28aaSamw newflags|ACE_INHERITED_ACE); 1625b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep); 1626fa9e4066Sahrens continue; 1627fa9e4066Sahrens } 1628fa9e4066Sahrens 1629d0f3f37eSMark Shellenbaum ASSERT(vdir); 1630fa9e4066Sahrens 1631da6c28aaSamw /* 163227dd1e87SMark Shellenbaum * If only FILE_INHERIT is set then turn on 163327dd1e87SMark Shellenbaum * inherit_only 1634da6c28aaSamw */ 163527dd1e87SMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE | 163627dd1e87SMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == 163727dd1e87SMark Shellenbaum ACE_FILE_INHERIT_ACE) { 1638da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1639da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1640da6c28aaSamw newflags|ACE_INHERITED_ACE); 1641da6c28aaSamw } 1642da6c28aaSamw } 1643fa9e4066Sahrens return (aclp); 1644fa9e4066Sahrens } 1645fa9e4066Sahrens 1646fa9e4066Sahrens /* 1647fa9e4066Sahrens * Create file system object initial permissions 1648fa9e4066Sahrens * including inheritable ACEs. 1649fa9e4066Sahrens */ 165089459e17SMark Shellenbaum int 165189459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 165289459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1653fa9e4066Sahrens { 1654fa9e4066Sahrens int error; 165589459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1656da6c28aaSamw zfs_acl_t *paclp; 1657e0d35c44Smarks gid_t gid; 1658b3d141f8Smarks boolean_t need_chmod = B_TRUE; 16590a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE; 16600a586ceaSMark Shellenbaum uint64_t parentgid; 1661da6c28aaSamw 166289459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 166389459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1664fa9e4066Sahrens 166589459e17SMark Shellenbaum if (vsecp) 166689459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 166789459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 166889459e17SMark Shellenbaum return (error); 1669fa9e4066Sahrens /* 1670fa9e4066Sahrens * Determine uid and gid. 1671fa9e4066Sahrens */ 16724a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1673fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 167489459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 167589459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 167689459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 167789459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 167889459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 167989459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1680e0d35c44Smarks gid = vap->va_gid; 1681fa9e4066Sahrens } else { 16820a586ceaSMark Shellenbaum if (IS_EPHEMERAL(dzp->z_gid)) 16830a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(dzp->z_sa_hdl, SA_ZPL_GID(zfsvfs), 16840a586ceaSMark Shellenbaum &parentgid, sizeof (parentgid))); 16850a586ceaSMark Shellenbaum else 16860a586ceaSMark Shellenbaum parentgid = (uint64_t)dzp->z_gid; 16870a586ceaSMark Shellenbaum 168889459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 168989459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 169089459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1691e0d35c44Smarks if (vap->va_mask & AT_GID) { 169289459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 169389459e17SMark Shellenbaum (uint64_t)vap->va_gid, 169489459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1695e0d35c44Smarks gid = vap->va_gid; 16960a586ceaSMark Shellenbaum if (acl_ids->z_fgid != parentgid && 1697e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1698e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 169989459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1700e0d35c44Smarks } 170189459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 17020a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) { 1703b3874165SJohn Harres char *domain; 1704b3874165SJohn Harres uint32_t rid; 1705b3874165SJohn Harres 17060a586ceaSMark Shellenbaum acl_ids->z_fgid = parentgid; 170789459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1708e0d35c44Smarks cr, ZFS_GROUP); 1709b3874165SJohn Harres 1710b3874165SJohn Harres if (zfsvfs->z_use_fuids && 1711b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) { 1712b3874165SJohn Harres domain = zfs_fuid_idx_domain( 1713b3874165SJohn Harres &zfsvfs->z_fuid_idx, 1714b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid)); 1715b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid); 1716b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp, 1717b3874165SJohn Harres domain, rid, 1718b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid), 1719b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP); 1720b3874165SJohn Harres } 1721da6c28aaSamw } else { 172289459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 172389459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1724e0d35c44Smarks gid = crgetgid(cr); 1725e0d35c44Smarks } 1726da6c28aaSamw } 1727fa9e4066Sahrens } 1728fa9e4066Sahrens 1729fa9e4066Sahrens /* 1730fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1731fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1732fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1733fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1734fa9e4066Sahrens */ 1735fa9e4066Sahrens 17360a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) && 173789459e17SMark Shellenbaum (vap->va_type == VDIR)) { 173889459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1739e0d35c44Smarks } else { 174089459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1741fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 174289459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1743fa9e4066Sahrens } 1744fa9e4066Sahrens 174589459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 174689459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 174789459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && 17480a586ceaSMark Shellenbaum (dzp->z_pflags & ZFS_INHERIT_ACE)) && 17490a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) { 175089459e17SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 175189459e17SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE)); 175289459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 175389459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 17540a586ceaSMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 17550a586ceaSMark Shellenbaum inherited = B_TRUE; 1756fa9e4066Sahrens } else { 175789459e17SMark Shellenbaum acl_ids->z_aclp = 175889459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 17590a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 1760fa9e4066Sahrens } 176189459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 176289459e17SMark Shellenbaum if (need_chmod) { 17630a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ? 176489459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 176527dd1e87SMark Shellenbaum zfs_acl_chmod(zfsvfs, acl_ids->z_mode, acl_ids->z_aclp); 176689459e17SMark Shellenbaum } 1767da6c28aaSamw } 1768da6c28aaSamw 17690a586ceaSMark Shellenbaum if (inherited || vsecp) { 17700a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode, 177127dd1e87SMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints, 177227dd1e87SMark Shellenbaum acl_ids->z_fuid, acl_ids->z_fgid); 17730a586ceaSMark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0) 17740a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 17750a586ceaSMark Shellenbaum } 17760a586ceaSMark Shellenbaum 177789459e17SMark Shellenbaum return (0); 1778fa9e4066Sahrens } 1779fa9e4066Sahrens 1780fa9e4066Sahrens /* 178189459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 178289459e17SMark Shellenbaum */ 178389459e17SMark Shellenbaum void 178489459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 178589459e17SMark Shellenbaum { 178689459e17SMark Shellenbaum if (acl_ids->z_aclp) 178789459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 178889459e17SMark Shellenbaum if (acl_ids->z_fuidp) 178989459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 179089459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 179189459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 179289459e17SMark Shellenbaum } 179389459e17SMark Shellenbaum 179414843421SMatthew Ahrens boolean_t 179514843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 179614843421SMatthew Ahrens { 17970a586ceaSMark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 17980a586ceaSMark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 179914843421SMatthew Ahrens } 180089459e17SMark Shellenbaum 180189459e17SMark Shellenbaum /* 1802fa9e4066Sahrens * Retrieve a files ACL 1803fa9e4066Sahrens */ 1804fa9e4066Sahrens int 1805da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1806fa9e4066Sahrens { 1807fa9e4066Sahrens zfs_acl_t *aclp; 1808da6c28aaSamw ulong_t mask; 1809fa9e4066Sahrens int error; 1810da6c28aaSamw int count = 0; 1811da6c28aaSamw int largeace = 0; 1812fa9e4066Sahrens 1813da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1814da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1815da6c28aaSamw 1816fa9e4066Sahrens if (mask == 0) 1817fa9e4066Sahrens return (ENOSYS); 1818fa9e4066Sahrens 18190a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 18200a586ceaSMark Shellenbaum return (error); 18210a586ceaSMark Shellenbaum 1822fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1823fa9e4066Sahrens 1824da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 1825ea8dc4b6Seschrock if (error != 0) { 1826ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1827ea8dc4b6Seschrock return (error); 1828ea8dc4b6Seschrock } 1829ea8dc4b6Seschrock 1830da6c28aaSamw /* 1831da6c28aaSamw * Scan ACL to determine number of ACEs 1832da6c28aaSamw */ 18330a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) { 1834da6c28aaSamw void *zacep = NULL; 1835da6c28aaSamw uint64_t who; 1836da6c28aaSamw uint32_t access_mask; 1837da6c28aaSamw uint16_t type, iflags; 1838da6c28aaSamw 1839da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1840da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1841da6c28aaSamw switch (type) { 1842da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1843da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1844da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1845da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1846da6c28aaSamw largeace++; 1847da6c28aaSamw continue; 1848da6c28aaSamw default: 1849da6c28aaSamw count++; 1850da6c28aaSamw } 1851da6c28aaSamw } 1852da6c28aaSamw vsecp->vsa_aclcnt = count; 1853da6c28aaSamw } else 18540a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count; 1855fa9e4066Sahrens 1856fa9e4066Sahrens if (mask & VSA_ACECNT) { 1857da6c28aaSamw vsecp->vsa_aclcnt = count; 1858fa9e4066Sahrens } 1859fa9e4066Sahrens 1860fa9e4066Sahrens if (mask & VSA_ACE) { 1861da6c28aaSamw size_t aclsz; 1862da6c28aaSamw 1863da6c28aaSamw aclsz = count * sizeof (ace_t) + 1864da6c28aaSamw sizeof (ace_object_t) * largeace; 1865da6c28aaSamw 1866da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 1867da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 1868da6c28aaSamw 1869da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 1870bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 1871da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 1872da6c28aaSamw else { 18732e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode; 18742e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp; 18752e7d9b42SMark Shellenbaum 18762e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode; 18772e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) { 18782e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start, 18792e7d9b42SMark Shellenbaum aclnode->z_size); 18802e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size; 18812e7d9b42SMark Shellenbaum } 18822e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 18832e7d9b42SMark Shellenbaum aclp->z_acl_bytes); 1884da6c28aaSamw } 1885da6c28aaSamw } 1886da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 1887da6c28aaSamw vsecp->vsa_aclflags = 0; 18880a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED) 1889da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 18900a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED) 1891da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 18920a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT) 1893da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 1894fa9e4066Sahrens } 1895fa9e4066Sahrens 1896fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1897fa9e4066Sahrens 1898fa9e4066Sahrens return (0); 1899fa9e4066Sahrens } 1900fa9e4066Sahrens 1901da6c28aaSamw int 1902da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 190389459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 1904da6c28aaSamw { 1905da6c28aaSamw zfs_acl_t *aclp; 1906da6c28aaSamw zfs_acl_node_t *aclnode; 1907da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 1908da6c28aaSamw int error; 1909da6c28aaSamw 1910da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 1911da6c28aaSamw return (EINVAL); 1912da6c28aaSamw 1913da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 1914da6c28aaSamw 1915da6c28aaSamw aclp->z_hints = 0; 1916da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 1917da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1918da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 1919da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 1920da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 1921da6c28aaSamw zfs_acl_free(aclp); 1922da6c28aaSamw zfs_acl_node_free(aclnode); 1923da6c28aaSamw return (error); 1924da6c28aaSamw } 1925da6c28aaSamw } else { 192689459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 1927da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 192889459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 1929da6c28aaSamw zfs_acl_free(aclp); 1930da6c28aaSamw zfs_acl_node_free(aclnode); 1931da6c28aaSamw return (error); 1932da6c28aaSamw } 1933da6c28aaSamw } 1934da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 1935da6c28aaSamw aclnode->z_ace_count = aclcnt; 1936da6c28aaSamw aclp->z_acl_count = aclcnt; 1937da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1938da6c28aaSamw 1939da6c28aaSamw /* 1940da6c28aaSamw * If flags are being set then add them to z_hints 1941da6c28aaSamw */ 1942da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 1943da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 1944da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 1945da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 1946da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 1947da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 1948da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 1949da6c28aaSamw } 1950da6c28aaSamw 1951da6c28aaSamw *zaclp = aclp; 1952da6c28aaSamw 1953da6c28aaSamw return (0); 1954da6c28aaSamw } 1955da6c28aaSamw 1956fa9e4066Sahrens /* 1957fa9e4066Sahrens * Set a files ACL 1958fa9e4066Sahrens */ 1959fa9e4066Sahrens int 1960da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1961fa9e4066Sahrens { 1962fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1963fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 1964fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 1965fa9e4066Sahrens dmu_tx_t *tx; 1966fa9e4066Sahrens int error; 1967fa9e4066Sahrens zfs_acl_t *aclp; 1968da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 196989459e17SMark Shellenbaum boolean_t fuid_dirtied; 1970fa9e4066Sahrens 1971fa9e4066Sahrens if (mask == 0) 19727106075aSmarks return (ENOSYS); 1973fa9e4066Sahrens 19740a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE) 1975da6c28aaSamw return (EPERM); 1976da6c28aaSamw 1977da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 1978fa9e4066Sahrens return (error); 1979da6c28aaSamw 198089459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 198189459e17SMark Shellenbaum &aclp); 1982da6c28aaSamw if (error) 1983da6c28aaSamw return (error); 1984da6c28aaSamw 1985da6c28aaSamw /* 1986da6c28aaSamw * If ACL wide flags aren't being set then preserve any 1987da6c28aaSamw * existing flags. 1988da6c28aaSamw */ 1989da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 19900a586ceaSMark Shellenbaum aclp->z_hints |= 19910a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS); 1992fa9e4066Sahrens } 1993da6c28aaSamw top: 1994fa9e4066Sahrens mutex_enter(&zp->z_lock); 1995fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1996fa9e4066Sahrens 1997fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 1998fa9e4066Sahrens 19990a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); 20000a586ceaSMark Shellenbaum 200189459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 200214843421SMatthew Ahrens if (fuid_dirtied) 200314843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 2004fa9e4066Sahrens 20050a586ceaSMark Shellenbaum /* 20060a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't 20070a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds 20080a586ceaSMark Shellenbaum */ 20090a586ceaSMark Shellenbaum 20100a586ceaSMark Shellenbaum if (ZFS_EXTERNAL_ACL(zp)) { 20110a586ceaSMark Shellenbaum if (zfsvfs->z_version <= ZPL_VERSION_SA && 20120a586ceaSMark Shellenbaum ZNODE_ACL_VERSION(zp) <= ZFS_ACL_VERSION_INITIAL) { 20130a586ceaSMark Shellenbaum dmu_tx_hold_free(tx, ZFS_EXTERNAL_ACL(zp), 0, 20140a586ceaSMark Shellenbaum DMU_OBJECT_END); 20150a586ceaSMark Shellenbaum } else { 20160a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, ZFS_EXTERNAL_ACL(zp), 20170a586ceaSMark Shellenbaum 0, aclp->z_acl_bytes); 20180a586ceaSMark Shellenbaum } 20190a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { 20200a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 20210a586ceaSMark Shellenbaum } 20220a586ceaSMark Shellenbaum 20230a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp); 20241209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 2025fa9e4066Sahrens if (error) { 2026fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2027fa9e4066Sahrens mutex_exit(&zp->z_lock); 2028fa9e4066Sahrens 20291209a471SNeil Perrin if (error == ERESTART) { 20308a2f1b91Sahrens dmu_tx_wait(tx); 20318a2f1b91Sahrens dmu_tx_abort(tx); 2032fa9e4066Sahrens goto top; 2033fa9e4066Sahrens } 20348a2f1b91Sahrens dmu_tx_abort(tx); 2035da6c28aaSamw zfs_acl_free(aclp); 2036fa9e4066Sahrens return (error); 2037fa9e4066Sahrens } 2038fa9e4066Sahrens 203989459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2040fa9e4066Sahrens ASSERT(error == 0); 20414929fd5eSTim Haley zp->z_acl_cached = aclp; 2042fa9e4066Sahrens 204389459e17SMark Shellenbaum if (fuid_dirtied) 204489459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 204589459e17SMark Shellenbaum 2046da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2047da6c28aaSamw 2048da6c28aaSamw if (fuidp) 2049da6c28aaSamw zfs_fuid_info_free(fuidp); 2050fa9e4066Sahrens dmu_tx_commit(tx); 2051fa9e4066Sahrens done: 2052fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2053fa9e4066Sahrens mutex_exit(&zp->z_lock); 2054fa9e4066Sahrens 2055fa9e4066Sahrens return (error); 2056fa9e4066Sahrens } 2057fa9e4066Sahrens 2058fa9e4066Sahrens /* 2059e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2060e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2061e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2062fa9e4066Sahrens */ 2063fa9e4066Sahrens static int 2064e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2065fa9e4066Sahrens { 2066fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2067fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2068f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2069f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2070fa9e4066Sahrens return (EROFS); 2071fa9e4066Sahrens } 2072fa9e4066Sahrens 2073da6c28aaSamw /* 2074da6c28aaSamw * Only check for READONLY on non-directories. 2075da6c28aaSamw */ 2076da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2077da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 20780a586ceaSMark Shellenbaum (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2079da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 20800a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_IMMUTABLE)))) { 2081da6c28aaSamw return (EPERM); 2082da6c28aaSamw } 2083da6c28aaSamw 2084da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 20850a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) { 2086da6c28aaSamw return (EPERM); 2087da6c28aaSamw } 2088da6c28aaSamw 2089da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 20900a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) { 2091da6c28aaSamw return (EACCES); 2092da6c28aaSamw } 2093da6c28aaSamw 2094da6c28aaSamw return (0); 2095da6c28aaSamw } 2096da6c28aaSamw 2097e802abbdSTim Haley /* 2098e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2099e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2100e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2101e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2102e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2103e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2104e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2105e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2106e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2107e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2108e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2109e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2110e802abbdSTim Haley * accesses. Returns: 2111e802abbdSTim Haley * 0 if all AoI granted 2112e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2113e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2114e802abbdSTim Haley * 2115e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2116e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2117e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2118e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2119e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2120e802abbdSTim Haley * is used in this manner. 2121e802abbdSTim Haley */ 2122e802abbdSTim Haley static int 2123e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2124e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2125e802abbdSTim Haley { 2126e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2127e802abbdSTim Haley zfs_acl_t *aclp; 2128e802abbdSTim Haley int error; 2129e802abbdSTim Haley uid_t uid = crgetuid(cr); 2130e802abbdSTim Haley uint64_t who; 2131e802abbdSTim Haley uint16_t type, iflags; 2132e802abbdSTim Haley uint16_t entry_type; 2133e802abbdSTim Haley uint32_t access_mask; 2134e802abbdSTim Haley uint32_t deny_mask = 0; 2135e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2136e802abbdSTim Haley boolean_t checkit; 21370a586ceaSMark Shellenbaum uint64_t gowner; 2138da6c28aaSamw 2139fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2140fa9e4066Sahrens 2141da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 2142ea8dc4b6Seschrock if (error != 0) { 2143ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2144ea8dc4b6Seschrock return (error); 2145ea8dc4b6Seschrock } 2146ea8dc4b6Seschrock 21470a586ceaSMark Shellenbaum ASSERT(zp->z_acl_cached); 21480a586ceaSMark Shellenbaum 21490a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs), 2150f3e6fb2fSMark Shellenbaum &gowner, sizeof (gowner))) != 0) { 2151f3e6fb2fSMark Shellenbaum mutex_exit(&zp->z_acl_lock); 21520a586ceaSMark Shellenbaum return (error); 2153f3e6fb2fSMark Shellenbaum } 21540a586ceaSMark Shellenbaum 2155da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2156da6c28aaSamw &iflags, &type)) { 2157e802abbdSTim Haley uint32_t mask_matched; 2158fa9e4066Sahrens 2159003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2160003c2582SMark Shellenbaum continue; 2161003c2582SMark Shellenbaum 2162b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2163fa9e4066Sahrens continue; 2164fa9e4066Sahrens 2165e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2166e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2167e802abbdSTim Haley if (!mask_matched) 2168e802abbdSTim Haley continue; 2169e802abbdSTim Haley 2170da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2171da6c28aaSamw 2172da6c28aaSamw checkit = B_FALSE; 2173da6c28aaSamw 2174fa9e4066Sahrens switch (entry_type) { 2175fa9e4066Sahrens case ACE_OWNER: 21760a586ceaSMark Shellenbaum if (uid == zp->z_uid) 2177da6c28aaSamw checkit = B_TRUE; 2178fa9e4066Sahrens break; 2179da6c28aaSamw case OWNING_GROUP: 2180da6c28aaSamw who = gowner; 2181da6c28aaSamw /*FALLTHROUGH*/ 2182fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2183da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2184fa9e4066Sahrens break; 2185fa9e4066Sahrens case ACE_EVERYONE: 2186da6c28aaSamw checkit = B_TRUE; 2187fa9e4066Sahrens break; 2188fa9e4066Sahrens 2189fa9e4066Sahrens /* USER Entry */ 2190fa9e4066Sahrens default: 2191fa9e4066Sahrens if (entry_type == 0) { 2192da6c28aaSamw uid_t newid; 2193da6c28aaSamw 2194e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2195e0d35c44Smarks ZFS_ACE_USER); 2196da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2197da6c28aaSamw uid == newid) 2198da6c28aaSamw checkit = B_TRUE; 2199fa9e4066Sahrens break; 2200da6c28aaSamw } else { 2201fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2202fa9e4066Sahrens return (EIO); 2203fa9e4066Sahrens } 2204da6c28aaSamw } 2205da6c28aaSamw 2206da6c28aaSamw if (checkit) { 2207e802abbdSTim Haley if (type == DENY) { 2208e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2209e802abbdSTim Haley znode_t *, zp, 2210e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2211e802abbdSTim Haley uint32_t, mask_matched); 221290fafcf0Smarks deny_mask |= mask_matched; 2213e802abbdSTim Haley } else { 2214e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2215e802abbdSTim Haley znode_t *, zp, 2216e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2217e802abbdSTim Haley uint32_t, mask_matched); 2218e802abbdSTim Haley if (anyaccess) { 2219e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2220e802abbdSTim Haley return (0); 2221da6c28aaSamw } 2222da6c28aaSamw } 2223e802abbdSTim Haley *working_mode &= ~mask_matched; 2224e802abbdSTim Haley } 2225fa9e4066Sahrens 222690fafcf0Smarks /* Are we done? */ 222790fafcf0Smarks if (*working_mode == 0) 2228fa9e4066Sahrens break; 2229fa9e4066Sahrens } 2230fa9e4066Sahrens 2231fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 223290fafcf0Smarks 223390fafcf0Smarks /* Put the found 'denies' back on the working mode */ 22347ed7e920Smarks if (deny_mask) { 223590fafcf0Smarks *working_mode |= deny_mask; 223690fafcf0Smarks return (EACCES); 22377ed7e920Smarks } else if (*working_mode) { 22387ed7e920Smarks return (-1); 22397ed7e920Smarks } 224090fafcf0Smarks 224190fafcf0Smarks return (0); 2242fa9e4066Sahrens } 2243fa9e4066Sahrens 2244e802abbdSTim Haley /* 2245e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2246e802abbdSTim Haley * care what access is granted. 2247e802abbdSTim Haley */ 2248e802abbdSTim Haley boolean_t 2249e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2250e802abbdSTim Haley { 2251e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2252e802abbdSTim Haley 2253e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2254*134a1f4eSCasper H.S. Dik return (secpolicy_vnode_any_access(cr, ZTOV(zp), 2255*134a1f4eSCasper H.S. Dik zp->z_uid) == 0); 2256e802abbdSTim Haley } 2257e802abbdSTim Haley return (B_TRUE); 2258e802abbdSTim Haley } 2259e802abbdSTim Haley 2260e802abbdSTim Haley static int 2261e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2262e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2263e802abbdSTim Haley { 2264e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2265e802abbdSTim Haley int err; 2266e802abbdSTim Haley 2267e802abbdSTim Haley *working_mode = v4_mode; 2268e802abbdSTim Haley *check_privs = B_TRUE; 2269e802abbdSTim Haley 2270e802abbdSTim Haley /* 2271e802abbdSTim Haley * Short circuit empty requests 2272e802abbdSTim Haley */ 2273e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2274e802abbdSTim Haley *working_mode = 0; 2275e802abbdSTim Haley return (0); 2276e802abbdSTim Haley } 2277e802abbdSTim Haley 2278e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2279e802abbdSTim Haley *check_privs = B_FALSE; 2280e802abbdSTim Haley return (err); 2281e802abbdSTim Haley } 2282e802abbdSTim Haley 2283e802abbdSTim Haley /* 2284e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2285e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2286e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2287e802abbdSTim Haley */ 2288e802abbdSTim Haley if (skipaclchk) { 2289e802abbdSTim Haley *working_mode = 0; 2290e802abbdSTim Haley return (0); 2291e802abbdSTim Haley } 2292e802abbdSTim Haley 2293e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2294e802abbdSTim Haley } 2295e802abbdSTim Haley 2296da6c28aaSamw static int 2297da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2298da6c28aaSamw cred_t *cr) 2299da6c28aaSamw { 2300da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2301da6c28aaSamw return (EACCES); 2302da6c28aaSamw 2303da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2304da6c28aaSamw check_privs, B_FALSE, cr)); 2305da6c28aaSamw } 2306fa9e4066Sahrens 2307d47621a4STim Haley int 2308d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2309d47621a4STim Haley { 2310d47621a4STim Haley boolean_t owner = B_FALSE; 2311d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2312d47621a4STim Haley boolean_t is_attr; 2313d47621a4STim Haley uid_t uid = crgetuid(cr); 2314d47621a4STim Haley int error; 2315d47621a4STim Haley 23160a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED) 2317d47621a4STim Haley return (EACCES); 2318d47621a4STim Haley 23190a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) && 2320d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2321d47621a4STim Haley if (is_attr) 2322d47621a4STim Haley goto slow; 2323d47621a4STim Haley 23240a586ceaSMark Shellenbaum 2325d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2326d47621a4STim Haley 23270a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) { 2328d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2329d47621a4STim Haley return (0); 2330d47621a4STim Haley } 2331d47621a4STim Haley 23320a586ceaSMark Shellenbaum if (IS_EPHEMERAL(zdp->z_uid) != 0 || IS_EPHEMERAL(zdp->z_gid) != 0) { 2333d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2334d47621a4STim Haley goto slow; 2335d47621a4STim Haley } 2336d47621a4STim Haley 23370a586ceaSMark Shellenbaum if (uid == zdp->z_uid) { 2338d47621a4STim Haley owner = B_TRUE; 23390a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) { 2340d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2341d47621a4STim Haley return (0); 2342e4f96946STim Haley } else { 2343e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2344e4f96946STim Haley goto slow; 2345d47621a4STim Haley } 2346d47621a4STim Haley } 23470a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) { 2348d47621a4STim Haley groupmbr = B_TRUE; 23490a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) { 2350d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2351d47621a4STim Haley return (0); 2352e4f96946STim Haley } else { 2353e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2354e4f96946STim Haley goto slow; 2355d47621a4STim Haley } 2356d47621a4STim Haley } 2357d47621a4STim Haley if (!owner && !groupmbr) { 23580a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) { 2359d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2360d47621a4STim Haley return (0); 2361d47621a4STim Haley } 2362d47621a4STim Haley } 2363d47621a4STim Haley 2364d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2365d47621a4STim Haley 2366d47621a4STim Haley slow: 2367d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2368d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2369d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2370d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2371d47621a4STim Haley return (error); 2372d47621a4STim Haley } 2373d47621a4STim Haley 2374fa9e4066Sahrens /* 2375*134a1f4eSCasper H.S. Dik * Determine whether Access should be granted/denied. 2376*134a1f4eSCasper H.S. Dik * The least priv subsytem is always consulted as a basic privilege 2377*134a1f4eSCasper H.S. Dik * can define any form of access. 2378fa9e4066Sahrens */ 2379fa9e4066Sahrens int 2380da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2381fa9e4066Sahrens { 2382da6c28aaSamw uint32_t working_mode; 2383fa9e4066Sahrens int error; 2384fa9e4066Sahrens int is_attr; 2385da6c28aaSamw boolean_t check_privs; 2386fa9e4066Sahrens znode_t *xzp; 2387fa9e4066Sahrens znode_t *check_zp = zp; 2388*134a1f4eSCasper H.S. Dik mode_t needed_bits; 2389fa9e4066Sahrens 23900a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); 2391fa9e4066Sahrens 2392fa9e4066Sahrens /* 2393fa9e4066Sahrens * If attribute then validate against base file 2394fa9e4066Sahrens */ 2395fa9e4066Sahrens if (is_attr) { 23960a586ceaSMark Shellenbaum uint64_t parent; 23970a586ceaSMark Shellenbaum 23980a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 23990a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent, 24000a586ceaSMark Shellenbaum sizeof (parent))) != 0) 24010a586ceaSMark Shellenbaum return (error); 24020a586ceaSMark Shellenbaum 2403fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 24040a586ceaSMark Shellenbaum parent, &xzp)) != 0) { 2405fa9e4066Sahrens return (error); 2406fa9e4066Sahrens } 2407da6c28aaSamw 2408fa9e4066Sahrens check_zp = xzp; 2409da6c28aaSamw 2410fa9e4066Sahrens /* 2411fa9e4066Sahrens * fixup mode to map to xattr perms 2412fa9e4066Sahrens */ 2413fa9e4066Sahrens 2414fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2415fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2416fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2417fa9e4066Sahrens } 2418fa9e4066Sahrens 2419fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2420fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2421fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2422fa9e4066Sahrens } 2423fa9e4066Sahrens } 2424fa9e4066Sahrens 2425*134a1f4eSCasper H.S. Dik /* 2426*134a1f4eSCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC 2427*134a1f4eSCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently 2428*134a1f4eSCasper H.S. Dik * missing) in missing_bits. 2429*134a1f4eSCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode), 2430*134a1f4eSCasper H.S. Dik * needed_bits. 2431*134a1f4eSCasper H.S. Dik */ 2432*134a1f4eSCasper H.S. Dik needed_bits = 0; 2433*134a1f4eSCasper H.S. Dik 2434*134a1f4eSCasper H.S. Dik working_mode = mode; 2435*134a1f4eSCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && 2436*134a1f4eSCasper H.S. Dik zp->z_uid == crgetuid(cr)) 2437*134a1f4eSCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2438*134a1f4eSCasper H.S. Dik 2439*134a1f4eSCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 2440*134a1f4eSCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2441*134a1f4eSCasper H.S. Dik needed_bits |= VREAD; 2442*134a1f4eSCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 2443*134a1f4eSCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2444*134a1f4eSCasper H.S. Dik needed_bits |= VWRITE; 2445*134a1f4eSCasper H.S. Dik if (working_mode & ACE_EXECUTE) 2446*134a1f4eSCasper H.S. Dik needed_bits |= VEXEC; 2447*134a1f4eSCasper H.S. Dik 2448da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2449da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2450da6c28aaSamw if (is_attr) 2451da6c28aaSamw VN_RELE(ZTOV(xzp)); 2452*134a1f4eSCasper H.S. Dik return (secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid, 2453*134a1f4eSCasper H.S. Dik needed_bits, needed_bits)); 2454da6c28aaSamw } 2455fa9e4066Sahrens 2456e0d35c44Smarks if (error && !check_privs) { 2457fa9e4066Sahrens if (is_attr) 2458fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2459fa9e4066Sahrens return (error); 2460fa9e4066Sahrens } 2461fa9e4066Sahrens 2462da6c28aaSamw if (error && (flags & V_APPEND)) { 2463da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2464fa9e4066Sahrens } 2465fa9e4066Sahrens 2466da6c28aaSamw if (error && check_privs) { 2467da6c28aaSamw mode_t checkmode = 0; 2468fa9e4066Sahrens 2469fa9e4066Sahrens /* 2470da6c28aaSamw * First check for implicit owner permission on 2471da6c28aaSamw * read_acl/read_attributes 2472fa9e4066Sahrens */ 2473fa9e4066Sahrens 2474da6c28aaSamw error = 0; 2475da6c28aaSamw ASSERT(working_mode != 0); 2476da6c28aaSamw 2477da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 24780a586ceaSMark Shellenbaum zp->z_uid == crgetuid(cr))) 2479da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2480da6c28aaSamw 2481da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 248247def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2483da6c28aaSamw checkmode |= VREAD; 2484da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 248547def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2486da6c28aaSamw checkmode |= VWRITE; 2487da6c28aaSamw if (working_mode & ACE_EXECUTE) 2488da6c28aaSamw checkmode |= VEXEC; 2489da6c28aaSamw 2490*134a1f4eSCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(check_zp), zp->z_uid, 2491*134a1f4eSCasper H.S. Dik needed_bits & ~checkmode, needed_bits); 2492da6c28aaSamw 2493da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 24940a586ceaSMark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid); 2495da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 24960a586ceaSMark Shellenbaum error = secpolicy_vnode_setdac(cr, zp->z_uid); 2497da6c28aaSamw 2498da6c28aaSamw if (error == 0 && (working_mode & 2499da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2500da6c28aaSamw error = secpolicy_vnode_remove(cr); 2501da6c28aaSamw 250247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 25030a586ceaSMark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid); 250447def0dcSMark Shellenbaum } 2505da6c28aaSamw if (error == 0) { 2506da6c28aaSamw /* 2507da6c28aaSamw * See if any bits other than those already checked 2508da6c28aaSamw * for are still present. If so then return EACCES 2509da6c28aaSamw */ 2510da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2511da6c28aaSamw error = EACCES; 2512da6c28aaSamw } 2513da6c28aaSamw } 2514*134a1f4eSCasper H.S. Dik } else if (error == 0) { 2515*134a1f4eSCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid, 2516*134a1f4eSCasper H.S. Dik needed_bits, needed_bits); 2517da6c28aaSamw } 2518da6c28aaSamw 2519*134a1f4eSCasper H.S. Dik 2520da6c28aaSamw if (is_attr) 2521da6c28aaSamw VN_RELE(ZTOV(xzp)); 2522da6c28aaSamw 2523da6c28aaSamw return (error); 2524fa9e4066Sahrens } 2525fa9e4066Sahrens 2526fa9e4066Sahrens /* 2527da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2528fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2529fa9e4066Sahrens */ 2530fa9e4066Sahrens int 2531da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2532da6c28aaSamw { 2533da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2534da6c28aaSamw } 2535da6c28aaSamw 2536da6c28aaSamw /* 2537da6c28aaSamw * Access function for secpolicy_vnode_setattr 2538da6c28aaSamw */ 2539da6c28aaSamw int 2540da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2541fa9e4066Sahrens { 2542fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2543fa9e4066Sahrens 2544da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2545fa9e4066Sahrens } 2546fa9e4066Sahrens 254747db7e74Smarks static int 254823d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 2549*134a1f4eSCasper H.S. Dik mode_t available_perms, cred_t *cr) 255047db7e74Smarks { 255147db7e74Smarks int error; 255247db7e74Smarks 2553*134a1f4eSCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(dzp), 2554*134a1f4eSCasper H.S. Dik dzp->z_uid, available_perms, VWRITE|VEXEC); 255547db7e74Smarks 255647db7e74Smarks if (error == 0) 255747db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 255847db7e74Smarks 255947db7e74Smarks return (error); 256047db7e74Smarks } 256147db7e74Smarks 2562fa9e4066Sahrens /* 2563fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2564fa9e4066Sahrens * consulting least priv subsystem. 2565fa9e4066Sahrens * 2566fa9e4066Sahrens * 2567fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2568fa9e4066Sahrens * ability to delete an object. 2569fa9e4066Sahrens * 2570fa9e4066Sahrens * ------------------------------------------------------- 2571fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2572fa9e4066Sahrens * | permissions | | 2573fa9e4066Sahrens * ------------------------------------------------------- 2574fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2575fa9e4066Sahrens * | | Delete | Delete | unspecified| 2576fa9e4066Sahrens * ------------------------------------------------------- 2577fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2578fa9e4066Sahrens * | DELETE_CHILD | | 2579fa9e4066Sahrens * ------------------------------------------------------- 2580fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2581fa9e4066Sahrens * | DELETE_CHILD | | | | 2582fa9e4066Sahrens * ------------------------------------------------------- 2583fa9e4066Sahrens * | ACL specifies | | | | 2584fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2585fa9e4066Sahrens * | write and | | | | 2586fa9e4066Sahrens * | execute | | | | 2587fa9e4066Sahrens * ------------------------------------------------------- 2588fa9e4066Sahrens * | ACL denies | | | | 2589fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2590fa9e4066Sahrens * | execute | | | | 2591fa9e4066Sahrens * ------------------------------------------------------- 2592fa9e4066Sahrens * ^ 2593fa9e4066Sahrens * | 2594fa9e4066Sahrens * No search privilege, can't even look up file? 2595fa9e4066Sahrens * 2596fa9e4066Sahrens */ 2597fa9e4066Sahrens int 2598fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2599fa9e4066Sahrens { 2600da6c28aaSamw uint32_t dzp_working_mode = 0; 2601da6c28aaSamw uint32_t zp_working_mode = 0; 2602fa9e4066Sahrens int dzp_error, zp_error; 2603*134a1f4eSCasper H.S. Dik mode_t available_perms; 2604da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2605da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2606fa9e4066Sahrens 2607fa9e4066Sahrens /* 260823d5bb1fSmarks * We want specific DELETE permissions to 2609fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2610fa9e4066Sahrens * want an ACL such as this to mess us up. 261147db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2612fa9e4066Sahrens * 2613fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2614fa9e4066Sahrens * by secpolicy_vnode_access(). 261523d5bb1fSmarks * 261623d5bb1fSmarks * We will ask for all of the necessary permissions and then 261723d5bb1fSmarks * look at the working modes from the directory and target object 261823d5bb1fSmarks * to determine what was found. 2619fa9e4066Sahrens */ 2620fa9e4066Sahrens 26210a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2622da6c28aaSamw return (EPERM); 2623fa9e4066Sahrens 262423d5bb1fSmarks /* 26257ed7e920Smarks * First row 262623d5bb1fSmarks * If the directory permissions allow the delete, we are done. 262723d5bb1fSmarks */ 26287ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 262923d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 263023d5bb1fSmarks return (0); 2631da6c28aaSamw 263223d5bb1fSmarks /* 263323d5bb1fSmarks * If target object has delete permission then we are done 263423d5bb1fSmarks */ 263523d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 263623d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 263723d5bb1fSmarks return (0); 263823d5bb1fSmarks 26397ed7e920Smarks ASSERT(dzp_error && zp_error); 26407ed7e920Smarks 264123d5bb1fSmarks if (!dzpcheck_privs) 2642fa9e4066Sahrens return (dzp_error); 26437ed7e920Smarks if (!zpcheck_privs) 264423d5bb1fSmarks return (zp_error); 2645fa9e4066Sahrens 2646fa9e4066Sahrens /* 2647fa9e4066Sahrens * Second row 26487ed7e920Smarks * 26497ed7e920Smarks * If directory returns EACCES then delete_child was denied 26507ed7e920Smarks * due to deny delete_child. In this case send the request through 26517ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 26527ed7e920Smarks * since that *could* allow the delete based on write/execute permission 26537ed7e920Smarks * and we want delete permissions to override write/execute. 2654fa9e4066Sahrens */ 2655fa9e4066Sahrens 265647db7e74Smarks if (dzp_error == EACCES) 26577ed7e920Smarks return (secpolicy_vnode_remove(cr)); 265847db7e74Smarks 265947db7e74Smarks /* 2660fa9e4066Sahrens * Third Row 266123d5bb1fSmarks * only need to see if we have write/execute on directory. 2662fa9e4066Sahrens */ 2663fa9e4066Sahrens 2664*134a1f4eSCasper H.S. Dik dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 2665*134a1f4eSCasper H.S. Dik &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); 2666fa9e4066Sahrens 2667*134a1f4eSCasper H.S. Dik if (dzp_error != 0 && !dzpcheck_privs) 26687ed7e920Smarks return (dzp_error); 26697ed7e920Smarks 2670fa9e4066Sahrens /* 26717ed7e920Smarks * Fourth row 2672fa9e4066Sahrens */ 2673fa9e4066Sahrens 2674*134a1f4eSCasper H.S. Dik available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE; 2675*134a1f4eSCasper H.S. Dik available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC; 26767ed7e920Smarks 2677*134a1f4eSCasper H.S. Dik return (zfs_delete_final_check(zp, dzp, available_perms, cr)); 26787ed7e920Smarks 2679fa9e4066Sahrens } 2680fa9e4066Sahrens 2681fa9e4066Sahrens int 2682fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2683fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2684fa9e4066Sahrens { 2685fa9e4066Sahrens int add_perm; 2686fa9e4066Sahrens int error; 2687fa9e4066Sahrens 26880a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED) 2689da6c28aaSamw return (EACCES); 2690da6c28aaSamw 2691fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2692fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2693fa9e4066Sahrens 2694fa9e4066Sahrens /* 2695fa9e4066Sahrens * Rename permissions are combination of delete permission + 2696fa9e4066Sahrens * add file/subdir permission. 2697fa9e4066Sahrens */ 2698fa9e4066Sahrens 2699fa9e4066Sahrens /* 2700fa9e4066Sahrens * first make sure we do the delete portion. 2701fa9e4066Sahrens * 2702fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2703fa9e4066Sahrens */ 2704fa9e4066Sahrens 2705fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2706fa9e4066Sahrens return (error); 2707fa9e4066Sahrens 2708fa9e4066Sahrens /* 2709fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2710fa9e4066Sahrens */ 2711fa9e4066Sahrens if (tzp) { 2712fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2713fa9e4066Sahrens return (error); 2714fa9e4066Sahrens } 2715fa9e4066Sahrens 2716fa9e4066Sahrens /* 2717fa9e4066Sahrens * Now check for add permissions 2718fa9e4066Sahrens */ 2719da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2720fa9e4066Sahrens 2721fa9e4066Sahrens return (error); 2722fa9e4066Sahrens } 2723