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. 23*a3c49ce1SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/time.h> 29fa9e4066Sahrens #include <sys/systm.h> 30fa9e4066Sahrens #include <sys/sysmacros.h> 31fa9e4066Sahrens #include <sys/resource.h> 32fa9e4066Sahrens #include <sys/vfs.h> 33fa9e4066Sahrens #include <sys/vnode.h> 34da6c28aaSamw #include <sys/sid.h> 35fa9e4066Sahrens #include <sys/file.h> 36fa9e4066Sahrens #include <sys/stat.h> 37fa9e4066Sahrens #include <sys/kmem.h> 38fa9e4066Sahrens #include <sys/cmn_err.h> 39fa9e4066Sahrens #include <sys/errno.h> 40fa9e4066Sahrens #include <sys/unistd.h> 41169cdae2Smarks #include <sys/sdt.h> 42fa9e4066Sahrens #include <sys/fs/zfs.h> 43fa9e4066Sahrens #include <sys/mode.h> 44fa9e4066Sahrens #include <sys/policy.h> 45fa9e4066Sahrens #include <sys/zfs_znode.h> 46da6c28aaSamw #include <sys/zfs_fuid.h> 47fa9e4066Sahrens #include <sys/zfs_acl.h> 48fa9e4066Sahrens #include <sys/zfs_dir.h> 49fa9e4066Sahrens #include <sys/zfs_vfsops.h> 50fa9e4066Sahrens #include <sys/dmu.h> 51da6c28aaSamw #include <sys/dnode.h> 52fa9e4066Sahrens #include <sys/zap.h> 530a586ceaSMark Shellenbaum #include <sys/sa.h> 54fa9e4066Sahrens #include "fs/fs_subr.h" 55fa9e4066Sahrens #include <acl/acl_common.h> 56fa9e4066Sahrens 57fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 58fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 59da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 60003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW 61fa9e4066Sahrens 62fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 63fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 64fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 65fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 66fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 67fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 68fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 69da6c28aaSamw 70da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 71da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 72da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 73da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 74da6c28aaSamw 75f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS) 76f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \ 77f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD) 78f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS) 79fa9e4066Sahrens 80fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 81fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 82fa9e4066Sahrens 83fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 84fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 85fa9e4066Sahrens 86fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \ 87da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE) 88fa9e4066Sahrens 89b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER) 90fa9e4066Sahrens 91da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\ 92da6c28aaSamw ZFS_ACL_PROTECTED) 93fa9e4066Sahrens 94da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 95da6c28aaSamw ZFS_ACL_OBJ_ACE) 96da6c28aaSamw 974929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) 984929fd5eSTim Haley 99da6c28aaSamw static uint16_t 100da6c28aaSamw zfs_ace_v0_get_type(void *acep) 101da6c28aaSamw { 102da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type); 103da6c28aaSamw } 104da6c28aaSamw 105da6c28aaSamw static uint16_t 106da6c28aaSamw zfs_ace_v0_get_flags(void *acep) 107da6c28aaSamw { 108da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags); 109da6c28aaSamw } 110da6c28aaSamw 111da6c28aaSamw static uint32_t 112da6c28aaSamw zfs_ace_v0_get_mask(void *acep) 113da6c28aaSamw { 114da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask); 115da6c28aaSamw } 116da6c28aaSamw 117da6c28aaSamw static uint64_t 118da6c28aaSamw zfs_ace_v0_get_who(void *acep) 119da6c28aaSamw { 120da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid); 121da6c28aaSamw } 122da6c28aaSamw 123da6c28aaSamw static void 124da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type) 125da6c28aaSamw { 126da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type; 127da6c28aaSamw } 128da6c28aaSamw 129da6c28aaSamw static void 130da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags) 131da6c28aaSamw { 132da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags; 133da6c28aaSamw } 134da6c28aaSamw 135da6c28aaSamw static void 136da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask) 137da6c28aaSamw { 138da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask; 139da6c28aaSamw } 140da6c28aaSamw 141da6c28aaSamw static void 142da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who) 143da6c28aaSamw { 144da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who; 145da6c28aaSamw } 146da6c28aaSamw 147da6c28aaSamw /*ARGSUSED*/ 148da6c28aaSamw static size_t 149da6c28aaSamw zfs_ace_v0_size(void *acep) 150da6c28aaSamw { 151da6c28aaSamw return (sizeof (zfs_oldace_t)); 152da6c28aaSamw } 153da6c28aaSamw 154da6c28aaSamw static size_t 155da6c28aaSamw zfs_ace_v0_abstract_size(void) 156da6c28aaSamw { 157da6c28aaSamw return (sizeof (zfs_oldace_t)); 158da6c28aaSamw } 159da6c28aaSamw 160da6c28aaSamw static int 161da6c28aaSamw zfs_ace_v0_mask_off(void) 162da6c28aaSamw { 163da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask)); 164da6c28aaSamw } 165da6c28aaSamw 166da6c28aaSamw /*ARGSUSED*/ 167da6c28aaSamw static int 168da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap) 169da6c28aaSamw { 170da6c28aaSamw *datap = NULL; 171da6c28aaSamw return (0); 172da6c28aaSamw } 173da6c28aaSamw 174da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = { 175da6c28aaSamw zfs_ace_v0_get_mask, 176da6c28aaSamw zfs_ace_v0_set_mask, 177da6c28aaSamw zfs_ace_v0_get_flags, 178da6c28aaSamw zfs_ace_v0_set_flags, 179da6c28aaSamw zfs_ace_v0_get_type, 180da6c28aaSamw zfs_ace_v0_set_type, 181da6c28aaSamw zfs_ace_v0_get_who, 182da6c28aaSamw zfs_ace_v0_set_who, 183da6c28aaSamw zfs_ace_v0_size, 184da6c28aaSamw zfs_ace_v0_abstract_size, 185da6c28aaSamw zfs_ace_v0_mask_off, 186da6c28aaSamw zfs_ace_v0_data 187da6c28aaSamw }; 188da6c28aaSamw 189da6c28aaSamw static uint16_t 190da6c28aaSamw zfs_ace_fuid_get_type(void *acep) 191da6c28aaSamw { 192da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type); 193da6c28aaSamw } 194da6c28aaSamw 195da6c28aaSamw static uint16_t 196da6c28aaSamw zfs_ace_fuid_get_flags(void *acep) 197da6c28aaSamw { 198da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags); 199da6c28aaSamw } 200da6c28aaSamw 201da6c28aaSamw static uint32_t 202da6c28aaSamw zfs_ace_fuid_get_mask(void *acep) 203da6c28aaSamw { 204da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask); 205da6c28aaSamw } 206da6c28aaSamw 207da6c28aaSamw static uint64_t 208da6c28aaSamw zfs_ace_fuid_get_who(void *args) 209da6c28aaSamw { 210da6c28aaSamw uint16_t entry_type; 211da6c28aaSamw zfs_ace_t *acep = args; 212da6c28aaSamw 213da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 214da6c28aaSamw 215da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 216da6c28aaSamw entry_type == ACE_EVERYONE) 217da6c28aaSamw return (-1); 218da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid); 219da6c28aaSamw } 220da6c28aaSamw 221da6c28aaSamw static void 222da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type) 223da6c28aaSamw { 224da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type; 225da6c28aaSamw } 226da6c28aaSamw 227da6c28aaSamw static void 228da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags) 229da6c28aaSamw { 230da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags; 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw static void 234da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask) 235da6c28aaSamw { 236da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask; 237da6c28aaSamw } 238da6c28aaSamw 239da6c28aaSamw static void 240da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who) 241da6c28aaSamw { 242da6c28aaSamw zfs_ace_t *acep = arg; 243da6c28aaSamw 244da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 245da6c28aaSamw 246da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 247da6c28aaSamw entry_type == ACE_EVERYONE) 248da6c28aaSamw return; 249da6c28aaSamw acep->z_fuid = who; 250da6c28aaSamw } 251da6c28aaSamw 252da6c28aaSamw static size_t 253da6c28aaSamw zfs_ace_fuid_size(void *acep) 254da6c28aaSamw { 255da6c28aaSamw zfs_ace_hdr_t *zacep = acep; 256da6c28aaSamw uint16_t entry_type; 257da6c28aaSamw 258da6c28aaSamw switch (zacep->z_type) { 259da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 260da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 261da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 262da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 263da6c28aaSamw return (sizeof (zfs_object_ace_t)); 264da6c28aaSamw case ALLOW: 265da6c28aaSamw case DENY: 266da6c28aaSamw entry_type = 267da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS); 268da6c28aaSamw if (entry_type == ACE_OWNER || 2691ab99678SMark Shellenbaum entry_type == OWNING_GROUP || 270da6c28aaSamw entry_type == ACE_EVERYONE) 271da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 272da6c28aaSamw /*FALLTHROUGH*/ 273da6c28aaSamw default: 274da6c28aaSamw return (sizeof (zfs_ace_t)); 275da6c28aaSamw } 276da6c28aaSamw } 277da6c28aaSamw 278da6c28aaSamw static size_t 279da6c28aaSamw zfs_ace_fuid_abstract_size(void) 280da6c28aaSamw { 281da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 282da6c28aaSamw } 283da6c28aaSamw 284da6c28aaSamw static int 285da6c28aaSamw zfs_ace_fuid_mask_off(void) 286da6c28aaSamw { 287da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 288da6c28aaSamw } 289da6c28aaSamw 290da6c28aaSamw static int 291da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap) 292da6c28aaSamw { 293da6c28aaSamw zfs_ace_t *zacep = acep; 294da6c28aaSamw zfs_object_ace_t *zobjp; 295da6c28aaSamw 296da6c28aaSamw switch (zacep->z_hdr.z_type) { 297da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 298da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 299da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 300da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 301da6c28aaSamw zobjp = acep; 302da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t); 303da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t)); 304da6c28aaSamw default: 305da6c28aaSamw *datap = NULL; 306da6c28aaSamw return (0); 307da6c28aaSamw } 308da6c28aaSamw } 309da6c28aaSamw 310da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = { 311da6c28aaSamw zfs_ace_fuid_get_mask, 312da6c28aaSamw zfs_ace_fuid_set_mask, 313da6c28aaSamw zfs_ace_fuid_get_flags, 314da6c28aaSamw zfs_ace_fuid_set_flags, 315da6c28aaSamw zfs_ace_fuid_get_type, 316da6c28aaSamw zfs_ace_fuid_set_type, 317da6c28aaSamw zfs_ace_fuid_get_who, 318da6c28aaSamw zfs_ace_fuid_set_who, 319da6c28aaSamw zfs_ace_fuid_size, 320da6c28aaSamw zfs_ace_fuid_abstract_size, 321da6c28aaSamw zfs_ace_fuid_mask_off, 322da6c28aaSamw zfs_ace_fuid_data 323da6c28aaSamw }; 324da6c28aaSamw 3250a586ceaSMark Shellenbaum /* 3260a586ceaSMark Shellenbaum * The following three functions are provided for compatibility with 3270a586ceaSMark Shellenbaum * older ZPL version in order to determine if the file use to have 3280a586ceaSMark Shellenbaum * an external ACL and what version of ACL previously existed on the 3290a586ceaSMark Shellenbaum * file. Would really be nice to not need this, sigh. 3300a586ceaSMark Shellenbaum */ 3310a586ceaSMark Shellenbaum uint64_t 3320a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp) 3330a586ceaSMark Shellenbaum { 3340a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 3351412a1a2SMark Shellenbaum int error; 3360a586ceaSMark Shellenbaum 3370a586ceaSMark Shellenbaum if (zp->z_is_sa) 3380a586ceaSMark Shellenbaum return (0); 3390a586ceaSMark Shellenbaum 3401412a1a2SMark Shellenbaum /* 3411412a1a2SMark Shellenbaum * Need to deal with a potential 3421412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause 3431412a1a2SMark Shellenbaum * z_isa_sa to change. 3441412a1a2SMark Shellenbaum * 3451412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have 3461412a1a2SMark Shellenbaum * changed. 3471412a1a2SMark Shellenbaum */ 3480a586ceaSMark Shellenbaum 3491412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 3501412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0) 3510a586ceaSMark Shellenbaum return (acl_phys.z_acl_extern_obj); 3521412a1a2SMark Shellenbaum else { 3531412a1a2SMark Shellenbaum /* 3541412a1a2SMark Shellenbaum * after upgrade the SA_ZPL_ZNODE_ACL should have been 3551412a1a2SMark Shellenbaum * removed 3561412a1a2SMark Shellenbaum */ 3571412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT); 3581412a1a2SMark Shellenbaum return (0); 3591412a1a2SMark Shellenbaum } 3600a586ceaSMark Shellenbaum } 3610a586ceaSMark Shellenbaum 3620a586ceaSMark Shellenbaum /* 3630a586ceaSMark Shellenbaum * Determine size of ACL in bytes 3640a586ceaSMark Shellenbaum * 3650a586ceaSMark Shellenbaum * This is more complicated than it should be since we have to deal 3660a586ceaSMark Shellenbaum * with old external ACLs. 3670a586ceaSMark Shellenbaum */ 3680a586ceaSMark Shellenbaum static int 3690a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount, 3700a586ceaSMark Shellenbaum zfs_acl_phys_t *aclphys) 3710a586ceaSMark Shellenbaum { 3720a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs; 3730a586ceaSMark Shellenbaum uint64_t acl_count; 3740a586ceaSMark Shellenbaum int size; 3750a586ceaSMark Shellenbaum int error; 3760a586ceaSMark Shellenbaum 3771412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 3780a586ceaSMark Shellenbaum if (zp->z_is_sa) { 3790a586ceaSMark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs), 3800a586ceaSMark Shellenbaum &size)) != 0) 3810a586ceaSMark Shellenbaum return (error); 3820a586ceaSMark Shellenbaum *aclsize = size; 3830a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs), 3840a586ceaSMark Shellenbaum &acl_count, sizeof (acl_count))) != 0) 3850a586ceaSMark Shellenbaum return (error); 3860a586ceaSMark Shellenbaum *aclcount = acl_count; 3870a586ceaSMark Shellenbaum } else { 3880a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 3890a586ceaSMark Shellenbaum aclphys, sizeof (*aclphys))) != 0) 3900a586ceaSMark Shellenbaum return (error); 3910a586ceaSMark Shellenbaum 3920a586ceaSMark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) { 3930a586ceaSMark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size); 3940a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_size; 3950a586ceaSMark Shellenbaum } else { 3960a586ceaSMark Shellenbaum *aclsize = aclphys->z_acl_size; 3970a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_count; 3980a586ceaSMark Shellenbaum } 3990a586ceaSMark Shellenbaum } 4000a586ceaSMark Shellenbaum return (0); 4010a586ceaSMark Shellenbaum } 4020a586ceaSMark Shellenbaum 4030a586ceaSMark Shellenbaum int 4040a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp) 4050a586ceaSMark Shellenbaum { 4060a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 4070a586ceaSMark Shellenbaum 4081412a1a2SMark Shellenbaum if (zp->z_is_sa) 4090a586ceaSMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 4101412a1a2SMark Shellenbaum else { 4111412a1a2SMark Shellenbaum int error; 4121412a1a2SMark Shellenbaum 4131412a1a2SMark Shellenbaum /* 4141412a1a2SMark Shellenbaum * Need to deal with a potential 4151412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause 4161412a1a2SMark Shellenbaum * z_isa_sa to change. 4171412a1a2SMark Shellenbaum * 4181412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have 4191412a1a2SMark Shellenbaum * changed. 4201412a1a2SMark Shellenbaum */ 4211412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 4220a586ceaSMark Shellenbaum SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 4231412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0) 4240a586ceaSMark Shellenbaum return (acl_phys.z_acl_version); 4251412a1a2SMark Shellenbaum else { 4261412a1a2SMark Shellenbaum /* 4271412a1a2SMark Shellenbaum * After upgrade SA_ZPL_ZNODE_ACL should have 4281412a1a2SMark Shellenbaum * been removed. 4291412a1a2SMark Shellenbaum */ 4301412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT); 4311412a1a2SMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 4321412a1a2SMark Shellenbaum } 4330a586ceaSMark Shellenbaum } 4340a586ceaSMark Shellenbaum } 4350a586ceaSMark Shellenbaum 436da6c28aaSamw static int 437da6c28aaSamw zfs_acl_version(int version) 438da6c28aaSamw { 439da6c28aaSamw if (version < ZPL_VERSION_FUID) 440da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 441da6c28aaSamw else 442da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 443da6c28aaSamw } 444da6c28aaSamw 445da6c28aaSamw static int 446da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 447da6c28aaSamw { 448da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 449da6c28aaSamw } 450fa9e4066Sahrens 4510a586ceaSMark Shellenbaum zfs_acl_t * 452da6c28aaSamw zfs_acl_alloc(int vers) 453fa9e4066Sahrens { 454fa9e4066Sahrens zfs_acl_t *aclp; 455fa9e4066Sahrens 456fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 457da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 458da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 459da6c28aaSamw aclp->z_version = vers; 460da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 461da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 462da6c28aaSamw else 463da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 464fa9e4066Sahrens return (aclp); 465fa9e4066Sahrens } 466fa9e4066Sahrens 4670a586ceaSMark Shellenbaum zfs_acl_node_t * 468da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 469da6c28aaSamw { 470da6c28aaSamw zfs_acl_node_t *aclnode; 471da6c28aaSamw 472da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 473da6c28aaSamw if (bytes) { 474da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 475da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 476da6c28aaSamw aclnode->z_allocsize = bytes; 477da6c28aaSamw aclnode->z_size = bytes; 478da6c28aaSamw } 479da6c28aaSamw 480da6c28aaSamw return (aclnode); 481da6c28aaSamw } 482da6c28aaSamw 483da6c28aaSamw static void 484da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 485da6c28aaSamw { 486da6c28aaSamw if (aclnode->z_allocsize) 487da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 488da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 489da6c28aaSamw } 490da6c28aaSamw 4912459a9eaSmarks static void 4922459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 493fa9e4066Sahrens { 494da6c28aaSamw zfs_acl_node_t *aclnode; 495da6c28aaSamw 496da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 497da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 498da6c28aaSamw zfs_acl_node_free(aclnode); 499fa9e4066Sahrens } 5002459a9eaSmarks aclp->z_acl_count = 0; 5012459a9eaSmarks aclp->z_acl_bytes = 0; 5022459a9eaSmarks } 503da6c28aaSamw 5042459a9eaSmarks void 5052459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 5062459a9eaSmarks { 5072459a9eaSmarks zfs_acl_release_nodes(aclp); 508da6c28aaSamw list_destroy(&aclp->z_acl); 509fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 510fa9e4066Sahrens } 511fa9e4066Sahrens 512da6c28aaSamw static boolean_t 513003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 514003c2582SMark Shellenbaum { 515003c2582SMark Shellenbaum uint16_t entry_type; 516003c2582SMark Shellenbaum 517003c2582SMark Shellenbaum switch (type) { 518003c2582SMark Shellenbaum case ALLOW: 519003c2582SMark Shellenbaum case DENY: 520003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 521003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 522003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 523003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 524003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 525003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 526003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 527003c2582SMark Shellenbaum default: 528003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 529003c2582SMark Shellenbaum return (B_TRUE); 530003c2582SMark Shellenbaum } 531003c2582SMark Shellenbaum return (B_FALSE); 532003c2582SMark Shellenbaum } 533003c2582SMark Shellenbaum 534003c2582SMark Shellenbaum static boolean_t 535da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 536fa9e4066Sahrens { 537da6c28aaSamw /* 538da6c28aaSamw * first check type of entry 539da6c28aaSamw */ 540da6c28aaSamw 541003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 542da6c28aaSamw return (B_FALSE); 543da6c28aaSamw 544da6c28aaSamw switch (type) { 545da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 546da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 547da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 548da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 549da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 550da6c28aaSamw return (B_FALSE); 551da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 552da6c28aaSamw } 553da6c28aaSamw 554003c2582SMark Shellenbaum /* 555003c2582SMark Shellenbaum * next check inheritance level flags 556003c2582SMark Shellenbaum */ 557003c2582SMark Shellenbaum 558b249c65cSmarks if (obj_type == VDIR && 559b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 560da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 561da6c28aaSamw 562da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 563da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 564da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 565da6c28aaSamw return (B_FALSE); 566da6c28aaSamw } 567da6c28aaSamw } 568da6c28aaSamw 569da6c28aaSamw return (B_TRUE); 570da6c28aaSamw } 571da6c28aaSamw 572da6c28aaSamw static void * 573da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 574da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 575da6c28aaSamw { 576da6c28aaSamw zfs_acl_node_t *aclnode; 577da6c28aaSamw 5780a586ceaSMark Shellenbaum ASSERT(aclp); 5790a586ceaSMark Shellenbaum 580da6c28aaSamw if (start == NULL) { 581da6c28aaSamw aclnode = list_head(&aclp->z_acl); 582da6c28aaSamw if (aclnode == NULL) 583da6c28aaSamw return (NULL); 584da6c28aaSamw 585da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 586da6c28aaSamw aclp->z_curr_node = aclnode; 587da6c28aaSamw aclnode->z_ace_idx = 0; 588da6c28aaSamw } 589da6c28aaSamw 590da6c28aaSamw aclnode = aclp->z_curr_node; 591da6c28aaSamw 592da6c28aaSamw if (aclnode == NULL) 593da6c28aaSamw return (NULL); 594da6c28aaSamw 595da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 596da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 597da6c28aaSamw if (aclnode == NULL) 598da6c28aaSamw return (NULL); 599da6c28aaSamw else { 600da6c28aaSamw aclp->z_curr_node = aclnode; 601da6c28aaSamw aclnode->z_ace_idx = 0; 602da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 603da6c28aaSamw } 604da6c28aaSamw } 605da6c28aaSamw 606da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 607da6c28aaSamw void *acep = aclp->z_next_ace; 608003c2582SMark Shellenbaum size_t ace_size; 609003c2582SMark Shellenbaum 610003c2582SMark Shellenbaum /* 611003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 612003c2582SMark Shellenbaum */ 613003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 614003c2582SMark Shellenbaum 615003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 616003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 617003c2582SMark Shellenbaum return (NULL); 618003c2582SMark Shellenbaum } 619003c2582SMark Shellenbaum 620da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 621da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 622da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 623da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 624003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 625da6c28aaSamw aclnode->z_ace_idx++; 6260a586ceaSMark Shellenbaum 627da6c28aaSamw return ((void *)acep); 628da6c28aaSamw } 629da6c28aaSamw return (NULL); 630da6c28aaSamw } 631da6c28aaSamw 632da6c28aaSamw /*ARGSUSED*/ 633da6c28aaSamw static uint64_t 634da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 635da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 636da6c28aaSamw { 637da6c28aaSamw zfs_acl_t *aclp = datap; 638da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 639da6c28aaSamw uint64_t who; 640da6c28aaSamw 641da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 642da6c28aaSamw flags, type); 643da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 644da6c28aaSamw } 645da6c28aaSamw 646da6c28aaSamw static zfs_acl_node_t * 647da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 648da6c28aaSamw { 649da6c28aaSamw ASSERT(aclp->z_curr_node); 650da6c28aaSamw return (aclp->z_curr_node); 651da6c28aaSamw } 652da6c28aaSamw 653da6c28aaSamw /* 654da6c28aaSamw * Copy ACE to internal ZFS format. 655da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 656da6c28aaSamw * ACE FUIDs will be created later. 657da6c28aaSamw */ 658da6c28aaSamw int 65989459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 6600a586ceaSMark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size, 66189459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 662da6c28aaSamw { 663da6c28aaSamw int i; 664da6c28aaSamw uint16_t entry_type; 665da6c28aaSamw zfs_ace_t *aceptr = z_acl; 666da6c28aaSamw ace_t *acep = datap; 667da6c28aaSamw zfs_object_ace_t *zobjacep; 668da6c28aaSamw ace_object_t *aceobjp; 669da6c28aaSamw 670da6c28aaSamw for (i = 0; i != aclcnt; i++) { 671da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 672da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 673da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 674da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 675da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 6764c841f60Smarks entry_type != ACE_EVERYONE) { 67789459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 67889459e17SMark Shellenbaum cr, (entry_type == 0) ? 67989459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 6804c841f60Smarks } 6814c841f60Smarks 682da6c28aaSamw /* 683da6c28aaSamw * Make sure ACE is valid 684da6c28aaSamw */ 685da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 686da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 687da6c28aaSamw return (EINVAL); 688da6c28aaSamw 689da6c28aaSamw switch (acep->a_type) { 690da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 691da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 692da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 693da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 694da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 695da6c28aaSamw aceobjp = (ace_object_t *)acep; 696da6c28aaSamw 697da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 698da6c28aaSamw sizeof (aceobjp->a_obj_type)); 699da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 700da6c28aaSamw zobjacep->z_inherit_type, 701da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 702da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 703da6c28aaSamw break; 704da6c28aaSamw default: 705da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 706da6c28aaSamw } 707da6c28aaSamw 708da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 709da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 710da6c28aaSamw } 711da6c28aaSamw 712da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 713da6c28aaSamw 714da6c28aaSamw return (0); 715da6c28aaSamw } 716da6c28aaSamw 717da6c28aaSamw /* 718da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 719da6c28aaSamw */ 720da6c28aaSamw static void 721bda89588Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 722bda89588Sjp151216 void *datap, int filter) 723da6c28aaSamw { 724da6c28aaSamw uint64_t who; 725da6c28aaSamw uint32_t access_mask; 726da6c28aaSamw uint16_t iflags, type; 727da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 728da6c28aaSamw ace_t *acep = datap; 729da6c28aaSamw ace_object_t *objacep; 730da6c28aaSamw zfs_object_ace_t *zobjacep; 731da6c28aaSamw size_t ace_size; 732da6c28aaSamw uint16_t entry_type; 733da6c28aaSamw 734da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 735da6c28aaSamw &who, &access_mask, &iflags, &type)) { 736da6c28aaSamw 737da6c28aaSamw switch (type) { 738da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 739da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 740da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 741da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 742da6c28aaSamw if (filter) { 743da6c28aaSamw continue; 744da6c28aaSamw } 745da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 746da6c28aaSamw objacep = (ace_object_t *)acep; 747da6c28aaSamw bcopy(zobjacep->z_object_type, 748da6c28aaSamw objacep->a_obj_type, 749da6c28aaSamw sizeof (zobjacep->z_object_type)); 750da6c28aaSamw bcopy(zobjacep->z_inherit_type, 751da6c28aaSamw objacep->a_inherit_obj_type, 752da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 753da6c28aaSamw ace_size = sizeof (ace_object_t); 754da6c28aaSamw break; 755da6c28aaSamw default: 756da6c28aaSamw ace_size = sizeof (ace_t); 757da6c28aaSamw break; 758da6c28aaSamw } 759da6c28aaSamw 760da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 761da6c28aaSamw if ((entry_type != ACE_OWNER && 7621ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 763e0d35c44Smarks entry_type != ACE_EVERYONE)) { 764e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 765e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 766e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 767e0d35c44Smarks } else { 768da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 769e0d35c44Smarks } 770da6c28aaSamw acep->a_access_mask = access_mask; 771da6c28aaSamw acep->a_flags = iflags; 772da6c28aaSamw acep->a_type = type; 773da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 774da6c28aaSamw } 775da6c28aaSamw } 776da6c28aaSamw 777da6c28aaSamw static int 778da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 779da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 780da6c28aaSamw { 781da6c28aaSamw int i; 782da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 783da6c28aaSamw 784da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 785da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 786da6c28aaSamw aceptr->z_type = acep[i].a_type; 787da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 788da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 789da6c28aaSamw /* 790da6c28aaSamw * Make sure ACE is valid 791da6c28aaSamw */ 792da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 793da6c28aaSamw aceptr->z_flags) != B_TRUE) 794da6c28aaSamw return (EINVAL); 795da6c28aaSamw } 796da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 797da6c28aaSamw return (0); 798da6c28aaSamw } 799da6c28aaSamw 800da6c28aaSamw /* 801da6c28aaSamw * convert old ACL format to new 802da6c28aaSamw */ 803da6c28aaSamw void 80489459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 805da6c28aaSamw { 806da6c28aaSamw zfs_oldace_t *oldaclp; 807da6c28aaSamw int i; 808da6c28aaSamw uint16_t type, iflags; 809da6c28aaSamw uint32_t access_mask; 810da6c28aaSamw uint64_t who; 811da6c28aaSamw void *cookie = NULL; 8122459a9eaSmarks zfs_acl_node_t *newaclnode; 813da6c28aaSamw 814da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 815da6c28aaSamw /* 816da6c28aaSamw * First create the ACE in a contiguous piece of memory 817da6c28aaSamw * for zfs_copy_ace_2_fuid(). 818da6c28aaSamw * 819da6c28aaSamw * We only convert an ACL once, so this won't happen 820da6c28aaSamw * everytime. 821da6c28aaSamw */ 822da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 823da6c28aaSamw KM_SLEEP); 824da6c28aaSamw i = 0; 825da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 826da6c28aaSamw &access_mask, &iflags, &type)) { 827da6c28aaSamw oldaclp[i].z_flags = iflags; 828da6c28aaSamw oldaclp[i].z_type = type; 829da6c28aaSamw oldaclp[i].z_fuid = who; 830da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 831da6c28aaSamw } 832da6c28aaSamw 833da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 834da6c28aaSamw sizeof (zfs_object_ace_t)); 835da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 83689459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 83789459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 83889459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 839da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 840da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 841da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 842da6c28aaSamw 843da6c28aaSamw /* 844da6c28aaSamw * Release all previous ACL nodes 845da6c28aaSamw */ 846da6c28aaSamw 8472459a9eaSmarks zfs_acl_release_nodes(aclp); 8482459a9eaSmarks 849da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 8502459a9eaSmarks 8512459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 8522459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 8532459a9eaSmarks 854fa9e4066Sahrens } 855fa9e4066Sahrens 856fa9e4066Sahrens /* 857fa9e4066Sahrens * Convert unix access mask to v4 access mask 858fa9e4066Sahrens */ 859fa9e4066Sahrens static uint32_t 860fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 861fa9e4066Sahrens { 862fa9e4066Sahrens uint32_t new_mask = 0; 863fa9e4066Sahrens 864da6c28aaSamw if (access_mask & S_IXOTH) 865da6c28aaSamw new_mask |= ACE_EXECUTE; 866da6c28aaSamw if (access_mask & S_IWOTH) 867da6c28aaSamw new_mask |= ACE_WRITE_DATA; 868da6c28aaSamw if (access_mask & S_IROTH) 869fa9e4066Sahrens new_mask |= ACE_READ_DATA; 870fa9e4066Sahrens return (new_mask); 871fa9e4066Sahrens } 872fa9e4066Sahrens 873fa9e4066Sahrens static void 874da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 875da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 876fa9e4066Sahrens { 877da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 878da6c28aaSamw 879da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 880da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 881da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 8821ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 883da6c28aaSamw type != ACE_EVERYONE)) 884da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 885fa9e4066Sahrens } 886fa9e4066Sahrens 887da6c28aaSamw /* 888da6c28aaSamw * Determine mode of file based on ACL. 889da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 890da6c28aaSamw */ 8910a586ceaSMark Shellenbaum uint64_t 89227dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp, 89327dd1e87SMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid) 894fa9e4066Sahrens { 895fa9e4066Sahrens int entry_type; 896da6c28aaSamw mode_t mode; 897fa9e4066Sahrens mode_t seen = 0; 898da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 899da6c28aaSamw uint64_t who; 900da6c28aaSamw uint16_t iflags, type; 901da6c28aaSamw uint32_t access_mask; 902d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 903fa9e4066Sahrens 9040a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 905da6c28aaSamw 906da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 907da6c28aaSamw &access_mask, &iflags, &type)) { 90829a0b737Smarks 909003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 910003c2582SMark Shellenbaum continue; 911003c2582SMark Shellenbaum 912e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 913e6032be1Smarks 9141ab99678SMark Shellenbaum /* 9151ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 9161ab99678SMark Shellenbaum */ 9171ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 9181ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 9191ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 9201ab99678SMark Shellenbaum continue; 9211ab99678SMark Shellenbaum 92227dd1e87SMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 && 92327dd1e87SMark Shellenbaum who == fuid)) { 924da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 925fa9e4066Sahrens (!(seen & S_IRUSR))) { 926fa9e4066Sahrens seen |= S_IRUSR; 927da6c28aaSamw if (type == ALLOW) { 928fa9e4066Sahrens mode |= S_IRUSR; 929fa9e4066Sahrens } 930fa9e4066Sahrens } 931da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 932fa9e4066Sahrens (!(seen & S_IWUSR))) { 933fa9e4066Sahrens seen |= S_IWUSR; 934da6c28aaSamw if (type == ALLOW) { 935fa9e4066Sahrens mode |= S_IWUSR; 936fa9e4066Sahrens } 937fa9e4066Sahrens } 938da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 939fa9e4066Sahrens (!(seen & S_IXUSR))) { 940fa9e4066Sahrens seen |= S_IXUSR; 941da6c28aaSamw if (type == ALLOW) { 942fa9e4066Sahrens mode |= S_IXUSR; 943fa9e4066Sahrens } 944fa9e4066Sahrens } 94527dd1e87SMark Shellenbaum } else if (entry_type == OWNING_GROUP || 94627dd1e87SMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) { 947da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 948fa9e4066Sahrens (!(seen & S_IRGRP))) { 949fa9e4066Sahrens seen |= S_IRGRP; 950da6c28aaSamw if (type == ALLOW) { 951fa9e4066Sahrens mode |= S_IRGRP; 952fa9e4066Sahrens } 953fa9e4066Sahrens } 954da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 955fa9e4066Sahrens (!(seen & S_IWGRP))) { 956fa9e4066Sahrens seen |= S_IWGRP; 957da6c28aaSamw if (type == ALLOW) { 958fa9e4066Sahrens mode |= S_IWGRP; 959fa9e4066Sahrens } 960fa9e4066Sahrens } 961da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 962fa9e4066Sahrens (!(seen & S_IXGRP))) { 963fa9e4066Sahrens seen |= S_IXGRP; 964da6c28aaSamw if (type == ALLOW) { 965fa9e4066Sahrens mode |= S_IXGRP; 966fa9e4066Sahrens } 967fa9e4066Sahrens } 968fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 969da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 970fa9e4066Sahrens if (!(seen & S_IRUSR)) { 971fa9e4066Sahrens seen |= S_IRUSR; 972da6c28aaSamw if (type == ALLOW) { 973fa9e4066Sahrens mode |= S_IRUSR; 974fa9e4066Sahrens } 975fa9e4066Sahrens } 976fa9e4066Sahrens if (!(seen & S_IRGRP)) { 977fa9e4066Sahrens seen |= S_IRGRP; 978da6c28aaSamw if (type == ALLOW) { 979fa9e4066Sahrens mode |= S_IRGRP; 980fa9e4066Sahrens } 981fa9e4066Sahrens } 982fa9e4066Sahrens if (!(seen & S_IROTH)) { 983fa9e4066Sahrens seen |= S_IROTH; 984da6c28aaSamw if (type == ALLOW) { 985fa9e4066Sahrens mode |= S_IROTH; 986fa9e4066Sahrens } 987fa9e4066Sahrens } 988fa9e4066Sahrens } 989da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 990fa9e4066Sahrens if (!(seen & S_IWUSR)) { 991fa9e4066Sahrens seen |= S_IWUSR; 992da6c28aaSamw if (type == ALLOW) { 993fa9e4066Sahrens mode |= S_IWUSR; 994fa9e4066Sahrens } 995fa9e4066Sahrens } 996fa9e4066Sahrens if (!(seen & S_IWGRP)) { 997fa9e4066Sahrens seen |= S_IWGRP; 998da6c28aaSamw if (type == ALLOW) { 999fa9e4066Sahrens mode |= S_IWGRP; 1000fa9e4066Sahrens } 1001fa9e4066Sahrens } 1002fa9e4066Sahrens if (!(seen & S_IWOTH)) { 1003fa9e4066Sahrens seen |= S_IWOTH; 1004da6c28aaSamw if (type == ALLOW) { 1005fa9e4066Sahrens mode |= S_IWOTH; 1006fa9e4066Sahrens } 1007fa9e4066Sahrens } 1008fa9e4066Sahrens } 1009da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 1010fa9e4066Sahrens if (!(seen & S_IXUSR)) { 1011fa9e4066Sahrens seen |= S_IXUSR; 1012da6c28aaSamw if (type == ALLOW) { 1013fa9e4066Sahrens mode |= S_IXUSR; 1014fa9e4066Sahrens } 1015fa9e4066Sahrens } 1016fa9e4066Sahrens if (!(seen & S_IXGRP)) { 1017fa9e4066Sahrens seen |= S_IXGRP; 1018da6c28aaSamw if (type == ALLOW) { 1019fa9e4066Sahrens mode |= S_IXGRP; 1020fa9e4066Sahrens } 1021fa9e4066Sahrens } 1022fa9e4066Sahrens if (!(seen & S_IXOTH)) { 1023fa9e4066Sahrens seen |= S_IXOTH; 1024da6c28aaSamw if (type == ALLOW) { 1025fa9e4066Sahrens mode |= S_IXOTH; 1026fa9e4066Sahrens } 1027fa9e4066Sahrens } 1028fa9e4066Sahrens } 1029d47621a4STim Haley } else { 1030d47621a4STim Haley /* 1031d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 1032d47621a4STim Haley * USER ACE denies execute access to someone, 1033d47621a4STim Haley * mode is not affected 1034d47621a4STim Haley */ 1035d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 1036d47621a4STim Haley an_exec_denied = B_TRUE; 1037fa9e4066Sahrens } 1038fa9e4066Sahrens } 1039d47621a4STim Haley 10404929fd5eSTim Haley /* 10414929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 10424929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 10434929fd5eSTim Haley * weren't allowed it. 10444929fd5eSTim Haley */ 10454929fd5eSTim Haley if (!an_exec_denied && 10464929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 10474929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 1048d47621a4STim Haley an_exec_denied = B_TRUE; 1049d47621a4STim Haley 1050d47621a4STim Haley if (an_exec_denied) 10510a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED; 1052d47621a4STim Haley else 10530a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED; 1054d47621a4STim Haley 1055fa9e4066Sahrens return (mode); 1056fa9e4066Sahrens } 1057fa9e4066Sahrens 1058fa9e4066Sahrens /* 10594929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 10604929fd5eSTim Haley * create a new acl and leave any cached acl in place. 1061fa9e4066Sahrens */ 1062ea8dc4b6Seschrock static int 10631412a1a2SMark Shellenbaum zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp, 10641412a1a2SMark Shellenbaum boolean_t will_modify) 1065fa9e4066Sahrens { 1066fa9e4066Sahrens zfs_acl_t *aclp; 10670a586ceaSMark Shellenbaum int aclsize; 10680a586ceaSMark Shellenbaum int acl_count; 1069da6c28aaSamw zfs_acl_node_t *aclnode; 10700a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl; 10710a586ceaSMark Shellenbaum int version; 1072ea8dc4b6Seschrock int error; 10731412a1a2SMark Shellenbaum boolean_t drop_lock = B_FALSE; 1074fa9e4066Sahrens 1075fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 1076fa9e4066Sahrens 10774929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 1078d47621a4STim Haley *aclpp = zp->z_acl_cached; 1079d47621a4STim Haley return (0); 1080d47621a4STim Haley } 1081d47621a4STim Haley 10821412a1a2SMark Shellenbaum /* 10831412a1a2SMark Shellenbaum * close race where znode could be upgrade while trying to 10841412a1a2SMark Shellenbaum * read the znode attributes. 10851412a1a2SMark Shellenbaum * 10861412a1a2SMark Shellenbaum * But this could only happen if the file isn't already an SA 10871412a1a2SMark Shellenbaum * znode 10881412a1a2SMark Shellenbaum */ 10891412a1a2SMark Shellenbaum if (!zp->z_is_sa && !have_lock) { 10901412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 10911412a1a2SMark Shellenbaum drop_lock = B_TRUE; 10921412a1a2SMark Shellenbaum } 10931412a1a2SMark Shellenbaum version = zfs_znode_acl_version(zp); 1094fa9e4066Sahrens 10950a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize, 10961412a1a2SMark Shellenbaum &acl_count, &znode_acl)) != 0) { 10971412a1a2SMark Shellenbaum goto done; 10981412a1a2SMark Shellenbaum } 1099fa9e4066Sahrens 11000a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version); 11010a586ceaSMark Shellenbaum 1102da6c28aaSamw aclp->z_acl_count = acl_count; 1103da6c28aaSamw aclp->z_acl_bytes = aclsize; 1104da6c28aaSamw 11050a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize); 11060a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count; 11070a586ceaSMark Shellenbaum aclnode->z_size = aclsize; 11080a586ceaSMark Shellenbaum 11090a586ceaSMark Shellenbaum if (!zp->z_is_sa) { 11100a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) { 11110a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os, 11120a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size, 11130a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH); 11140a586ceaSMark Shellenbaum } else { 11150a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata, 11160a586ceaSMark Shellenbaum aclnode->z_size); 11170a586ceaSMark Shellenbaum } 11180a586ceaSMark Shellenbaum } else { 11190a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs), 11200a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size); 11210a586ceaSMark Shellenbaum } 11220a586ceaSMark Shellenbaum 1123ea8dc4b6Seschrock if (error != 0) { 1124ea8dc4b6Seschrock zfs_acl_free(aclp); 11250a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode); 1126b87f3af3Sperrin /* convert checksum errors into IO errors */ 1127b87f3af3Sperrin if (error == ECKSUM) 1128b87f3af3Sperrin error = EIO; 11291412a1a2SMark Shellenbaum goto done; 1130ea8dc4b6Seschrock } 1131fa9e4066Sahrens 11320a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode); 11330a586ceaSMark Shellenbaum 11344929fd5eSTim Haley *aclpp = aclp; 11354929fd5eSTim Haley if (!will_modify) 11364929fd5eSTim Haley zp->z_acl_cached = aclp; 11371412a1a2SMark Shellenbaum done: 11381412a1a2SMark Shellenbaum if (drop_lock) 11391412a1a2SMark Shellenbaum mutex_exit(&zp->z_lock); 11401412a1a2SMark Shellenbaum return (error); 1141fa9e4066Sahrens } 1142fa9e4066Sahrens 11430a586ceaSMark Shellenbaum /*ARGSUSED*/ 11440a586ceaSMark Shellenbaum void 11450a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, 11460a586ceaSMark Shellenbaum boolean_t start, void *userdata) 11470a586ceaSMark Shellenbaum { 11480a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata; 11490a586ceaSMark Shellenbaum 11500a586ceaSMark Shellenbaum if (start) { 11510a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl); 11520a586ceaSMark Shellenbaum } else { 11530a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, 11540a586ceaSMark Shellenbaum cb->cb_acl_node); 11550a586ceaSMark Shellenbaum } 11560a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata; 11570a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size; 11580a586ceaSMark Shellenbaum } 11590a586ceaSMark Shellenbaum 116027dd1e87SMark Shellenbaum int 116127dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp) 116227dd1e87SMark Shellenbaum { 116327dd1e87SMark Shellenbaum int error; 116427dd1e87SMark Shellenbaum zfs_acl_t *aclp; 116527dd1e87SMark Shellenbaum 11661412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_lock)); 11671412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 116827dd1e87SMark Shellenbaum 11691412a1a2SMark Shellenbaum if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0) 117027dd1e87SMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp, 1171f1696b23SMark Shellenbaum &zp->z_pflags, zp->z_uid, zp->z_gid); 117227dd1e87SMark Shellenbaum return (error); 117327dd1e87SMark Shellenbaum } 117427dd1e87SMark Shellenbaum 1175fa9e4066Sahrens /* 1176da6c28aaSamw * common code for setting ACLs. 1177fa9e4066Sahrens * 1178fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1179fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1180fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1181fa9e4066Sahrens */ 1182fa9e4066Sahrens int 118389459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1184fa9e4066Sahrens { 1185fa9e4066Sahrens int error; 1186fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1187da6c28aaSamw dmu_object_type_t otype; 11880a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 }; 11890a586ceaSMark Shellenbaum uint64_t mode; 11900a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5]; 11910a586ceaSMark Shellenbaum uint64_t ctime[2]; 11920a586ceaSMark Shellenbaum int count = 0; 1193fa9e4066Sahrens 11940a586ceaSMark Shellenbaum mode = zp->z_mode; 119527dd1e87SMark Shellenbaum 1196f1696b23SMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, 1197f1696b23SMark Shellenbaum zp->z_uid, zp->z_gid); 11980a586ceaSMark Shellenbaum 11990a586ceaSMark Shellenbaum zp->z_mode = mode; 12000a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, 12010a586ceaSMark Shellenbaum &mode, sizeof (mode)); 12020a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, 12030a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags)); 12040a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, 12050a586ceaSMark Shellenbaum &ctime, sizeof (ctime)); 1206fa9e4066Sahrens 12074929fd5eSTim Haley if (zp->z_acl_cached) { 1208d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1209d47621a4STim Haley zp->z_acl_cached = NULL; 1210d47621a4STim Haley } 1211d47621a4STim Haley 1212fa9e4066Sahrens /* 12130a586ceaSMark Shellenbaum * Upgrade needed? 1214fa9e4066Sahrens */ 1215da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1216da6c28aaSamw otype = DMU_OT_OLDACL; 1217da6c28aaSamw } else { 1218da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1219da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 122089459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1221da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1222da6c28aaSamw otype = DMU_OT_ACL; 1223da6c28aaSamw } 1224da6c28aaSamw 12250a586ceaSMark Shellenbaum /* 12260a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format 12270a586ceaSMark Shellenbaum * as well as newer (preferred) SA format. 12280a586ceaSMark Shellenbaum */ 12290a586ceaSMark Shellenbaum 12300a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */ 12310a586ceaSMark Shellenbaum locate.cb_aclp = aclp; 12320a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs), 12330a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes); 12340a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), 12350a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t)); 12360a586ceaSMark Shellenbaum } else { /* Painful legacy way */ 12370a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode; 12380a586ceaSMark Shellenbaum uint64_t off = 0; 12390a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 12400a586ceaSMark Shellenbaum uint64_t aoid; 12410a586ceaSMark Shellenbaum 12420a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 12430a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0) 12440a586ceaSMark Shellenbaum return (error); 12450a586ceaSMark Shellenbaum 12460a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj; 12470a586ceaSMark Shellenbaum 1248da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1249da6c28aaSamw /* 1250da6c28aaSamw * If ACL was previously external and we are now 1251da6c28aaSamw * converting to new ACL format then release old 1252da6c28aaSamw * ACL object and create a new one. 1253da6c28aaSamw */ 12540a586ceaSMark Shellenbaum if (aoid && 12550a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) { 12560a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx); 1257da6c28aaSamw if (error) 1258da6c28aaSamw return (error); 1259da6c28aaSamw aoid = 0; 1260da6c28aaSamw } 1261fa9e4066Sahrens if (aoid == 0) { 1262fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1263da6c28aaSamw otype, aclp->z_acl_bytes, 12640a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12650a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE, 12660a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12670a586ceaSMark Shellenbaum DN_MAX_BONUSLEN : 0, tx); 1268fa9e4066Sahrens } else { 12690a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os, 12700a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx); 1271fa9e4066Sahrens } 12720a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid; 1273da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1274da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1275da6c28aaSamw if (aclnode->z_ace_count == 0) 1276da6c28aaSamw continue; 1277da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1278da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1279da6c28aaSamw off += aclnode->z_size; 1280da6c28aaSamw } 1281fa9e4066Sahrens } else { 12820a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data; 1283fa9e4066Sahrens /* 1284fa9e4066Sahrens * Migrating back embedded? 1285fa9e4066Sahrens */ 12860a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) { 1287fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 12880a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx); 1289fa9e4066Sahrens if (error) 1290fa9e4066Sahrens return (error); 12910a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0; 1292fa9e4066Sahrens } 1293da6c28aaSamw 1294da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1295da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1296da6c28aaSamw if (aclnode->z_ace_count == 0) 1297da6c28aaSamw continue; 12980a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start, 12990a586ceaSMark Shellenbaum aclnode->z_size); 1300da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1301da6c28aaSamw } 1302fa9e4066Sahrens } 1303da6c28aaSamw /* 1304da6c28aaSamw * If Old version then swap count/bytes to match old 1305da6c28aaSamw * layout of znode_acl_phys_t. 1306da6c28aaSamw */ 1307da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 13080a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count; 13090a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes; 1310da6c28aaSamw } else { 13110a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes; 13120a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count; 1313da6c28aaSamw } 13140a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version; 1315da6c28aaSamw 13160a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL, 13170a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys)); 13180a586ceaSMark Shellenbaum } 1319da6c28aaSamw 1320da6c28aaSamw /* 1321da6c28aaSamw * Replace ACL wide bits, but first clear them. 1322da6c28aaSamw */ 13230a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS; 1324da6c28aaSamw 13250a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints; 1326da6c28aaSamw 1327da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 13280a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL; 1329fa9e4066Sahrens 13300a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE); 13310a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); 1332fa9e4066Sahrens } 1333fa9e4066Sahrens 1334fa9e4066Sahrens static void 1335*a3c49ce1SAlbert Lee zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t trim, zfs_acl_t *aclp) 1336fa9e4066Sahrens { 133727dd1e87SMark Shellenbaum void *acep = NULL; 1338da6c28aaSamw uint64_t who; 133927dd1e87SMark Shellenbaum int new_count, new_bytes; 134027dd1e87SMark Shellenbaum int ace_size; 1341fa9e4066Sahrens int entry_type; 1342da6c28aaSamw uint16_t iflags, type; 1343da6c28aaSamw uint32_t access_mask; 134427dd1e87SMark Shellenbaum zfs_acl_node_t *newnode; 134527dd1e87SMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size(); 134627dd1e87SMark Shellenbaum void *zacep; 1347*a3c49ce1SAlbert Lee boolean_t isdir; 1348*a3c49ce1SAlbert Lee trivial_acl_t masks; 1349fa9e4066Sahrens 135027dd1e87SMark Shellenbaum new_count = new_bytes = 0; 135127dd1e87SMark Shellenbaum 1352*a3c49ce1SAlbert Lee isdir = (vtype == VDIR); 1353*a3c49ce1SAlbert Lee 1354*a3c49ce1SAlbert Lee acl_trivial_access_masks((mode_t)mode, isdir, &masks); 135527dd1e87SMark Shellenbaum 135627dd1e87SMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes); 135727dd1e87SMark Shellenbaum 135827dd1e87SMark Shellenbaum zacep = newnode->z_acldata; 1359*a3c49ce1SAlbert Lee if (masks.allow0) { 1360*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER); 136127dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136227dd1e87SMark Shellenbaum new_count++; 136327dd1e87SMark Shellenbaum new_bytes += abstract_size; 1364*a3c49ce1SAlbert Lee } if (masks.deny1) { 1365*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER); 136627dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136727dd1e87SMark Shellenbaum new_count++; 136827dd1e87SMark Shellenbaum new_bytes += abstract_size; 136927dd1e87SMark Shellenbaum } 1370*a3c49ce1SAlbert Lee if (masks.deny2) { 1371*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP); 137227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 137327dd1e87SMark Shellenbaum new_count++; 137427dd1e87SMark Shellenbaum new_bytes += abstract_size; 137527dd1e87SMark Shellenbaum } 13762459a9eaSmarks 1377da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1378da6c28aaSamw &iflags, &type)) { 137927dd1e87SMark Shellenbaum uint16_t inherit_flags; 1380fa9e4066Sahrens 1381da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 138227dd1e87SMark Shellenbaum inherit_flags = (iflags & ALL_INHERIT); 138327dd1e87SMark Shellenbaum 138427dd1e87SMark Shellenbaum if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 138527dd1e87SMark Shellenbaum (entry_type == OWNING_GROUP)) && 138627dd1e87SMark Shellenbaum ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) { 138727dd1e87SMark Shellenbaum continue; 138827dd1e87SMark Shellenbaum } 1389da6c28aaSamw 1390*a3c49ce1SAlbert Lee /* 1391*a3c49ce1SAlbert Lee * If this ACL has any inheritable ACEs, mark that in 1392*a3c49ce1SAlbert Lee * the hints (which are later masked into the pflags) 1393*a3c49ce1SAlbert Lee * so create knows to do inheritance. 1394*a3c49ce1SAlbert Lee */ 1395*a3c49ce1SAlbert Lee if (isdir && (inherit_flags & 1396*a3c49ce1SAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 1397*a3c49ce1SAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE; 1398*a3c49ce1SAlbert Lee 1399da6c28aaSamw if ((type != ALLOW && type != DENY) || 140027dd1e87SMark Shellenbaum (inherit_flags & ACE_INHERIT_ONLY_ACE)) { 1401da6c28aaSamw switch (type) { 1402da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1403da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1404da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1405da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1406da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1407da6c28aaSamw break; 1408fa9e4066Sahrens } 1409fa9e4066Sahrens } else { 1410fa9e4066Sahrens 1411fa9e4066Sahrens /* 141227dd1e87SMark Shellenbaum * Limit permissions to be no greater than 1413*a3c49ce1SAlbert Lee * group permissions. 1414*a3c49ce1SAlbert Lee * The "aclinherit" and "aclmode" properties 1415*a3c49ce1SAlbert Lee * affect policy for create and chmod(2), 1416*a3c49ce1SAlbert Lee * respectively. 1417fa9e4066Sahrens */ 1418*a3c49ce1SAlbert Lee if ((type == ALLOW) && trim) 1419*a3c49ce1SAlbert Lee access_mask &= masks.group; 1420fa9e4066Sahrens } 142127dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags); 142227dd1e87SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 142327dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size); 142427dd1e87SMark Shellenbaum new_count++; 142527dd1e87SMark Shellenbaum new_bytes += ace_size; 1426fa9e4066Sahrens } 1427*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.owner, 0, -1, ACE_OWNER); 142827dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1429*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.group, 0, -1, OWNING_GROUP); 143027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1431*a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.everyone, 0, -1, ACE_EVERYONE); 1432fa9e4066Sahrens 143327dd1e87SMark Shellenbaum new_count += 3; 143427dd1e87SMark Shellenbaum new_bytes += abstract_size * 3; 143527dd1e87SMark Shellenbaum zfs_acl_release_nodes(aclp); 143627dd1e87SMark Shellenbaum aclp->z_acl_count = new_count; 143727dd1e87SMark Shellenbaum aclp->z_acl_bytes = new_bytes; 143827dd1e87SMark Shellenbaum newnode->z_ace_count = new_count; 143927dd1e87SMark Shellenbaum newnode->z_size = new_bytes; 144027dd1e87SMark Shellenbaum list_insert_tail(&aclp->z_acl, newnode); 1441fa9e4066Sahrens } 1442fa9e4066Sahrens 1443*a3c49ce1SAlbert Lee int 14444c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1445fa9e4066Sahrens { 1446*a3c49ce1SAlbert Lee int error = 0; 1447*a3c49ce1SAlbert Lee 1448fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 14491412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1450*a3c49ce1SAlbert Lee if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 145127dd1e87SMark Shellenbaum *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); 1452*a3c49ce1SAlbert Lee else 1453*a3c49ce1SAlbert Lee error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE); 1454*a3c49ce1SAlbert Lee 1455*a3c49ce1SAlbert Lee if (error == 0) { 14560a586ceaSMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; 1457*a3c49ce1SAlbert Lee zfs_acl_chmod(ZTOV(zp)->v_type, mode, 1458*a3c49ce1SAlbert Lee (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp); 1459*a3c49ce1SAlbert Lee } 14604c841f60Smarks mutex_exit(&zp->z_lock); 14611412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 1462*a3c49ce1SAlbert Lee 1463*a3c49ce1SAlbert Lee return (error); 1464fa9e4066Sahrens } 1465fa9e4066Sahrens 1466fa9e4066Sahrens /* 1467fa9e4066Sahrens * strip off write_owner and write_acl 1468fa9e4066Sahrens */ 1469fa9e4066Sahrens static void 1470b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1471fa9e4066Sahrens { 1472da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1473da6c28aaSamw 1474b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1475da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1476b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1477da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1478da6c28aaSamw } 1479da6c28aaSamw } 1480da6c28aaSamw 1481da6c28aaSamw /* 1482da6c28aaSamw * Should ACE be inherited? 1483da6c28aaSamw */ 1484da6c28aaSamw static int 148589459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1486da6c28aaSamw { 1487da6c28aaSamw int iflags = (acep_flags & 0xf); 1488da6c28aaSamw 1489da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1490da6c28aaSamw return (1); 1491da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1492da6c28aaSamw return (!((vtype == VDIR) && 1493da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1494da6c28aaSamw return (0); 1495fa9e4066Sahrens } 1496fa9e4066Sahrens 1497fa9e4066Sahrens /* 1498fa9e4066Sahrens * inherit inheritable ACEs from parent 1499fa9e4066Sahrens */ 1500fa9e4066Sahrens static zfs_acl_t * 150189459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 150289459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1503fa9e4066Sahrens { 1504da6c28aaSamw void *pacep; 150527dd1e87SMark Shellenbaum void *acep; 150627dd1e87SMark Shellenbaum zfs_acl_node_t *aclnode; 1507fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1508da6c28aaSamw uint64_t who; 1509da6c28aaSamw uint32_t access_mask; 1510da6c28aaSamw uint16_t iflags, newflags, type; 1511da6c28aaSamw size_t ace_size; 1512da6c28aaSamw void *data1, *data2; 1513da6c28aaSamw size_t data1sz, data2sz; 151489459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 151589459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1516d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1517d0f3f37eSMark Shellenbaum 1518d0f3f37eSMark Shellenbaum passthrough_x = 1519d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1520d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1521d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1522d0f3f37eSMark Shellenbaum noallow = 1523d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1524fa9e4066Sahrens 1525b3d141f8Smarks *need_chmod = B_TRUE; 1526da6c28aaSamw pacep = NULL; 1527003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 15280a586ceaSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK) 1529d0f3f37eSMark Shellenbaum return (aclp); 1530da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1531da6c28aaSamw &access_mask, &iflags, &type)) { 1532fa9e4066Sahrens 1533003c2582SMark Shellenbaum /* 1534003c2582SMark Shellenbaum * don't inherit bogus ACEs 1535003c2582SMark Shellenbaum */ 1536003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1537003c2582SMark Shellenbaum continue; 1538003c2582SMark Shellenbaum 1539d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1540fa9e4066Sahrens continue; 1541fa9e4066Sahrens 1542da6c28aaSamw ace_size = aclp->z_ops.ace_size(pacep); 1543fa9e4066Sahrens 154489459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1545b3d141f8Smarks continue; 1546fa9e4066Sahrens 1547b3d141f8Smarks /* 1548b3d141f8Smarks * If owner@, group@, or everyone@ inheritable 1549b3d141f8Smarks * then zfs_acl_chmod() isn't needed. 1550b3d141f8Smarks */ 1551d0f3f37eSMark Shellenbaum if (passthrough && 1552b3d141f8Smarks ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1553b3d141f8Smarks ((iflags & OWNING_GROUP) == 1554d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1555d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1556b3d141f8Smarks *need_chmod = B_FALSE; 1557c694df91SMark Shellenbaum } 1558b3d141f8Smarks 1559d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1560d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1561d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1562d0f3f37eSMark Shellenbaum } 1563d0f3f37eSMark Shellenbaum 1564b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1565da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1566da6c28aaSamw acep = aclnode->z_acldata; 1567d0f3f37eSMark Shellenbaum 1568da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1569da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1570169cdae2Smarks 1571fa9e4066Sahrens /* 1572da6c28aaSamw * Copy special opaque data if any 1573fa9e4066Sahrens */ 1574d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1575b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1576da6c28aaSamw &data2)) == data1sz); 1577da6c28aaSamw bcopy(data1, data2, data2sz); 1578da6c28aaSamw } 157927dd1e87SMark Shellenbaum 1580da6c28aaSamw aclp->z_acl_count++; 1581da6c28aaSamw aclnode->z_ace_count++; 1582da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1583da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1584b3d141f8Smarks 1585d0f3f37eSMark Shellenbaum if (vdir) 1586b3d141f8Smarks aclp->z_hints |= ZFS_INHERIT_ACE; 1587b3d141f8Smarks 1588d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1589da6c28aaSamw newflags &= ~ALL_INHERIT; 1590da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1591da6c28aaSamw newflags|ACE_INHERITED_ACE); 1592b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep); 1593fa9e4066Sahrens continue; 1594fa9e4066Sahrens } 1595fa9e4066Sahrens 1596d0f3f37eSMark Shellenbaum ASSERT(vdir); 1597fa9e4066Sahrens 1598da6c28aaSamw /* 159927dd1e87SMark Shellenbaum * If only FILE_INHERIT is set then turn on 160027dd1e87SMark Shellenbaum * inherit_only 1601da6c28aaSamw */ 160227dd1e87SMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE | 1603485adf61SMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) { 1604da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1605da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1606da6c28aaSamw newflags|ACE_INHERITED_ACE); 1607485adf61SMark Shellenbaum } else { 1608485adf61SMark Shellenbaum newflags &= ~ACE_INHERIT_ONLY_ACE; 1609485adf61SMark Shellenbaum aclp->z_ops.ace_flags_set(acep, 1610485adf61SMark Shellenbaum newflags|ACE_INHERITED_ACE); 1611da6c28aaSamw } 1612da6c28aaSamw } 1613fa9e4066Sahrens return (aclp); 1614fa9e4066Sahrens } 1615fa9e4066Sahrens 1616fa9e4066Sahrens /* 1617fa9e4066Sahrens * Create file system object initial permissions 1618fa9e4066Sahrens * including inheritable ACEs. 1619fa9e4066Sahrens */ 162089459e17SMark Shellenbaum int 162189459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 162289459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1623fa9e4066Sahrens { 1624fa9e4066Sahrens int error; 162589459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1626da6c28aaSamw zfs_acl_t *paclp; 1627e0d35c44Smarks gid_t gid; 1628b3d141f8Smarks boolean_t need_chmod = B_TRUE; 16290a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE; 1630da6c28aaSamw 163189459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 163289459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1633fa9e4066Sahrens 163489459e17SMark Shellenbaum if (vsecp) 163589459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 163689459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 163789459e17SMark Shellenbaum return (error); 1638fa9e4066Sahrens /* 1639fa9e4066Sahrens * Determine uid and gid. 1640fa9e4066Sahrens */ 16414a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1642fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 164389459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 164489459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 164589459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 164689459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 164789459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 164889459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1649e0d35c44Smarks gid = vap->va_gid; 1650fa9e4066Sahrens } else { 165189459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 165289459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 165389459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1654e0d35c44Smarks if (vap->va_mask & AT_GID) { 165589459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 165689459e17SMark Shellenbaum (uint64_t)vap->va_gid, 165789459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1658e0d35c44Smarks gid = vap->va_gid; 1659f1696b23SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_gid && 1660e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1661e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 166289459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1663e0d35c44Smarks } 166489459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 16650a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) { 1666b3874165SJohn Harres char *domain; 1667b3874165SJohn Harres uint32_t rid; 1668b3874165SJohn Harres 1669f1696b23SMark Shellenbaum acl_ids->z_fgid = dzp->z_gid; 167089459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1671e0d35c44Smarks cr, ZFS_GROUP); 1672b3874165SJohn Harres 1673b3874165SJohn Harres if (zfsvfs->z_use_fuids && 1674b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) { 1675b3874165SJohn Harres domain = zfs_fuid_idx_domain( 1676b3874165SJohn Harres &zfsvfs->z_fuid_idx, 1677b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid)); 1678b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid); 1679b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp, 1680b3874165SJohn Harres domain, rid, 1681b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid), 1682b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP); 1683b3874165SJohn Harres } 1684da6c28aaSamw } else { 168589459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 168689459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1687e0d35c44Smarks gid = crgetgid(cr); 1688e0d35c44Smarks } 1689da6c28aaSamw } 1690fa9e4066Sahrens } 1691fa9e4066Sahrens 1692fa9e4066Sahrens /* 1693fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1694fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1695fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1696fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1697fa9e4066Sahrens */ 1698fa9e4066Sahrens 16990a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) && 170089459e17SMark Shellenbaum (vap->va_type == VDIR)) { 170189459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1702e0d35c44Smarks } else { 170389459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1704fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 170589459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1706fa9e4066Sahrens } 1707fa9e4066Sahrens 170889459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 17091412a1a2SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 171089459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 1711*a3c49ce1SAlbert Lee if (!(flag & IS_ROOT_NODE) && 1712*a3c49ce1SAlbert Lee (dzp->z_pflags & ZFS_INHERIT_ACE) && 17130a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) { 17141412a1a2SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE, 17151412a1a2SMark Shellenbaum &paclp, B_FALSE)); 171689459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 171789459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 17180a586ceaSMark Shellenbaum inherited = B_TRUE; 1719fa9e4066Sahrens } else { 172089459e17SMark Shellenbaum acl_ids->z_aclp = 172189459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 17220a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 1723fa9e4066Sahrens } 172489459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 17251412a1a2SMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 172689459e17SMark Shellenbaum if (need_chmod) { 17270a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ? 172889459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 1729*a3c49ce1SAlbert Lee zfs_acl_chmod(vap->va_type, acl_ids->z_mode, 1730*a3c49ce1SAlbert Lee (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED), 1731*a3c49ce1SAlbert Lee acl_ids->z_aclp); 173289459e17SMark Shellenbaum } 1733da6c28aaSamw } 1734da6c28aaSamw 17350a586ceaSMark Shellenbaum if (inherited || vsecp) { 17360a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode, 173727dd1e87SMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints, 173827dd1e87SMark Shellenbaum acl_ids->z_fuid, acl_ids->z_fgid); 17390a586ceaSMark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0) 17400a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 17410a586ceaSMark Shellenbaum } 17420a586ceaSMark Shellenbaum 174389459e17SMark Shellenbaum return (0); 1744fa9e4066Sahrens } 1745fa9e4066Sahrens 1746fa9e4066Sahrens /* 174789459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 174889459e17SMark Shellenbaum */ 174989459e17SMark Shellenbaum void 175089459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 175189459e17SMark Shellenbaum { 175289459e17SMark Shellenbaum if (acl_ids->z_aclp) 175389459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 175489459e17SMark Shellenbaum if (acl_ids->z_fuidp) 175589459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 175689459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 175789459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 175889459e17SMark Shellenbaum } 175989459e17SMark Shellenbaum 176014843421SMatthew Ahrens boolean_t 176114843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 176214843421SMatthew Ahrens { 17630a586ceaSMark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 17640a586ceaSMark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 176514843421SMatthew Ahrens } 176689459e17SMark Shellenbaum 176789459e17SMark Shellenbaum /* 1768fa9e4066Sahrens * Retrieve a files ACL 1769fa9e4066Sahrens */ 1770fa9e4066Sahrens int 1771da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1772fa9e4066Sahrens { 1773fa9e4066Sahrens zfs_acl_t *aclp; 1774da6c28aaSamw ulong_t mask; 1775fa9e4066Sahrens int error; 1776da6c28aaSamw int count = 0; 1777da6c28aaSamw int largeace = 0; 1778fa9e4066Sahrens 1779da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1780da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1781da6c28aaSamw 1782fa9e4066Sahrens if (mask == 0) 1783fa9e4066Sahrens return (ENOSYS); 1784fa9e4066Sahrens 17850a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 17860a586ceaSMark Shellenbaum return (error); 17870a586ceaSMark Shellenbaum 1788fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1789fa9e4066Sahrens 17901412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 1791ea8dc4b6Seschrock if (error != 0) { 1792ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1793ea8dc4b6Seschrock return (error); 1794ea8dc4b6Seschrock } 1795ea8dc4b6Seschrock 1796da6c28aaSamw /* 1797da6c28aaSamw * Scan ACL to determine number of ACEs 1798da6c28aaSamw */ 17990a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) { 1800da6c28aaSamw void *zacep = NULL; 1801da6c28aaSamw uint64_t who; 1802da6c28aaSamw uint32_t access_mask; 1803da6c28aaSamw uint16_t type, iflags; 1804da6c28aaSamw 1805da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1806da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1807da6c28aaSamw switch (type) { 1808da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1809da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1810da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1811da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1812da6c28aaSamw largeace++; 1813da6c28aaSamw continue; 1814da6c28aaSamw default: 1815da6c28aaSamw count++; 1816da6c28aaSamw } 1817da6c28aaSamw } 1818da6c28aaSamw vsecp->vsa_aclcnt = count; 1819da6c28aaSamw } else 18200a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count; 1821fa9e4066Sahrens 1822fa9e4066Sahrens if (mask & VSA_ACECNT) { 1823da6c28aaSamw vsecp->vsa_aclcnt = count; 1824fa9e4066Sahrens } 1825fa9e4066Sahrens 1826fa9e4066Sahrens if (mask & VSA_ACE) { 1827da6c28aaSamw size_t aclsz; 1828da6c28aaSamw 1829da6c28aaSamw aclsz = count * sizeof (ace_t) + 1830da6c28aaSamw sizeof (ace_object_t) * largeace; 1831da6c28aaSamw 1832da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 1833da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 1834da6c28aaSamw 1835da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 1836bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 1837da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 1838da6c28aaSamw else { 18392e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode; 18402e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp; 18412e7d9b42SMark Shellenbaum 18422e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode; 18432e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) { 18442e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start, 18452e7d9b42SMark Shellenbaum aclnode->z_size); 18462e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size; 18472e7d9b42SMark Shellenbaum } 18482e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 18492e7d9b42SMark Shellenbaum aclp->z_acl_bytes); 1850da6c28aaSamw } 1851da6c28aaSamw } 1852da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 1853da6c28aaSamw vsecp->vsa_aclflags = 0; 18540a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED) 1855da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 18560a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED) 1857da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 18580a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT) 1859da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 1860fa9e4066Sahrens } 1861fa9e4066Sahrens 1862fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1863fa9e4066Sahrens 1864fa9e4066Sahrens return (0); 1865fa9e4066Sahrens } 1866fa9e4066Sahrens 1867da6c28aaSamw int 1868da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 186989459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 1870da6c28aaSamw { 1871da6c28aaSamw zfs_acl_t *aclp; 1872da6c28aaSamw zfs_acl_node_t *aclnode; 1873da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 1874da6c28aaSamw int error; 1875da6c28aaSamw 1876da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 1877da6c28aaSamw return (EINVAL); 1878da6c28aaSamw 1879da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 1880da6c28aaSamw 1881da6c28aaSamw aclp->z_hints = 0; 1882da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 1883da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1884da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 1885da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 1886da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 1887da6c28aaSamw zfs_acl_free(aclp); 1888da6c28aaSamw zfs_acl_node_free(aclnode); 1889da6c28aaSamw return (error); 1890da6c28aaSamw } 1891da6c28aaSamw } else { 189289459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 1893da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 189489459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 1895da6c28aaSamw zfs_acl_free(aclp); 1896da6c28aaSamw zfs_acl_node_free(aclnode); 1897da6c28aaSamw return (error); 1898da6c28aaSamw } 1899da6c28aaSamw } 1900da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 1901da6c28aaSamw aclnode->z_ace_count = aclcnt; 1902da6c28aaSamw aclp->z_acl_count = aclcnt; 1903da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1904da6c28aaSamw 1905da6c28aaSamw /* 1906da6c28aaSamw * If flags are being set then add them to z_hints 1907da6c28aaSamw */ 1908da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 1909da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 1910da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 1911da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 1912da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 1913da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 1914da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 1915da6c28aaSamw } 1916da6c28aaSamw 1917da6c28aaSamw *zaclp = aclp; 1918da6c28aaSamw 1919da6c28aaSamw return (0); 1920da6c28aaSamw } 1921da6c28aaSamw 1922fa9e4066Sahrens /* 1923fa9e4066Sahrens * Set a files ACL 1924fa9e4066Sahrens */ 1925fa9e4066Sahrens int 1926da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1927fa9e4066Sahrens { 1928fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1929fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 1930fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 1931fa9e4066Sahrens dmu_tx_t *tx; 1932fa9e4066Sahrens int error; 1933fa9e4066Sahrens zfs_acl_t *aclp; 1934da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 193589459e17SMark Shellenbaum boolean_t fuid_dirtied; 19361412a1a2SMark Shellenbaum uint64_t acl_obj; 1937fa9e4066Sahrens 1938fa9e4066Sahrens if (mask == 0) 19397106075aSmarks return (ENOSYS); 1940fa9e4066Sahrens 19410a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE) 1942da6c28aaSamw return (EPERM); 1943da6c28aaSamw 1944da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 1945fa9e4066Sahrens return (error); 1946da6c28aaSamw 194789459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 194889459e17SMark Shellenbaum &aclp); 1949da6c28aaSamw if (error) 1950da6c28aaSamw return (error); 1951da6c28aaSamw 1952da6c28aaSamw /* 1953da6c28aaSamw * If ACL wide flags aren't being set then preserve any 1954da6c28aaSamw * existing flags. 1955da6c28aaSamw */ 1956da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 19570a586ceaSMark Shellenbaum aclp->z_hints |= 19580a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS); 1959fa9e4066Sahrens } 1960da6c28aaSamw top: 1961fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 19621412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1963fa9e4066Sahrens 1964fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 1965fa9e4066Sahrens 19660a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); 19670a586ceaSMark Shellenbaum 196889459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 196914843421SMatthew Ahrens if (fuid_dirtied) 197014843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 1971fa9e4066Sahrens 19720a586ceaSMark Shellenbaum /* 19730a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't 19740a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds 19750a586ceaSMark Shellenbaum */ 19760a586ceaSMark Shellenbaum 19771412a1a2SMark Shellenbaum if ((acl_obj = zfs_external_acl(zp)) != 0) { 19782bd6c4deSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_FUID && 19791412a1a2SMark Shellenbaum zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) { 19801412a1a2SMark Shellenbaum dmu_tx_hold_free(tx, acl_obj, 0, 19810a586ceaSMark Shellenbaum DMU_OBJECT_END); 19822bd6c4deSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 19832bd6c4deSMark Shellenbaum aclp->z_acl_bytes); 19840a586ceaSMark Shellenbaum } else { 19851412a1a2SMark Shellenbaum dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes); 19860a586ceaSMark Shellenbaum } 19870a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { 19880a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 19890a586ceaSMark Shellenbaum } 19900a586ceaSMark Shellenbaum 19910a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp); 19921209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 1993fa9e4066Sahrens if (error) { 1994fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1995fa9e4066Sahrens mutex_exit(&zp->z_lock); 1996fa9e4066Sahrens 19971209a471SNeil Perrin if (error == ERESTART) { 19988a2f1b91Sahrens dmu_tx_wait(tx); 19998a2f1b91Sahrens dmu_tx_abort(tx); 2000fa9e4066Sahrens goto top; 2001fa9e4066Sahrens } 20028a2f1b91Sahrens dmu_tx_abort(tx); 2003da6c28aaSamw zfs_acl_free(aclp); 2004fa9e4066Sahrens return (error); 2005fa9e4066Sahrens } 2006fa9e4066Sahrens 200789459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2008fa9e4066Sahrens ASSERT(error == 0); 20090b2a8171SMark Shellenbaum ASSERT(zp->z_acl_cached == NULL); 20104929fd5eSTim Haley zp->z_acl_cached = aclp; 2011fa9e4066Sahrens 201289459e17SMark Shellenbaum if (fuid_dirtied) 201389459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 201489459e17SMark Shellenbaum 2015da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2016da6c28aaSamw 2017da6c28aaSamw if (fuidp) 2018da6c28aaSamw zfs_fuid_info_free(fuidp); 2019fa9e4066Sahrens dmu_tx_commit(tx); 2020fa9e4066Sahrens done: 2021fa9e4066Sahrens mutex_exit(&zp->z_lock); 20221412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 2023fa9e4066Sahrens 2024fa9e4066Sahrens return (error); 2025fa9e4066Sahrens } 2026fa9e4066Sahrens 2027fa9e4066Sahrens /* 2028e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2029e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2030e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2031fa9e4066Sahrens */ 2032fa9e4066Sahrens static int 2033e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2034fa9e4066Sahrens { 2035fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2036fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2037f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2038f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2039fa9e4066Sahrens return (EROFS); 2040fa9e4066Sahrens } 2041fa9e4066Sahrens 2042da6c28aaSamw /* 2043da6c28aaSamw * Only check for READONLY on non-directories. 2044da6c28aaSamw */ 2045da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2046da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 20470a586ceaSMark Shellenbaum (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2048da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 20490a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_IMMUTABLE)))) { 2050da6c28aaSamw return (EPERM); 2051da6c28aaSamw } 2052da6c28aaSamw 2053da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 20540a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) { 2055da6c28aaSamw return (EPERM); 2056da6c28aaSamw } 2057da6c28aaSamw 2058da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 20590a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) { 2060da6c28aaSamw return (EACCES); 2061da6c28aaSamw } 2062da6c28aaSamw 2063da6c28aaSamw return (0); 2064da6c28aaSamw } 2065da6c28aaSamw 2066e802abbdSTim Haley /* 2067e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2068e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2069e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2070e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2071e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2072e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2073e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2074e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2075e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2076e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2077e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2078e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2079e802abbdSTim Haley * accesses. Returns: 2080e802abbdSTim Haley * 0 if all AoI granted 2081e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2082e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2083e802abbdSTim Haley * 2084e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2085e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2086e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2087e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2088e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2089e802abbdSTim Haley * is used in this manner. 2090e802abbdSTim Haley */ 2091e802abbdSTim Haley static int 2092e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2093e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2094e802abbdSTim Haley { 2095e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2096e802abbdSTim Haley zfs_acl_t *aclp; 2097e802abbdSTim Haley int error; 2098e802abbdSTim Haley uid_t uid = crgetuid(cr); 2099e802abbdSTim Haley uint64_t who; 2100e802abbdSTim Haley uint16_t type, iflags; 2101e802abbdSTim Haley uint16_t entry_type; 2102e802abbdSTim Haley uint32_t access_mask; 2103e802abbdSTim Haley uint32_t deny_mask = 0; 2104e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2105e802abbdSTim Haley boolean_t checkit; 2106f1696b23SMark Shellenbaum uid_t gowner; 2107f1696b23SMark Shellenbaum uid_t fowner; 2108f1696b23SMark Shellenbaum 2109f1696b23SMark Shellenbaum zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 2110da6c28aaSamw 2111fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2112fa9e4066Sahrens 21131412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 2114ea8dc4b6Seschrock if (error != 0) { 2115ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2116ea8dc4b6Seschrock return (error); 2117ea8dc4b6Seschrock } 2118ea8dc4b6Seschrock 21190a586ceaSMark Shellenbaum ASSERT(zp->z_acl_cached); 21200a586ceaSMark Shellenbaum 2121da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2122da6c28aaSamw &iflags, &type)) { 2123e802abbdSTim Haley uint32_t mask_matched; 2124fa9e4066Sahrens 2125003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2126003c2582SMark Shellenbaum continue; 2127003c2582SMark Shellenbaum 2128b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2129fa9e4066Sahrens continue; 2130fa9e4066Sahrens 2131e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2132e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2133e802abbdSTim Haley if (!mask_matched) 2134e802abbdSTim Haley continue; 2135e802abbdSTim Haley 2136da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2137da6c28aaSamw 2138da6c28aaSamw checkit = B_FALSE; 2139da6c28aaSamw 2140fa9e4066Sahrens switch (entry_type) { 2141fa9e4066Sahrens case ACE_OWNER: 2142f1696b23SMark Shellenbaum if (uid == fowner) 2143da6c28aaSamw checkit = B_TRUE; 2144fa9e4066Sahrens break; 2145da6c28aaSamw case OWNING_GROUP: 2146da6c28aaSamw who = gowner; 2147da6c28aaSamw /*FALLTHROUGH*/ 2148fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2149da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2150fa9e4066Sahrens break; 2151fa9e4066Sahrens case ACE_EVERYONE: 2152da6c28aaSamw checkit = B_TRUE; 2153fa9e4066Sahrens break; 2154fa9e4066Sahrens 2155fa9e4066Sahrens /* USER Entry */ 2156fa9e4066Sahrens default: 2157fa9e4066Sahrens if (entry_type == 0) { 2158da6c28aaSamw uid_t newid; 2159da6c28aaSamw 2160e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2161e0d35c44Smarks ZFS_ACE_USER); 2162da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2163da6c28aaSamw uid == newid) 2164da6c28aaSamw checkit = B_TRUE; 2165fa9e4066Sahrens break; 2166da6c28aaSamw } else { 2167fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2168fa9e4066Sahrens return (EIO); 2169fa9e4066Sahrens } 2170da6c28aaSamw } 2171da6c28aaSamw 2172da6c28aaSamw if (checkit) { 2173e802abbdSTim Haley if (type == DENY) { 2174e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2175e802abbdSTim Haley znode_t *, zp, 2176e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2177e802abbdSTim Haley uint32_t, mask_matched); 217890fafcf0Smarks deny_mask |= mask_matched; 2179e802abbdSTim Haley } else { 2180e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2181e802abbdSTim Haley znode_t *, zp, 2182e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2183e802abbdSTim Haley uint32_t, mask_matched); 2184e802abbdSTim Haley if (anyaccess) { 2185e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2186e802abbdSTim Haley return (0); 2187da6c28aaSamw } 2188da6c28aaSamw } 2189e802abbdSTim Haley *working_mode &= ~mask_matched; 2190e802abbdSTim Haley } 2191fa9e4066Sahrens 219290fafcf0Smarks /* Are we done? */ 219390fafcf0Smarks if (*working_mode == 0) 2194fa9e4066Sahrens break; 2195fa9e4066Sahrens } 2196fa9e4066Sahrens 2197fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 219890fafcf0Smarks 219990fafcf0Smarks /* Put the found 'denies' back on the working mode */ 22007ed7e920Smarks if (deny_mask) { 220190fafcf0Smarks *working_mode |= deny_mask; 220290fafcf0Smarks return (EACCES); 22037ed7e920Smarks } else if (*working_mode) { 22047ed7e920Smarks return (-1); 22057ed7e920Smarks } 220690fafcf0Smarks 220790fafcf0Smarks return (0); 2208fa9e4066Sahrens } 2209fa9e4066Sahrens 2210e802abbdSTim Haley /* 2211e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2212e802abbdSTim Haley * care what access is granted. 2213e802abbdSTim Haley */ 2214e802abbdSTim Haley boolean_t 2215e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2216e802abbdSTim Haley { 2217e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2218e802abbdSTim Haley 2219e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2220f1696b23SMark Shellenbaum uid_t owner; 2221f1696b23SMark Shellenbaum 2222f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2223f1696b23SMark Shellenbaum return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0); 2224e802abbdSTim Haley } 2225e802abbdSTim Haley return (B_TRUE); 2226e802abbdSTim Haley } 2227e802abbdSTim Haley 2228e802abbdSTim Haley static int 2229e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2230e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2231e802abbdSTim Haley { 2232e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2233e802abbdSTim Haley int err; 2234e802abbdSTim Haley 2235e802abbdSTim Haley *working_mode = v4_mode; 2236e802abbdSTim Haley *check_privs = B_TRUE; 2237e802abbdSTim Haley 2238e802abbdSTim Haley /* 2239e802abbdSTim Haley * Short circuit empty requests 2240e802abbdSTim Haley */ 2241e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2242e802abbdSTim Haley *working_mode = 0; 2243e802abbdSTim Haley return (0); 2244e802abbdSTim Haley } 2245e802abbdSTim Haley 2246e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2247e802abbdSTim Haley *check_privs = B_FALSE; 2248e802abbdSTim Haley return (err); 2249e802abbdSTim Haley } 2250e802abbdSTim Haley 2251e802abbdSTim Haley /* 2252e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2253e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2254e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2255e802abbdSTim Haley */ 2256e802abbdSTim Haley if (skipaclchk) { 2257e802abbdSTim Haley *working_mode = 0; 2258e802abbdSTim Haley return (0); 2259e802abbdSTim Haley } 2260e802abbdSTim Haley 2261e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2262e802abbdSTim Haley } 2263e802abbdSTim Haley 2264da6c28aaSamw static int 2265da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2266da6c28aaSamw cred_t *cr) 2267da6c28aaSamw { 2268da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2269da6c28aaSamw return (EACCES); 2270da6c28aaSamw 2271da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2272da6c28aaSamw check_privs, B_FALSE, cr)); 2273da6c28aaSamw } 2274fa9e4066Sahrens 2275d47621a4STim Haley int 2276d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2277d47621a4STim Haley { 2278d47621a4STim Haley boolean_t owner = B_FALSE; 2279d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2280d47621a4STim Haley boolean_t is_attr; 2281d47621a4STim Haley uid_t uid = crgetuid(cr); 2282d47621a4STim Haley int error; 2283d47621a4STim Haley 22840a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED) 2285d47621a4STim Haley return (EACCES); 2286d47621a4STim Haley 22870a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) && 2288d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2289d47621a4STim Haley if (is_attr) 2290d47621a4STim Haley goto slow; 2291d47621a4STim Haley 22920a586ceaSMark Shellenbaum 2293d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2294d47621a4STim Haley 22950a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) { 2296d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2297d47621a4STim Haley return (0); 2298d47621a4STim Haley } 2299d47621a4STim Haley 2300f1696b23SMark Shellenbaum if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) { 2301d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2302d47621a4STim Haley goto slow; 2303d47621a4STim Haley } 2304d47621a4STim Haley 23050a586ceaSMark Shellenbaum if (uid == zdp->z_uid) { 2306d47621a4STim Haley owner = B_TRUE; 23070a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) { 2308d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2309d47621a4STim Haley return (0); 2310e4f96946STim Haley } else { 2311e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2312e4f96946STim Haley goto slow; 2313d47621a4STim Haley } 2314d47621a4STim Haley } 23150a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) { 2316d47621a4STim Haley groupmbr = B_TRUE; 23170a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) { 2318d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2319d47621a4STim Haley return (0); 2320e4f96946STim Haley } else { 2321e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2322e4f96946STim Haley goto slow; 2323d47621a4STim Haley } 2324d47621a4STim Haley } 2325d47621a4STim Haley if (!owner && !groupmbr) { 23260a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) { 2327d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2328d47621a4STim Haley return (0); 2329d47621a4STim Haley } 2330d47621a4STim Haley } 2331d47621a4STim Haley 2332d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2333d47621a4STim Haley 2334d47621a4STim Haley slow: 2335d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2336d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2337d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2338d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2339d47621a4STim Haley return (error); 2340d47621a4STim Haley } 2341d47621a4STim Haley 2342fa9e4066Sahrens /* 2343134a1f4eSCasper H.S. Dik * Determine whether Access should be granted/denied. 2344134a1f4eSCasper H.S. Dik * The least priv subsytem is always consulted as a basic privilege 2345134a1f4eSCasper H.S. Dik * can define any form of access. 2346fa9e4066Sahrens */ 2347fa9e4066Sahrens int 2348da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2349fa9e4066Sahrens { 2350da6c28aaSamw uint32_t working_mode; 2351fa9e4066Sahrens int error; 2352fa9e4066Sahrens int is_attr; 2353da6c28aaSamw boolean_t check_privs; 2354fa9e4066Sahrens znode_t *xzp; 2355fa9e4066Sahrens znode_t *check_zp = zp; 2356134a1f4eSCasper H.S. Dik mode_t needed_bits; 2357f1696b23SMark Shellenbaum uid_t owner; 2358fa9e4066Sahrens 23590a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); 2360fa9e4066Sahrens 2361fa9e4066Sahrens /* 2362fa9e4066Sahrens * If attribute then validate against base file 2363fa9e4066Sahrens */ 2364fa9e4066Sahrens if (is_attr) { 23650a586ceaSMark Shellenbaum uint64_t parent; 23660a586ceaSMark Shellenbaum 23670a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 23680a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent, 23690a586ceaSMark Shellenbaum sizeof (parent))) != 0) 23700a586ceaSMark Shellenbaum return (error); 23710a586ceaSMark Shellenbaum 2372fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 23730a586ceaSMark Shellenbaum parent, &xzp)) != 0) { 2374fa9e4066Sahrens return (error); 2375fa9e4066Sahrens } 2376da6c28aaSamw 2377fa9e4066Sahrens check_zp = xzp; 2378da6c28aaSamw 2379fa9e4066Sahrens /* 2380fa9e4066Sahrens * fixup mode to map to xattr perms 2381fa9e4066Sahrens */ 2382fa9e4066Sahrens 2383fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2384fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2385fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2386fa9e4066Sahrens } 2387fa9e4066Sahrens 2388fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2389fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2390fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2391fa9e4066Sahrens } 2392fa9e4066Sahrens } 2393fa9e4066Sahrens 2394f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2395134a1f4eSCasper H.S. Dik /* 2396134a1f4eSCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC 2397134a1f4eSCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently 2398134a1f4eSCasper H.S. Dik * missing) in missing_bits. 2399134a1f4eSCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode), 2400134a1f4eSCasper H.S. Dik * needed_bits. 2401134a1f4eSCasper H.S. Dik */ 2402134a1f4eSCasper H.S. Dik needed_bits = 0; 2403134a1f4eSCasper H.S. Dik 2404134a1f4eSCasper H.S. Dik working_mode = mode; 2405134a1f4eSCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && 2406f1696b23SMark Shellenbaum owner == crgetuid(cr)) 2407134a1f4eSCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2408134a1f4eSCasper H.S. Dik 2409134a1f4eSCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 2410134a1f4eSCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2411134a1f4eSCasper H.S. Dik needed_bits |= VREAD; 2412134a1f4eSCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 2413134a1f4eSCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2414134a1f4eSCasper H.S. Dik needed_bits |= VWRITE; 2415134a1f4eSCasper H.S. Dik if (working_mode & ACE_EXECUTE) 2416134a1f4eSCasper H.S. Dik needed_bits |= VEXEC; 2417134a1f4eSCasper H.S. Dik 2418da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2419da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2420da6c28aaSamw if (is_attr) 2421da6c28aaSamw VN_RELE(ZTOV(xzp)); 2422f1696b23SMark Shellenbaum return (secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2423134a1f4eSCasper H.S. Dik needed_bits, needed_bits)); 2424da6c28aaSamw } 2425fa9e4066Sahrens 2426e0d35c44Smarks if (error && !check_privs) { 2427fa9e4066Sahrens if (is_attr) 2428fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2429fa9e4066Sahrens return (error); 2430fa9e4066Sahrens } 2431fa9e4066Sahrens 2432da6c28aaSamw if (error && (flags & V_APPEND)) { 2433da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2434fa9e4066Sahrens } 2435fa9e4066Sahrens 2436da6c28aaSamw if (error && check_privs) { 2437da6c28aaSamw mode_t checkmode = 0; 2438fa9e4066Sahrens 2439fa9e4066Sahrens /* 2440da6c28aaSamw * First check for implicit owner permission on 2441da6c28aaSamw * read_acl/read_attributes 2442fa9e4066Sahrens */ 2443fa9e4066Sahrens 2444da6c28aaSamw error = 0; 2445da6c28aaSamw ASSERT(working_mode != 0); 2446da6c28aaSamw 2447da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2448f1696b23SMark Shellenbaum owner == crgetuid(cr))) 2449da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2450da6c28aaSamw 2451da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 245247def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2453da6c28aaSamw checkmode |= VREAD; 2454da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 245547def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2456da6c28aaSamw checkmode |= VWRITE; 2457da6c28aaSamw if (working_mode & ACE_EXECUTE) 2458da6c28aaSamw checkmode |= VEXEC; 2459da6c28aaSamw 2460f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner, 2461134a1f4eSCasper H.S. Dik needed_bits & ~checkmode, needed_bits); 2462da6c28aaSamw 2463da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2464f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 2465da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2466f1696b23SMark Shellenbaum error = secpolicy_vnode_setdac(cr, owner); 2467da6c28aaSamw 2468da6c28aaSamw if (error == 0 && (working_mode & 2469da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2470da6c28aaSamw error = secpolicy_vnode_remove(cr); 2471da6c28aaSamw 247247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2473f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 247447def0dcSMark Shellenbaum } 2475da6c28aaSamw if (error == 0) { 2476da6c28aaSamw /* 2477da6c28aaSamw * See if any bits other than those already checked 2478da6c28aaSamw * for are still present. If so then return EACCES 2479da6c28aaSamw */ 2480da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2481da6c28aaSamw error = EACCES; 2482da6c28aaSamw } 2483da6c28aaSamw } 2484134a1f4eSCasper H.S. Dik } else if (error == 0) { 2485f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2486134a1f4eSCasper H.S. Dik needed_bits, needed_bits); 2487da6c28aaSamw } 2488da6c28aaSamw 2489134a1f4eSCasper H.S. Dik 2490da6c28aaSamw if (is_attr) 2491da6c28aaSamw VN_RELE(ZTOV(xzp)); 2492da6c28aaSamw 2493da6c28aaSamw return (error); 2494fa9e4066Sahrens } 2495fa9e4066Sahrens 2496fa9e4066Sahrens /* 2497da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2498fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2499fa9e4066Sahrens */ 2500fa9e4066Sahrens int 2501da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2502da6c28aaSamw { 2503da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2504da6c28aaSamw } 2505da6c28aaSamw 2506da6c28aaSamw /* 2507da6c28aaSamw * Access function for secpolicy_vnode_setattr 2508da6c28aaSamw */ 2509da6c28aaSamw int 2510da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2511fa9e4066Sahrens { 2512fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2513fa9e4066Sahrens 2514da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2515fa9e4066Sahrens } 2516fa9e4066Sahrens 251747db7e74Smarks static int 251823d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 2519134a1f4eSCasper H.S. Dik mode_t available_perms, cred_t *cr) 252047db7e74Smarks { 252147db7e74Smarks int error; 2522f1696b23SMark Shellenbaum uid_t downer; 2523f1696b23SMark Shellenbaum 2524f1696b23SMark Shellenbaum downer = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, ZFS_OWNER); 252547db7e74Smarks 2526134a1f4eSCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(dzp), 2527f1696b23SMark Shellenbaum downer, available_perms, VWRITE|VEXEC); 252847db7e74Smarks 252947db7e74Smarks if (error == 0) 253047db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 253147db7e74Smarks 253247db7e74Smarks return (error); 253347db7e74Smarks } 253447db7e74Smarks 2535fa9e4066Sahrens /* 2536fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2537fa9e4066Sahrens * consulting least priv subsystem. 2538fa9e4066Sahrens * 2539fa9e4066Sahrens * 2540fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2541fa9e4066Sahrens * ability to delete an object. 2542fa9e4066Sahrens * 2543fa9e4066Sahrens * ------------------------------------------------------- 2544fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2545fa9e4066Sahrens * | permissions | | 2546fa9e4066Sahrens * ------------------------------------------------------- 2547fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2548fa9e4066Sahrens * | | Delete | Delete | unspecified| 2549fa9e4066Sahrens * ------------------------------------------------------- 2550fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2551fa9e4066Sahrens * | DELETE_CHILD | | 2552fa9e4066Sahrens * ------------------------------------------------------- 2553fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2554fa9e4066Sahrens * | DELETE_CHILD | | | | 2555fa9e4066Sahrens * ------------------------------------------------------- 2556fa9e4066Sahrens * | ACL specifies | | | | 2557fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2558fa9e4066Sahrens * | write and | | | | 2559fa9e4066Sahrens * | execute | | | | 2560fa9e4066Sahrens * ------------------------------------------------------- 2561fa9e4066Sahrens * | ACL denies | | | | 2562fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2563fa9e4066Sahrens * | execute | | | | 2564fa9e4066Sahrens * ------------------------------------------------------- 2565fa9e4066Sahrens * ^ 2566fa9e4066Sahrens * | 2567fa9e4066Sahrens * No search privilege, can't even look up file? 2568fa9e4066Sahrens * 2569fa9e4066Sahrens */ 2570fa9e4066Sahrens int 2571fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2572fa9e4066Sahrens { 2573da6c28aaSamw uint32_t dzp_working_mode = 0; 2574da6c28aaSamw uint32_t zp_working_mode = 0; 2575fa9e4066Sahrens int dzp_error, zp_error; 2576134a1f4eSCasper H.S. Dik mode_t available_perms; 2577da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2578da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2579fa9e4066Sahrens 2580fa9e4066Sahrens /* 258123d5bb1fSmarks * We want specific DELETE permissions to 2582fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2583fa9e4066Sahrens * want an ACL such as this to mess us up. 258447db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2585fa9e4066Sahrens * 2586fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2587fa9e4066Sahrens * by secpolicy_vnode_access(). 258823d5bb1fSmarks * 258923d5bb1fSmarks * We will ask for all of the necessary permissions and then 259023d5bb1fSmarks * look at the working modes from the directory and target object 259123d5bb1fSmarks * to determine what was found. 2592fa9e4066Sahrens */ 2593fa9e4066Sahrens 25940a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2595da6c28aaSamw return (EPERM); 2596fa9e4066Sahrens 259723d5bb1fSmarks /* 25987ed7e920Smarks * First row 259923d5bb1fSmarks * If the directory permissions allow the delete, we are done. 260023d5bb1fSmarks */ 26017ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 260223d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 260323d5bb1fSmarks return (0); 2604da6c28aaSamw 260523d5bb1fSmarks /* 260623d5bb1fSmarks * If target object has delete permission then we are done 260723d5bb1fSmarks */ 260823d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 260923d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 261023d5bb1fSmarks return (0); 261123d5bb1fSmarks 26127ed7e920Smarks ASSERT(dzp_error && zp_error); 26137ed7e920Smarks 261423d5bb1fSmarks if (!dzpcheck_privs) 2615fa9e4066Sahrens return (dzp_error); 26167ed7e920Smarks if (!zpcheck_privs) 261723d5bb1fSmarks return (zp_error); 2618fa9e4066Sahrens 2619fa9e4066Sahrens /* 2620fa9e4066Sahrens * Second row 26217ed7e920Smarks * 26227ed7e920Smarks * If directory returns EACCES then delete_child was denied 26237ed7e920Smarks * due to deny delete_child. In this case send the request through 26247ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 26257ed7e920Smarks * since that *could* allow the delete based on write/execute permission 26267ed7e920Smarks * and we want delete permissions to override write/execute. 2627fa9e4066Sahrens */ 2628fa9e4066Sahrens 262947db7e74Smarks if (dzp_error == EACCES) 26307ed7e920Smarks return (secpolicy_vnode_remove(cr)); 263147db7e74Smarks 263247db7e74Smarks /* 2633fa9e4066Sahrens * Third Row 263423d5bb1fSmarks * only need to see if we have write/execute on directory. 2635fa9e4066Sahrens */ 2636fa9e4066Sahrens 2637134a1f4eSCasper H.S. Dik dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 2638134a1f4eSCasper H.S. Dik &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); 2639fa9e4066Sahrens 2640134a1f4eSCasper H.S. Dik if (dzp_error != 0 && !dzpcheck_privs) 26417ed7e920Smarks return (dzp_error); 26427ed7e920Smarks 2643fa9e4066Sahrens /* 26447ed7e920Smarks * Fourth row 2645fa9e4066Sahrens */ 2646fa9e4066Sahrens 2647134a1f4eSCasper H.S. Dik available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE; 2648134a1f4eSCasper H.S. Dik available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC; 26497ed7e920Smarks 2650134a1f4eSCasper H.S. Dik return (zfs_delete_final_check(zp, dzp, available_perms, cr)); 26517ed7e920Smarks 2652fa9e4066Sahrens } 2653fa9e4066Sahrens 2654fa9e4066Sahrens int 2655fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2656fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2657fa9e4066Sahrens { 2658fa9e4066Sahrens int add_perm; 2659fa9e4066Sahrens int error; 2660fa9e4066Sahrens 26610a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED) 2662da6c28aaSamw return (EACCES); 2663da6c28aaSamw 2664fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2665fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2666fa9e4066Sahrens 2667fa9e4066Sahrens /* 2668fa9e4066Sahrens * Rename permissions are combination of delete permission + 2669fa9e4066Sahrens * add file/subdir permission. 2670fa9e4066Sahrens */ 2671fa9e4066Sahrens 2672fa9e4066Sahrens /* 2673fa9e4066Sahrens * first make sure we do the delete portion. 2674fa9e4066Sahrens * 2675fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2676fa9e4066Sahrens */ 2677fa9e4066Sahrens 2678fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2679fa9e4066Sahrens return (error); 2680fa9e4066Sahrens 2681fa9e4066Sahrens /* 2682fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2683fa9e4066Sahrens */ 2684fa9e4066Sahrens if (tzp) { 2685fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2686fa9e4066Sahrens return (error); 2687fa9e4066Sahrens } 2688fa9e4066Sahrens 2689fa9e4066Sahrens /* 2690fa9e4066Sahrens * Now check for add permissions 2691fa9e4066Sahrens */ 2692da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2693fa9e4066Sahrens 2694fa9e4066Sahrens return (error); 2695fa9e4066Sahrens } 2696