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. 23a3c49ce1SAlbert Lee * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #include <sys/types.h> 28fa9e4066Sahrens #include <sys/param.h> 29fa9e4066Sahrens #include <sys/time.h> 30fa9e4066Sahrens #include <sys/systm.h> 31fa9e4066Sahrens #include <sys/sysmacros.h> 32fa9e4066Sahrens #include <sys/resource.h> 33fa9e4066Sahrens #include <sys/vfs.h> 34fa9e4066Sahrens #include <sys/vnode.h> 35da6c28aaSamw #include <sys/sid.h> 36fa9e4066Sahrens #include <sys/file.h> 37fa9e4066Sahrens #include <sys/stat.h> 38fa9e4066Sahrens #include <sys/kmem.h> 39fa9e4066Sahrens #include <sys/cmn_err.h> 40fa9e4066Sahrens #include <sys/errno.h> 41fa9e4066Sahrens #include <sys/unistd.h> 42169cdae2Smarks #include <sys/sdt.h> 43fa9e4066Sahrens #include <sys/fs/zfs.h> 44fa9e4066Sahrens #include <sys/mode.h> 45fa9e4066Sahrens #include <sys/policy.h> 46fa9e4066Sahrens #include <sys/zfs_znode.h> 47da6c28aaSamw #include <sys/zfs_fuid.h> 48fa9e4066Sahrens #include <sys/zfs_acl.h> 49fa9e4066Sahrens #include <sys/zfs_dir.h> 50fa9e4066Sahrens #include <sys/zfs_vfsops.h> 51fa9e4066Sahrens #include <sys/dmu.h> 52da6c28aaSamw #include <sys/dnode.h> 53fa9e4066Sahrens #include <sys/zap.h> 540a586ceaSMark Shellenbaum #include <sys/sa.h> 55fa9e4066Sahrens #include "fs/fs_subr.h" 56fa9e4066Sahrens #include <acl/acl_common.h> 57fa9e4066Sahrens 58fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 59fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 60da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 61003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW 62fa9e4066Sahrens 63fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 64fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 65fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 66fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 67fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 68fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 69fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 70da6c28aaSamw 71da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 72da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 73da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 74da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 75da6c28aaSamw 76f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS) 77f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \ 78f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD) 79f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS) 80fa9e4066Sahrens 81fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 82fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 83fa9e4066Sahrens 84fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 85fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 86fa9e4066Sahrens 87fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \ 88da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE) 89fa9e4066Sahrens 90b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER) 91fa9e4066Sahrens 92da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\ 93da6c28aaSamw ZFS_ACL_PROTECTED) 94fa9e4066Sahrens 95da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 96da6c28aaSamw ZFS_ACL_OBJ_ACE) 97da6c28aaSamw 984929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) 994929fd5eSTim Haley 100da6c28aaSamw static uint16_t 101da6c28aaSamw zfs_ace_v0_get_type(void *acep) 102da6c28aaSamw { 103da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type); 104da6c28aaSamw } 105da6c28aaSamw 106da6c28aaSamw static uint16_t 107da6c28aaSamw zfs_ace_v0_get_flags(void *acep) 108da6c28aaSamw { 109da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags); 110da6c28aaSamw } 111da6c28aaSamw 112da6c28aaSamw static uint32_t 113da6c28aaSamw zfs_ace_v0_get_mask(void *acep) 114da6c28aaSamw { 115da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask); 116da6c28aaSamw } 117da6c28aaSamw 118da6c28aaSamw static uint64_t 119da6c28aaSamw zfs_ace_v0_get_who(void *acep) 120da6c28aaSamw { 121da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid); 122da6c28aaSamw } 123da6c28aaSamw 124da6c28aaSamw static void 125da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type) 126da6c28aaSamw { 127da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type; 128da6c28aaSamw } 129da6c28aaSamw 130da6c28aaSamw static void 131da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags) 132da6c28aaSamw { 133da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags; 134da6c28aaSamw } 135da6c28aaSamw 136da6c28aaSamw static void 137da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask) 138da6c28aaSamw { 139da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask; 140da6c28aaSamw } 141da6c28aaSamw 142da6c28aaSamw static void 143da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who) 144da6c28aaSamw { 145da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who; 146da6c28aaSamw } 147da6c28aaSamw 148da6c28aaSamw /*ARGSUSED*/ 149da6c28aaSamw static size_t 150da6c28aaSamw zfs_ace_v0_size(void *acep) 151da6c28aaSamw { 152da6c28aaSamw return (sizeof (zfs_oldace_t)); 153da6c28aaSamw } 154da6c28aaSamw 155da6c28aaSamw static size_t 156da6c28aaSamw zfs_ace_v0_abstract_size(void) 157da6c28aaSamw { 158da6c28aaSamw return (sizeof (zfs_oldace_t)); 159da6c28aaSamw } 160da6c28aaSamw 161da6c28aaSamw static int 162da6c28aaSamw zfs_ace_v0_mask_off(void) 163da6c28aaSamw { 164da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask)); 165da6c28aaSamw } 166da6c28aaSamw 167da6c28aaSamw /*ARGSUSED*/ 168da6c28aaSamw static int 169da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap) 170da6c28aaSamw { 171da6c28aaSamw *datap = NULL; 172da6c28aaSamw return (0); 173da6c28aaSamw } 174da6c28aaSamw 175da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = { 176da6c28aaSamw zfs_ace_v0_get_mask, 177da6c28aaSamw zfs_ace_v0_set_mask, 178da6c28aaSamw zfs_ace_v0_get_flags, 179da6c28aaSamw zfs_ace_v0_set_flags, 180da6c28aaSamw zfs_ace_v0_get_type, 181da6c28aaSamw zfs_ace_v0_set_type, 182da6c28aaSamw zfs_ace_v0_get_who, 183da6c28aaSamw zfs_ace_v0_set_who, 184da6c28aaSamw zfs_ace_v0_size, 185da6c28aaSamw zfs_ace_v0_abstract_size, 186da6c28aaSamw zfs_ace_v0_mask_off, 187da6c28aaSamw zfs_ace_v0_data 188da6c28aaSamw }; 189da6c28aaSamw 190da6c28aaSamw static uint16_t 191da6c28aaSamw zfs_ace_fuid_get_type(void *acep) 192da6c28aaSamw { 193da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type); 194da6c28aaSamw } 195da6c28aaSamw 196da6c28aaSamw static uint16_t 197da6c28aaSamw zfs_ace_fuid_get_flags(void *acep) 198da6c28aaSamw { 199da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags); 200da6c28aaSamw } 201da6c28aaSamw 202da6c28aaSamw static uint32_t 203da6c28aaSamw zfs_ace_fuid_get_mask(void *acep) 204da6c28aaSamw { 205da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask); 206da6c28aaSamw } 207da6c28aaSamw 208da6c28aaSamw static uint64_t 209da6c28aaSamw zfs_ace_fuid_get_who(void *args) 210da6c28aaSamw { 211da6c28aaSamw uint16_t entry_type; 212da6c28aaSamw zfs_ace_t *acep = args; 213da6c28aaSamw 214da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 215da6c28aaSamw 216da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 217da6c28aaSamw entry_type == ACE_EVERYONE) 218da6c28aaSamw return (-1); 219da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid); 220da6c28aaSamw } 221da6c28aaSamw 222da6c28aaSamw static void 223da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type) 224da6c28aaSamw { 225da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type; 226da6c28aaSamw } 227da6c28aaSamw 228da6c28aaSamw static void 229da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags) 230da6c28aaSamw { 231da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags; 232da6c28aaSamw } 233da6c28aaSamw 234da6c28aaSamw static void 235da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask) 236da6c28aaSamw { 237da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask; 238da6c28aaSamw } 239da6c28aaSamw 240da6c28aaSamw static void 241da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who) 242da6c28aaSamw { 243da6c28aaSamw zfs_ace_t *acep = arg; 244da6c28aaSamw 245da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 246da6c28aaSamw 247da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 248da6c28aaSamw entry_type == ACE_EVERYONE) 249da6c28aaSamw return; 250da6c28aaSamw acep->z_fuid = who; 251da6c28aaSamw } 252da6c28aaSamw 253da6c28aaSamw static size_t 254da6c28aaSamw zfs_ace_fuid_size(void *acep) 255da6c28aaSamw { 256da6c28aaSamw zfs_ace_hdr_t *zacep = acep; 257da6c28aaSamw uint16_t entry_type; 258da6c28aaSamw 259da6c28aaSamw switch (zacep->z_type) { 260da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 261da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 262da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 263da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 264da6c28aaSamw return (sizeof (zfs_object_ace_t)); 265da6c28aaSamw case ALLOW: 266da6c28aaSamw case DENY: 267da6c28aaSamw entry_type = 268da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS); 269da6c28aaSamw if (entry_type == ACE_OWNER || 2701ab99678SMark Shellenbaum entry_type == OWNING_GROUP || 271da6c28aaSamw entry_type == ACE_EVERYONE) 272da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 273da6c28aaSamw /*FALLTHROUGH*/ 274da6c28aaSamw default: 275da6c28aaSamw return (sizeof (zfs_ace_t)); 276da6c28aaSamw } 277da6c28aaSamw } 278da6c28aaSamw 279da6c28aaSamw static size_t 280da6c28aaSamw zfs_ace_fuid_abstract_size(void) 281da6c28aaSamw { 282da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 283da6c28aaSamw } 284da6c28aaSamw 285da6c28aaSamw static int 286da6c28aaSamw zfs_ace_fuid_mask_off(void) 287da6c28aaSamw { 288da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 289da6c28aaSamw } 290da6c28aaSamw 291da6c28aaSamw static int 292da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap) 293da6c28aaSamw { 294da6c28aaSamw zfs_ace_t *zacep = acep; 295da6c28aaSamw zfs_object_ace_t *zobjp; 296da6c28aaSamw 297da6c28aaSamw switch (zacep->z_hdr.z_type) { 298da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 299da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 300da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 301da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 302da6c28aaSamw zobjp = acep; 303da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t); 304da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t)); 305da6c28aaSamw default: 306da6c28aaSamw *datap = NULL; 307da6c28aaSamw return (0); 308da6c28aaSamw } 309da6c28aaSamw } 310da6c28aaSamw 311da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = { 312da6c28aaSamw zfs_ace_fuid_get_mask, 313da6c28aaSamw zfs_ace_fuid_set_mask, 314da6c28aaSamw zfs_ace_fuid_get_flags, 315da6c28aaSamw zfs_ace_fuid_set_flags, 316da6c28aaSamw zfs_ace_fuid_get_type, 317da6c28aaSamw zfs_ace_fuid_set_type, 318da6c28aaSamw zfs_ace_fuid_get_who, 319da6c28aaSamw zfs_ace_fuid_set_who, 320da6c28aaSamw zfs_ace_fuid_size, 321da6c28aaSamw zfs_ace_fuid_abstract_size, 322da6c28aaSamw zfs_ace_fuid_mask_off, 323da6c28aaSamw zfs_ace_fuid_data 324da6c28aaSamw }; 325da6c28aaSamw 3260a586ceaSMark Shellenbaum /* 3270a586ceaSMark Shellenbaum * The following three functions are provided for compatibility with 3280a586ceaSMark Shellenbaum * older ZPL version in order to determine if the file use to have 3290a586ceaSMark Shellenbaum * an external ACL and what version of ACL previously existed on the 3300a586ceaSMark Shellenbaum * file. Would really be nice to not need this, sigh. 3310a586ceaSMark Shellenbaum */ 3320a586ceaSMark Shellenbaum uint64_t 3330a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp) 3340a586ceaSMark Shellenbaum { 3350a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 3361412a1a2SMark Shellenbaum int error; 3370a586ceaSMark Shellenbaum 3380a586ceaSMark Shellenbaum if (zp->z_is_sa) 3390a586ceaSMark Shellenbaum return (0); 3400a586ceaSMark Shellenbaum 3411412a1a2SMark Shellenbaum /* 3421412a1a2SMark Shellenbaum * Need to deal with a potential 3431412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause 3441412a1a2SMark Shellenbaum * z_isa_sa to change. 3451412a1a2SMark Shellenbaum * 3461412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have 3471412a1a2SMark Shellenbaum * changed. 3481412a1a2SMark Shellenbaum */ 3490a586ceaSMark Shellenbaum 3501412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 3511412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0) 3520a586ceaSMark Shellenbaum return (acl_phys.z_acl_extern_obj); 3531412a1a2SMark Shellenbaum else { 3541412a1a2SMark Shellenbaum /* 3551412a1a2SMark Shellenbaum * after upgrade the SA_ZPL_ZNODE_ACL should have been 3561412a1a2SMark Shellenbaum * removed 3571412a1a2SMark Shellenbaum */ 3581412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT); 3591412a1a2SMark Shellenbaum return (0); 3601412a1a2SMark Shellenbaum } 3610a586ceaSMark Shellenbaum } 3620a586ceaSMark Shellenbaum 3630a586ceaSMark Shellenbaum /* 3640a586ceaSMark Shellenbaum * Determine size of ACL in bytes 3650a586ceaSMark Shellenbaum * 3660a586ceaSMark Shellenbaum * This is more complicated than it should be since we have to deal 3670a586ceaSMark Shellenbaum * with old external ACLs. 3680a586ceaSMark Shellenbaum */ 3690a586ceaSMark Shellenbaum static int 3700a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount, 3710a586ceaSMark Shellenbaum zfs_acl_phys_t *aclphys) 3720a586ceaSMark Shellenbaum { 3730a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs; 3740a586ceaSMark Shellenbaum uint64_t acl_count; 3750a586ceaSMark Shellenbaum int size; 3760a586ceaSMark Shellenbaum int error; 3770a586ceaSMark Shellenbaum 3781412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 3790a586ceaSMark Shellenbaum if (zp->z_is_sa) { 3800a586ceaSMark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs), 3810a586ceaSMark Shellenbaum &size)) != 0) 3820a586ceaSMark Shellenbaum return (error); 3830a586ceaSMark Shellenbaum *aclsize = size; 3840a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs), 3850a586ceaSMark Shellenbaum &acl_count, sizeof (acl_count))) != 0) 3860a586ceaSMark Shellenbaum return (error); 3870a586ceaSMark Shellenbaum *aclcount = acl_count; 3880a586ceaSMark Shellenbaum } else { 3890a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 3900a586ceaSMark Shellenbaum aclphys, sizeof (*aclphys))) != 0) 3910a586ceaSMark Shellenbaum return (error); 3920a586ceaSMark Shellenbaum 3930a586ceaSMark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) { 3940a586ceaSMark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size); 3950a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_size; 3960a586ceaSMark Shellenbaum } else { 3970a586ceaSMark Shellenbaum *aclsize = aclphys->z_acl_size; 3980a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_count; 3990a586ceaSMark Shellenbaum } 4000a586ceaSMark Shellenbaum } 4010a586ceaSMark Shellenbaum return (0); 4020a586ceaSMark Shellenbaum } 4030a586ceaSMark Shellenbaum 4040a586ceaSMark Shellenbaum int 4050a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp) 4060a586ceaSMark Shellenbaum { 4070a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 4080a586ceaSMark Shellenbaum 4091412a1a2SMark Shellenbaum if (zp->z_is_sa) 4100a586ceaSMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 4111412a1a2SMark Shellenbaum else { 4121412a1a2SMark Shellenbaum int error; 4131412a1a2SMark Shellenbaum 4141412a1a2SMark Shellenbaum /* 4151412a1a2SMark Shellenbaum * Need to deal with a potential 4161412a1a2SMark Shellenbaum * race where zfs_sa_upgrade could cause 4171412a1a2SMark Shellenbaum * z_isa_sa to change. 4181412a1a2SMark Shellenbaum * 4191412a1a2SMark Shellenbaum * If the lookup fails then the state of z_is_sa should have 4201412a1a2SMark Shellenbaum * changed. 4211412a1a2SMark Shellenbaum */ 4221412a1a2SMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 4230a586ceaSMark Shellenbaum SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 4241412a1a2SMark Shellenbaum &acl_phys, sizeof (acl_phys))) == 0) 4250a586ceaSMark Shellenbaum return (acl_phys.z_acl_version); 4261412a1a2SMark Shellenbaum else { 4271412a1a2SMark Shellenbaum /* 4281412a1a2SMark Shellenbaum * After upgrade SA_ZPL_ZNODE_ACL should have 4291412a1a2SMark Shellenbaum * been removed. 4301412a1a2SMark Shellenbaum */ 4311412a1a2SMark Shellenbaum VERIFY(zp->z_is_sa && error == ENOENT); 4321412a1a2SMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 4331412a1a2SMark Shellenbaum } 4340a586ceaSMark Shellenbaum } 4350a586ceaSMark Shellenbaum } 4360a586ceaSMark Shellenbaum 437da6c28aaSamw static int 438da6c28aaSamw zfs_acl_version(int version) 439da6c28aaSamw { 440da6c28aaSamw if (version < ZPL_VERSION_FUID) 441da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 442da6c28aaSamw else 443da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 444da6c28aaSamw } 445da6c28aaSamw 446da6c28aaSamw static int 447da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 448da6c28aaSamw { 449da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 450da6c28aaSamw } 451fa9e4066Sahrens 4520a586ceaSMark Shellenbaum zfs_acl_t * 453da6c28aaSamw zfs_acl_alloc(int vers) 454fa9e4066Sahrens { 455fa9e4066Sahrens zfs_acl_t *aclp; 456fa9e4066Sahrens 457fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 458da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 459da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 460da6c28aaSamw aclp->z_version = vers; 461da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 462da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 463da6c28aaSamw else 464da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 465fa9e4066Sahrens return (aclp); 466fa9e4066Sahrens } 467fa9e4066Sahrens 4680a586ceaSMark Shellenbaum zfs_acl_node_t * 469da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 470da6c28aaSamw { 471da6c28aaSamw zfs_acl_node_t *aclnode; 472da6c28aaSamw 473da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 474da6c28aaSamw if (bytes) { 475da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 476da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 477da6c28aaSamw aclnode->z_allocsize = bytes; 478da6c28aaSamw aclnode->z_size = bytes; 479da6c28aaSamw } 480da6c28aaSamw 481da6c28aaSamw return (aclnode); 482da6c28aaSamw } 483da6c28aaSamw 484da6c28aaSamw static void 485da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 486da6c28aaSamw { 487da6c28aaSamw if (aclnode->z_allocsize) 488da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 489da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 490da6c28aaSamw } 491da6c28aaSamw 4922459a9eaSmarks static void 4932459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 494fa9e4066Sahrens { 495da6c28aaSamw zfs_acl_node_t *aclnode; 496da6c28aaSamw 497da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 498da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 499da6c28aaSamw zfs_acl_node_free(aclnode); 500fa9e4066Sahrens } 5012459a9eaSmarks aclp->z_acl_count = 0; 5022459a9eaSmarks aclp->z_acl_bytes = 0; 5032459a9eaSmarks } 504da6c28aaSamw 5052459a9eaSmarks void 5062459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 5072459a9eaSmarks { 5082459a9eaSmarks zfs_acl_release_nodes(aclp); 509da6c28aaSamw list_destroy(&aclp->z_acl); 510fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 511fa9e4066Sahrens } 512fa9e4066Sahrens 513da6c28aaSamw static boolean_t 514003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 515003c2582SMark Shellenbaum { 516003c2582SMark Shellenbaum uint16_t entry_type; 517003c2582SMark Shellenbaum 518003c2582SMark Shellenbaum switch (type) { 519003c2582SMark Shellenbaum case ALLOW: 520003c2582SMark Shellenbaum case DENY: 521003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 522003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 523003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 524003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 525003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 526003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 527003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 528003c2582SMark Shellenbaum default: 529003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 530003c2582SMark Shellenbaum return (B_TRUE); 531003c2582SMark Shellenbaum } 532003c2582SMark Shellenbaum return (B_FALSE); 533003c2582SMark Shellenbaum } 534003c2582SMark Shellenbaum 535003c2582SMark Shellenbaum static boolean_t 536da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 537fa9e4066Sahrens { 538da6c28aaSamw /* 539da6c28aaSamw * first check type of entry 540da6c28aaSamw */ 541da6c28aaSamw 542003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 543da6c28aaSamw return (B_FALSE); 544da6c28aaSamw 545da6c28aaSamw switch (type) { 546da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 547da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 548da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 549da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 550da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 551da6c28aaSamw return (B_FALSE); 552da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 553da6c28aaSamw } 554da6c28aaSamw 555003c2582SMark Shellenbaum /* 556003c2582SMark Shellenbaum * next check inheritance level flags 557003c2582SMark Shellenbaum */ 558003c2582SMark Shellenbaum 559b249c65cSmarks if (obj_type == VDIR && 560b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 561da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 562da6c28aaSamw 563da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 564da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 565da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 566da6c28aaSamw return (B_FALSE); 567da6c28aaSamw } 568da6c28aaSamw } 569da6c28aaSamw 570da6c28aaSamw return (B_TRUE); 571da6c28aaSamw } 572da6c28aaSamw 573da6c28aaSamw static void * 574da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 575da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 576da6c28aaSamw { 577da6c28aaSamw zfs_acl_node_t *aclnode; 578da6c28aaSamw 5790a586ceaSMark Shellenbaum ASSERT(aclp); 5800a586ceaSMark Shellenbaum 581da6c28aaSamw if (start == NULL) { 582da6c28aaSamw aclnode = list_head(&aclp->z_acl); 583da6c28aaSamw if (aclnode == NULL) 584da6c28aaSamw return (NULL); 585da6c28aaSamw 586da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 587da6c28aaSamw aclp->z_curr_node = aclnode; 588da6c28aaSamw aclnode->z_ace_idx = 0; 589da6c28aaSamw } 590da6c28aaSamw 591da6c28aaSamw aclnode = aclp->z_curr_node; 592da6c28aaSamw 593da6c28aaSamw if (aclnode == NULL) 594da6c28aaSamw return (NULL); 595da6c28aaSamw 596da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 597da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 598da6c28aaSamw if (aclnode == NULL) 599da6c28aaSamw return (NULL); 600da6c28aaSamw else { 601da6c28aaSamw aclp->z_curr_node = aclnode; 602da6c28aaSamw aclnode->z_ace_idx = 0; 603da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 604da6c28aaSamw } 605da6c28aaSamw } 606da6c28aaSamw 607da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 608da6c28aaSamw void *acep = aclp->z_next_ace; 609003c2582SMark Shellenbaum size_t ace_size; 610003c2582SMark Shellenbaum 611003c2582SMark Shellenbaum /* 612003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 613003c2582SMark Shellenbaum */ 614003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 615003c2582SMark Shellenbaum 616003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 617003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 618003c2582SMark Shellenbaum return (NULL); 619003c2582SMark Shellenbaum } 620003c2582SMark Shellenbaum 621da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 622da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 623da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 624da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 625003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 626da6c28aaSamw aclnode->z_ace_idx++; 6270a586ceaSMark Shellenbaum 628da6c28aaSamw return ((void *)acep); 629da6c28aaSamw } 630da6c28aaSamw return (NULL); 631da6c28aaSamw } 632da6c28aaSamw 633da6c28aaSamw /*ARGSUSED*/ 634da6c28aaSamw static uint64_t 635da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 636da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 637da6c28aaSamw { 638da6c28aaSamw zfs_acl_t *aclp = datap; 639da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 640da6c28aaSamw uint64_t who; 641da6c28aaSamw 642da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 643da6c28aaSamw flags, type); 644da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 645da6c28aaSamw } 646da6c28aaSamw 647da6c28aaSamw static zfs_acl_node_t * 648da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 649da6c28aaSamw { 650da6c28aaSamw ASSERT(aclp->z_curr_node); 651da6c28aaSamw return (aclp->z_curr_node); 652da6c28aaSamw } 653da6c28aaSamw 654da6c28aaSamw /* 655da6c28aaSamw * Copy ACE to internal ZFS format. 656da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 657da6c28aaSamw * ACE FUIDs will be created later. 658da6c28aaSamw */ 659da6c28aaSamw int 66089459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 6610a586ceaSMark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size, 66289459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 663da6c28aaSamw { 664da6c28aaSamw int i; 665da6c28aaSamw uint16_t entry_type; 666da6c28aaSamw zfs_ace_t *aceptr = z_acl; 667da6c28aaSamw ace_t *acep = datap; 668da6c28aaSamw zfs_object_ace_t *zobjacep; 669da6c28aaSamw ace_object_t *aceobjp; 670da6c28aaSamw 671da6c28aaSamw for (i = 0; i != aclcnt; i++) { 672da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 673da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 674da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 675da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 676da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 6774c841f60Smarks entry_type != ACE_EVERYONE) { 67889459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 67989459e17SMark Shellenbaum cr, (entry_type == 0) ? 68089459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 6814c841f60Smarks } 6824c841f60Smarks 683da6c28aaSamw /* 684da6c28aaSamw * Make sure ACE is valid 685da6c28aaSamw */ 686da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 687da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 688be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 689da6c28aaSamw 690da6c28aaSamw switch (acep->a_type) { 691da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 692da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 693da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 694da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 695da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 696da6c28aaSamw aceobjp = (ace_object_t *)acep; 697da6c28aaSamw 698da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 699da6c28aaSamw sizeof (aceobjp->a_obj_type)); 700da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 701da6c28aaSamw zobjacep->z_inherit_type, 702da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 703da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 704da6c28aaSamw break; 705da6c28aaSamw default: 706da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 707da6c28aaSamw } 708da6c28aaSamw 709da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 710da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 711da6c28aaSamw } 712da6c28aaSamw 713da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 714da6c28aaSamw 715da6c28aaSamw return (0); 716da6c28aaSamw } 717da6c28aaSamw 718da6c28aaSamw /* 719da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 720da6c28aaSamw */ 721da6c28aaSamw static void 722bda89588Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 723bda89588Sjp151216 void *datap, int filter) 724da6c28aaSamw { 725da6c28aaSamw uint64_t who; 726da6c28aaSamw uint32_t access_mask; 727da6c28aaSamw uint16_t iflags, type; 728da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 729da6c28aaSamw ace_t *acep = datap; 730da6c28aaSamw ace_object_t *objacep; 731da6c28aaSamw zfs_object_ace_t *zobjacep; 732da6c28aaSamw size_t ace_size; 733da6c28aaSamw uint16_t entry_type; 734da6c28aaSamw 735da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 736da6c28aaSamw &who, &access_mask, &iflags, &type)) { 737da6c28aaSamw 738da6c28aaSamw switch (type) { 739da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 740da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 741da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 742da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 743da6c28aaSamw if (filter) { 744da6c28aaSamw continue; 745da6c28aaSamw } 746da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 747da6c28aaSamw objacep = (ace_object_t *)acep; 748da6c28aaSamw bcopy(zobjacep->z_object_type, 749da6c28aaSamw objacep->a_obj_type, 750da6c28aaSamw sizeof (zobjacep->z_object_type)); 751da6c28aaSamw bcopy(zobjacep->z_inherit_type, 752da6c28aaSamw objacep->a_inherit_obj_type, 753da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 754da6c28aaSamw ace_size = sizeof (ace_object_t); 755da6c28aaSamw break; 756da6c28aaSamw default: 757da6c28aaSamw ace_size = sizeof (ace_t); 758da6c28aaSamw break; 759da6c28aaSamw } 760da6c28aaSamw 761da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 762da6c28aaSamw if ((entry_type != ACE_OWNER && 7631ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 764e0d35c44Smarks entry_type != ACE_EVERYONE)) { 765e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 766e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 767e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 768e0d35c44Smarks } else { 769da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 770e0d35c44Smarks } 771da6c28aaSamw acep->a_access_mask = access_mask; 772da6c28aaSamw acep->a_flags = iflags; 773da6c28aaSamw acep->a_type = type; 774da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 775da6c28aaSamw } 776da6c28aaSamw } 777da6c28aaSamw 778da6c28aaSamw static int 779da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 780da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 781da6c28aaSamw { 782da6c28aaSamw int i; 783da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 784da6c28aaSamw 785da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 786da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 787da6c28aaSamw aceptr->z_type = acep[i].a_type; 788da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 789da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 790da6c28aaSamw /* 791da6c28aaSamw * Make sure ACE is valid 792da6c28aaSamw */ 793da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 794da6c28aaSamw aceptr->z_flags) != B_TRUE) 795be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 796da6c28aaSamw } 797da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 798da6c28aaSamw return (0); 799da6c28aaSamw } 800da6c28aaSamw 801da6c28aaSamw /* 802da6c28aaSamw * convert old ACL format to new 803da6c28aaSamw */ 804da6c28aaSamw void 80589459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 806da6c28aaSamw { 807da6c28aaSamw zfs_oldace_t *oldaclp; 808da6c28aaSamw int i; 809da6c28aaSamw uint16_t type, iflags; 810da6c28aaSamw uint32_t access_mask; 811da6c28aaSamw uint64_t who; 812da6c28aaSamw void *cookie = NULL; 8132459a9eaSmarks zfs_acl_node_t *newaclnode; 814da6c28aaSamw 815da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 816da6c28aaSamw /* 817da6c28aaSamw * First create the ACE in a contiguous piece of memory 818da6c28aaSamw * for zfs_copy_ace_2_fuid(). 819da6c28aaSamw * 820da6c28aaSamw * We only convert an ACL once, so this won't happen 821da6c28aaSamw * everytime. 822da6c28aaSamw */ 823da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 824da6c28aaSamw KM_SLEEP); 825da6c28aaSamw i = 0; 826da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 827da6c28aaSamw &access_mask, &iflags, &type)) { 828da6c28aaSamw oldaclp[i].z_flags = iflags; 829da6c28aaSamw oldaclp[i].z_type = type; 830da6c28aaSamw oldaclp[i].z_fuid = who; 831da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 832da6c28aaSamw } 833da6c28aaSamw 834da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 835da6c28aaSamw sizeof (zfs_object_ace_t)); 836da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 83789459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 83889459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 83989459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 840da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 841da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 842da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 843da6c28aaSamw 844da6c28aaSamw /* 845da6c28aaSamw * Release all previous ACL nodes 846da6c28aaSamw */ 847da6c28aaSamw 8482459a9eaSmarks zfs_acl_release_nodes(aclp); 8492459a9eaSmarks 850da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 8512459a9eaSmarks 8522459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 8532459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 8542459a9eaSmarks 855fa9e4066Sahrens } 856fa9e4066Sahrens 857fa9e4066Sahrens /* 858fa9e4066Sahrens * Convert unix access mask to v4 access mask 859fa9e4066Sahrens */ 860fa9e4066Sahrens static uint32_t 861fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 862fa9e4066Sahrens { 863fa9e4066Sahrens uint32_t new_mask = 0; 864fa9e4066Sahrens 865da6c28aaSamw if (access_mask & S_IXOTH) 866da6c28aaSamw new_mask |= ACE_EXECUTE; 867da6c28aaSamw if (access_mask & S_IWOTH) 868da6c28aaSamw new_mask |= ACE_WRITE_DATA; 869da6c28aaSamw if (access_mask & S_IROTH) 870fa9e4066Sahrens new_mask |= ACE_READ_DATA; 871fa9e4066Sahrens return (new_mask); 872fa9e4066Sahrens } 873fa9e4066Sahrens 874fa9e4066Sahrens static void 875da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 876da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 877fa9e4066Sahrens { 878da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 879da6c28aaSamw 880da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 881da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 882da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 8831ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 884da6c28aaSamw type != ACE_EVERYONE)) 885da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 886fa9e4066Sahrens } 887fa9e4066Sahrens 888da6c28aaSamw /* 889da6c28aaSamw * Determine mode of file based on ACL. 890da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 891da6c28aaSamw */ 8920a586ceaSMark Shellenbaum uint64_t 89327dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp, 89427dd1e87SMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid) 895fa9e4066Sahrens { 896fa9e4066Sahrens int entry_type; 897da6c28aaSamw mode_t mode; 898fa9e4066Sahrens mode_t seen = 0; 899da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 900da6c28aaSamw uint64_t who; 901da6c28aaSamw uint16_t iflags, type; 902da6c28aaSamw uint32_t access_mask; 903d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 904fa9e4066Sahrens 9050a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 906da6c28aaSamw 907da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 908da6c28aaSamw &access_mask, &iflags, &type)) { 90929a0b737Smarks 910003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 911003c2582SMark Shellenbaum continue; 912003c2582SMark Shellenbaum 913e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 914e6032be1Smarks 9151ab99678SMark Shellenbaum /* 9161ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 9171ab99678SMark Shellenbaum */ 9181ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 9191ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 9201ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 9211ab99678SMark Shellenbaum continue; 9221ab99678SMark Shellenbaum 92327dd1e87SMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 && 92427dd1e87SMark Shellenbaum who == fuid)) { 925da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 926fa9e4066Sahrens (!(seen & S_IRUSR))) { 927fa9e4066Sahrens seen |= S_IRUSR; 928da6c28aaSamw if (type == ALLOW) { 929fa9e4066Sahrens mode |= S_IRUSR; 930fa9e4066Sahrens } 931fa9e4066Sahrens } 932da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 933fa9e4066Sahrens (!(seen & S_IWUSR))) { 934fa9e4066Sahrens seen |= S_IWUSR; 935da6c28aaSamw if (type == ALLOW) { 936fa9e4066Sahrens mode |= S_IWUSR; 937fa9e4066Sahrens } 938fa9e4066Sahrens } 939da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 940fa9e4066Sahrens (!(seen & S_IXUSR))) { 941fa9e4066Sahrens seen |= S_IXUSR; 942da6c28aaSamw if (type == ALLOW) { 943fa9e4066Sahrens mode |= S_IXUSR; 944fa9e4066Sahrens } 945fa9e4066Sahrens } 94627dd1e87SMark Shellenbaum } else if (entry_type == OWNING_GROUP || 94727dd1e87SMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) { 948da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 949fa9e4066Sahrens (!(seen & S_IRGRP))) { 950fa9e4066Sahrens seen |= S_IRGRP; 951da6c28aaSamw if (type == ALLOW) { 952fa9e4066Sahrens mode |= S_IRGRP; 953fa9e4066Sahrens } 954fa9e4066Sahrens } 955da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 956fa9e4066Sahrens (!(seen & S_IWGRP))) { 957fa9e4066Sahrens seen |= S_IWGRP; 958da6c28aaSamw if (type == ALLOW) { 959fa9e4066Sahrens mode |= S_IWGRP; 960fa9e4066Sahrens } 961fa9e4066Sahrens } 962da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 963fa9e4066Sahrens (!(seen & S_IXGRP))) { 964fa9e4066Sahrens seen |= S_IXGRP; 965da6c28aaSamw if (type == ALLOW) { 966fa9e4066Sahrens mode |= S_IXGRP; 967fa9e4066Sahrens } 968fa9e4066Sahrens } 969fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 970da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 971fa9e4066Sahrens if (!(seen & S_IRUSR)) { 972fa9e4066Sahrens seen |= S_IRUSR; 973da6c28aaSamw if (type == ALLOW) { 974fa9e4066Sahrens mode |= S_IRUSR; 975fa9e4066Sahrens } 976fa9e4066Sahrens } 977fa9e4066Sahrens if (!(seen & S_IRGRP)) { 978fa9e4066Sahrens seen |= S_IRGRP; 979da6c28aaSamw if (type == ALLOW) { 980fa9e4066Sahrens mode |= S_IRGRP; 981fa9e4066Sahrens } 982fa9e4066Sahrens } 983fa9e4066Sahrens if (!(seen & S_IROTH)) { 984fa9e4066Sahrens seen |= S_IROTH; 985da6c28aaSamw if (type == ALLOW) { 986fa9e4066Sahrens mode |= S_IROTH; 987fa9e4066Sahrens } 988fa9e4066Sahrens } 989fa9e4066Sahrens } 990da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 991fa9e4066Sahrens if (!(seen & S_IWUSR)) { 992fa9e4066Sahrens seen |= S_IWUSR; 993da6c28aaSamw if (type == ALLOW) { 994fa9e4066Sahrens mode |= S_IWUSR; 995fa9e4066Sahrens } 996fa9e4066Sahrens } 997fa9e4066Sahrens if (!(seen & S_IWGRP)) { 998fa9e4066Sahrens seen |= S_IWGRP; 999da6c28aaSamw if (type == ALLOW) { 1000fa9e4066Sahrens mode |= S_IWGRP; 1001fa9e4066Sahrens } 1002fa9e4066Sahrens } 1003fa9e4066Sahrens if (!(seen & S_IWOTH)) { 1004fa9e4066Sahrens seen |= S_IWOTH; 1005da6c28aaSamw if (type == ALLOW) { 1006fa9e4066Sahrens mode |= S_IWOTH; 1007fa9e4066Sahrens } 1008fa9e4066Sahrens } 1009fa9e4066Sahrens } 1010da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 1011fa9e4066Sahrens if (!(seen & S_IXUSR)) { 1012fa9e4066Sahrens seen |= S_IXUSR; 1013da6c28aaSamw if (type == ALLOW) { 1014fa9e4066Sahrens mode |= S_IXUSR; 1015fa9e4066Sahrens } 1016fa9e4066Sahrens } 1017fa9e4066Sahrens if (!(seen & S_IXGRP)) { 1018fa9e4066Sahrens seen |= S_IXGRP; 1019da6c28aaSamw if (type == ALLOW) { 1020fa9e4066Sahrens mode |= S_IXGRP; 1021fa9e4066Sahrens } 1022fa9e4066Sahrens } 1023fa9e4066Sahrens if (!(seen & S_IXOTH)) { 1024fa9e4066Sahrens seen |= S_IXOTH; 1025da6c28aaSamw if (type == ALLOW) { 1026fa9e4066Sahrens mode |= S_IXOTH; 1027fa9e4066Sahrens } 1028fa9e4066Sahrens } 1029fa9e4066Sahrens } 1030d47621a4STim Haley } else { 1031d47621a4STim Haley /* 1032d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 1033d47621a4STim Haley * USER ACE denies execute access to someone, 1034d47621a4STim Haley * mode is not affected 1035d47621a4STim Haley */ 1036d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 1037d47621a4STim Haley an_exec_denied = B_TRUE; 1038fa9e4066Sahrens } 1039fa9e4066Sahrens } 1040d47621a4STim Haley 10414929fd5eSTim Haley /* 10424929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 10434929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 10444929fd5eSTim Haley * weren't allowed it. 10454929fd5eSTim Haley */ 10464929fd5eSTim Haley if (!an_exec_denied && 10474929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 10484929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 1049d47621a4STim Haley an_exec_denied = B_TRUE; 1050d47621a4STim Haley 1051d47621a4STim Haley if (an_exec_denied) 10520a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED; 1053d47621a4STim Haley else 10540a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED; 1055d47621a4STim Haley 1056fa9e4066Sahrens return (mode); 1057fa9e4066Sahrens } 1058fa9e4066Sahrens 1059fa9e4066Sahrens /* 10604929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 10614929fd5eSTim Haley * create a new acl and leave any cached acl in place. 1062fa9e4066Sahrens */ 1063ea8dc4b6Seschrock static int 10641412a1a2SMark Shellenbaum zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp, 10651412a1a2SMark Shellenbaum boolean_t will_modify) 1066fa9e4066Sahrens { 1067fa9e4066Sahrens zfs_acl_t *aclp; 10680a586ceaSMark Shellenbaum int aclsize; 10690a586ceaSMark Shellenbaum int acl_count; 1070da6c28aaSamw zfs_acl_node_t *aclnode; 10710a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl; 10720a586ceaSMark Shellenbaum int version; 1073ea8dc4b6Seschrock int error; 10741412a1a2SMark Shellenbaum boolean_t drop_lock = B_FALSE; 1075fa9e4066Sahrens 1076fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 1077fa9e4066Sahrens 10784929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 1079d47621a4STim Haley *aclpp = zp->z_acl_cached; 1080d47621a4STim Haley return (0); 1081d47621a4STim Haley } 1082d47621a4STim Haley 10831412a1a2SMark Shellenbaum /* 10841412a1a2SMark Shellenbaum * close race where znode could be upgrade while trying to 10851412a1a2SMark Shellenbaum * read the znode attributes. 10861412a1a2SMark Shellenbaum * 10871412a1a2SMark Shellenbaum * But this could only happen if the file isn't already an SA 10881412a1a2SMark Shellenbaum * znode 10891412a1a2SMark Shellenbaum */ 10901412a1a2SMark Shellenbaum if (!zp->z_is_sa && !have_lock) { 10911412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 10921412a1a2SMark Shellenbaum drop_lock = B_TRUE; 10931412a1a2SMark Shellenbaum } 10941412a1a2SMark Shellenbaum version = zfs_znode_acl_version(zp); 1095fa9e4066Sahrens 10960a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize, 10971412a1a2SMark Shellenbaum &acl_count, &znode_acl)) != 0) { 10981412a1a2SMark Shellenbaum goto done; 10991412a1a2SMark Shellenbaum } 1100fa9e4066Sahrens 11010a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version); 11020a586ceaSMark Shellenbaum 1103da6c28aaSamw aclp->z_acl_count = acl_count; 1104da6c28aaSamw aclp->z_acl_bytes = aclsize; 1105da6c28aaSamw 11060a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize); 11070a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count; 11080a586ceaSMark Shellenbaum aclnode->z_size = aclsize; 11090a586ceaSMark Shellenbaum 11100a586ceaSMark Shellenbaum if (!zp->z_is_sa) { 11110a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) { 11120a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os, 11130a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size, 11140a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH); 11150a586ceaSMark Shellenbaum } else { 11160a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata, 11170a586ceaSMark Shellenbaum aclnode->z_size); 11180a586ceaSMark Shellenbaum } 11190a586ceaSMark Shellenbaum } else { 11200a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs), 11210a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size); 11220a586ceaSMark Shellenbaum } 11230a586ceaSMark Shellenbaum 1124ea8dc4b6Seschrock if (error != 0) { 1125ea8dc4b6Seschrock zfs_acl_free(aclp); 11260a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode); 1127b87f3af3Sperrin /* convert checksum errors into IO errors */ 1128b87f3af3Sperrin if (error == ECKSUM) 1129be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 11301412a1a2SMark Shellenbaum goto done; 1131ea8dc4b6Seschrock } 1132fa9e4066Sahrens 11330a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode); 11340a586ceaSMark Shellenbaum 11354929fd5eSTim Haley *aclpp = aclp; 11364929fd5eSTim Haley if (!will_modify) 11374929fd5eSTim Haley zp->z_acl_cached = aclp; 11381412a1a2SMark Shellenbaum done: 11391412a1a2SMark Shellenbaum if (drop_lock) 11401412a1a2SMark Shellenbaum mutex_exit(&zp->z_lock); 11411412a1a2SMark Shellenbaum return (error); 1142fa9e4066Sahrens } 1143fa9e4066Sahrens 11440a586ceaSMark Shellenbaum /*ARGSUSED*/ 11450a586ceaSMark Shellenbaum void 11460a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, 11470a586ceaSMark Shellenbaum boolean_t start, void *userdata) 11480a586ceaSMark Shellenbaum { 11490a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata; 11500a586ceaSMark Shellenbaum 11510a586ceaSMark Shellenbaum if (start) { 11520a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl); 11530a586ceaSMark Shellenbaum } else { 11540a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, 11550a586ceaSMark Shellenbaum cb->cb_acl_node); 11560a586ceaSMark Shellenbaum } 11570a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata; 11580a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size; 11590a586ceaSMark Shellenbaum } 11600a586ceaSMark Shellenbaum 116127dd1e87SMark Shellenbaum int 116227dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp) 116327dd1e87SMark Shellenbaum { 116427dd1e87SMark Shellenbaum int error; 116527dd1e87SMark Shellenbaum zfs_acl_t *aclp; 116627dd1e87SMark Shellenbaum 11671412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_lock)); 11681412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 116927dd1e87SMark Shellenbaum 11701412a1a2SMark Shellenbaum if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0) 117127dd1e87SMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp, 1172f1696b23SMark Shellenbaum &zp->z_pflags, zp->z_uid, zp->z_gid); 117327dd1e87SMark Shellenbaum return (error); 117427dd1e87SMark Shellenbaum } 117527dd1e87SMark Shellenbaum 1176fa9e4066Sahrens /* 1177da6c28aaSamw * common code for setting ACLs. 1178fa9e4066Sahrens * 1179fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1180fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1181fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1182fa9e4066Sahrens */ 1183fa9e4066Sahrens int 118489459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1185fa9e4066Sahrens { 1186fa9e4066Sahrens int error; 1187fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1188da6c28aaSamw dmu_object_type_t otype; 11890a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 }; 11900a586ceaSMark Shellenbaum uint64_t mode; 11910a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5]; 11920a586ceaSMark Shellenbaum uint64_t ctime[2]; 11930a586ceaSMark Shellenbaum int count = 0; 1194fa9e4066Sahrens 11950a586ceaSMark Shellenbaum mode = zp->z_mode; 119627dd1e87SMark Shellenbaum 1197f1696b23SMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, 1198f1696b23SMark Shellenbaum zp->z_uid, zp->z_gid); 11990a586ceaSMark Shellenbaum 12000a586ceaSMark Shellenbaum zp->z_mode = mode; 12010a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, 12020a586ceaSMark Shellenbaum &mode, sizeof (mode)); 12030a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, 12040a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags)); 12050a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, 12060a586ceaSMark Shellenbaum &ctime, sizeof (ctime)); 1207fa9e4066Sahrens 12084929fd5eSTim Haley if (zp->z_acl_cached) { 1209d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1210d47621a4STim Haley zp->z_acl_cached = NULL; 1211d47621a4STim Haley } 1212d47621a4STim Haley 1213fa9e4066Sahrens /* 12140a586ceaSMark Shellenbaum * Upgrade needed? 1215fa9e4066Sahrens */ 1216da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1217da6c28aaSamw otype = DMU_OT_OLDACL; 1218da6c28aaSamw } else { 1219da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1220da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 122189459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1222da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1223da6c28aaSamw otype = DMU_OT_ACL; 1224da6c28aaSamw } 1225da6c28aaSamw 12260a586ceaSMark Shellenbaum /* 12270a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format 12280a586ceaSMark Shellenbaum * as well as newer (preferred) SA format. 12290a586ceaSMark Shellenbaum */ 12300a586ceaSMark Shellenbaum 12310a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */ 12320a586ceaSMark Shellenbaum locate.cb_aclp = aclp; 12330a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs), 12340a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes); 12350a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), 12360a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t)); 12370a586ceaSMark Shellenbaum } else { /* Painful legacy way */ 12380a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode; 12390a586ceaSMark Shellenbaum uint64_t off = 0; 12400a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 12410a586ceaSMark Shellenbaum uint64_t aoid; 12420a586ceaSMark Shellenbaum 12430a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 12440a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0) 12450a586ceaSMark Shellenbaum return (error); 12460a586ceaSMark Shellenbaum 12470a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj; 12480a586ceaSMark Shellenbaum 1249da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1250da6c28aaSamw /* 1251da6c28aaSamw * If ACL was previously external and we are now 1252da6c28aaSamw * converting to new ACL format then release old 1253da6c28aaSamw * ACL object and create a new one. 1254da6c28aaSamw */ 12550a586ceaSMark Shellenbaum if (aoid && 12560a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) { 12570a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx); 1258da6c28aaSamw if (error) 1259da6c28aaSamw return (error); 1260da6c28aaSamw aoid = 0; 1261da6c28aaSamw } 1262fa9e4066Sahrens if (aoid == 0) { 1263fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1264da6c28aaSamw otype, aclp->z_acl_bytes, 12650a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12660a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE, 12670a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12680a586ceaSMark Shellenbaum DN_MAX_BONUSLEN : 0, tx); 1269fa9e4066Sahrens } else { 12700a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os, 12710a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx); 1272fa9e4066Sahrens } 12730a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid; 1274da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1275da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1276da6c28aaSamw if (aclnode->z_ace_count == 0) 1277da6c28aaSamw continue; 1278da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1279da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1280da6c28aaSamw off += aclnode->z_size; 1281da6c28aaSamw } 1282fa9e4066Sahrens } else { 12830a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data; 1284fa9e4066Sahrens /* 1285fa9e4066Sahrens * Migrating back embedded? 1286fa9e4066Sahrens */ 12870a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) { 1288fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 12890a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx); 1290fa9e4066Sahrens if (error) 1291fa9e4066Sahrens return (error); 12920a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0; 1293fa9e4066Sahrens } 1294da6c28aaSamw 1295da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1296da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1297da6c28aaSamw if (aclnode->z_ace_count == 0) 1298da6c28aaSamw continue; 12990a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start, 13000a586ceaSMark Shellenbaum aclnode->z_size); 1301da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1302da6c28aaSamw } 1303fa9e4066Sahrens } 1304da6c28aaSamw /* 1305da6c28aaSamw * If Old version then swap count/bytes to match old 1306da6c28aaSamw * layout of znode_acl_phys_t. 1307da6c28aaSamw */ 1308da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 13090a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count; 13100a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes; 1311da6c28aaSamw } else { 13120a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes; 13130a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count; 1314da6c28aaSamw } 13150a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version; 1316da6c28aaSamw 13170a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL, 13180a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys)); 13190a586ceaSMark Shellenbaum } 1320da6c28aaSamw 1321da6c28aaSamw /* 1322da6c28aaSamw * Replace ACL wide bits, but first clear them. 1323da6c28aaSamw */ 13240a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS; 1325da6c28aaSamw 13260a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints; 1327da6c28aaSamw 1328da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 13290a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL; 1330fa9e4066Sahrens 13310a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE); 13320a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); 1333fa9e4066Sahrens } 1334fa9e4066Sahrens 1335fa9e4066Sahrens static void 1336a3c49ce1SAlbert Lee zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t trim, zfs_acl_t *aclp) 1337fa9e4066Sahrens { 133827dd1e87SMark Shellenbaum void *acep = NULL; 1339da6c28aaSamw uint64_t who; 134027dd1e87SMark Shellenbaum int new_count, new_bytes; 134127dd1e87SMark Shellenbaum int ace_size; 1342fa9e4066Sahrens int entry_type; 1343da6c28aaSamw uint16_t iflags, type; 1344da6c28aaSamw uint32_t access_mask; 134527dd1e87SMark Shellenbaum zfs_acl_node_t *newnode; 134627dd1e87SMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size(); 134727dd1e87SMark Shellenbaum void *zacep; 1348a3c49ce1SAlbert Lee boolean_t isdir; 1349a3c49ce1SAlbert Lee trivial_acl_t masks; 1350fa9e4066Sahrens 135127dd1e87SMark Shellenbaum new_count = new_bytes = 0; 135227dd1e87SMark Shellenbaum 1353a3c49ce1SAlbert Lee isdir = (vtype == VDIR); 1354a3c49ce1SAlbert Lee 1355a3c49ce1SAlbert Lee acl_trivial_access_masks((mode_t)mode, isdir, &masks); 135627dd1e87SMark Shellenbaum 135727dd1e87SMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes); 135827dd1e87SMark Shellenbaum 135927dd1e87SMark Shellenbaum zacep = newnode->z_acldata; 1360a3c49ce1SAlbert Lee if (masks.allow0) { 1361a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER); 136227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136327dd1e87SMark Shellenbaum new_count++; 136427dd1e87SMark Shellenbaum new_bytes += abstract_size; 1365*f7170741SWill Andrews } 1366*f7170741SWill Andrews if (masks.deny1) { 1367a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER); 136827dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136927dd1e87SMark Shellenbaum new_count++; 137027dd1e87SMark Shellenbaum new_bytes += abstract_size; 137127dd1e87SMark Shellenbaum } 1372a3c49ce1SAlbert Lee if (masks.deny2) { 1373a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP); 137427dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 137527dd1e87SMark Shellenbaum new_count++; 137627dd1e87SMark Shellenbaum new_bytes += abstract_size; 137727dd1e87SMark Shellenbaum } 13782459a9eaSmarks 1379da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1380da6c28aaSamw &iflags, &type)) { 138127dd1e87SMark Shellenbaum uint16_t inherit_flags; 1382fa9e4066Sahrens 1383da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 138427dd1e87SMark Shellenbaum inherit_flags = (iflags & ALL_INHERIT); 138527dd1e87SMark Shellenbaum 138627dd1e87SMark Shellenbaum if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 138727dd1e87SMark Shellenbaum (entry_type == OWNING_GROUP)) && 138827dd1e87SMark Shellenbaum ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) { 138927dd1e87SMark Shellenbaum continue; 139027dd1e87SMark Shellenbaum } 1391da6c28aaSamw 1392a3c49ce1SAlbert Lee /* 1393a3c49ce1SAlbert Lee * If this ACL has any inheritable ACEs, mark that in 1394a3c49ce1SAlbert Lee * the hints (which are later masked into the pflags) 1395a3c49ce1SAlbert Lee * so create knows to do inheritance. 1396a3c49ce1SAlbert Lee */ 1397a3c49ce1SAlbert Lee if (isdir && (inherit_flags & 1398a3c49ce1SAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 1399a3c49ce1SAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE; 1400a3c49ce1SAlbert Lee 1401da6c28aaSamw if ((type != ALLOW && type != DENY) || 140227dd1e87SMark Shellenbaum (inherit_flags & ACE_INHERIT_ONLY_ACE)) { 1403da6c28aaSamw switch (type) { 1404da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1405da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1406da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1407da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1408da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1409da6c28aaSamw break; 1410fa9e4066Sahrens } 1411fa9e4066Sahrens } else { 1412fa9e4066Sahrens 1413fa9e4066Sahrens /* 141427dd1e87SMark Shellenbaum * Limit permissions to be no greater than 1415a3c49ce1SAlbert Lee * group permissions. 1416a3c49ce1SAlbert Lee * The "aclinherit" and "aclmode" properties 1417a3c49ce1SAlbert Lee * affect policy for create and chmod(2), 1418a3c49ce1SAlbert Lee * respectively. 1419fa9e4066Sahrens */ 1420a3c49ce1SAlbert Lee if ((type == ALLOW) && trim) 1421a3c49ce1SAlbert Lee access_mask &= masks.group; 1422fa9e4066Sahrens } 142327dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags); 142427dd1e87SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 142527dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size); 142627dd1e87SMark Shellenbaum new_count++; 142727dd1e87SMark Shellenbaum new_bytes += ace_size; 1428fa9e4066Sahrens } 1429a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.owner, 0, -1, ACE_OWNER); 143027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1431a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.group, 0, -1, OWNING_GROUP); 143227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1433a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.everyone, 0, -1, ACE_EVERYONE); 1434fa9e4066Sahrens 143527dd1e87SMark Shellenbaum new_count += 3; 143627dd1e87SMark Shellenbaum new_bytes += abstract_size * 3; 143727dd1e87SMark Shellenbaum zfs_acl_release_nodes(aclp); 143827dd1e87SMark Shellenbaum aclp->z_acl_count = new_count; 143927dd1e87SMark Shellenbaum aclp->z_acl_bytes = new_bytes; 144027dd1e87SMark Shellenbaum newnode->z_ace_count = new_count; 144127dd1e87SMark Shellenbaum newnode->z_size = new_bytes; 144227dd1e87SMark Shellenbaum list_insert_tail(&aclp->z_acl, newnode); 1443fa9e4066Sahrens } 1444fa9e4066Sahrens 1445a3c49ce1SAlbert Lee int 14464c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1447fa9e4066Sahrens { 1448a3c49ce1SAlbert Lee int error = 0; 1449a3c49ce1SAlbert Lee 1450fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 14511412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1452a3c49ce1SAlbert Lee if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 145327dd1e87SMark Shellenbaum *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); 1454a3c49ce1SAlbert Lee else 1455a3c49ce1SAlbert Lee error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE); 1456a3c49ce1SAlbert Lee 1457a3c49ce1SAlbert Lee if (error == 0) { 14580a586ceaSMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; 1459a3c49ce1SAlbert Lee zfs_acl_chmod(ZTOV(zp)->v_type, mode, 1460a3c49ce1SAlbert Lee (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp); 1461a3c49ce1SAlbert Lee } 14624c841f60Smarks mutex_exit(&zp->z_lock); 14631412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 1464a3c49ce1SAlbert Lee 1465a3c49ce1SAlbert Lee return (error); 1466fa9e4066Sahrens } 1467fa9e4066Sahrens 1468fa9e4066Sahrens /* 1469fa9e4066Sahrens * strip off write_owner and write_acl 1470fa9e4066Sahrens */ 1471fa9e4066Sahrens static void 1472b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1473fa9e4066Sahrens { 1474da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1475da6c28aaSamw 1476b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1477da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1478b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1479da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1480da6c28aaSamw } 1481da6c28aaSamw } 1482da6c28aaSamw 1483da6c28aaSamw /* 1484da6c28aaSamw * Should ACE be inherited? 1485da6c28aaSamw */ 1486da6c28aaSamw static int 148789459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1488da6c28aaSamw { 1489da6c28aaSamw int iflags = (acep_flags & 0xf); 1490da6c28aaSamw 1491da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1492da6c28aaSamw return (1); 1493da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1494da6c28aaSamw return (!((vtype == VDIR) && 1495da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1496da6c28aaSamw return (0); 1497fa9e4066Sahrens } 1498fa9e4066Sahrens 1499fa9e4066Sahrens /* 1500fa9e4066Sahrens * inherit inheritable ACEs from parent 1501fa9e4066Sahrens */ 1502fa9e4066Sahrens static zfs_acl_t * 150389459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 150489459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1505fa9e4066Sahrens { 1506da6c28aaSamw void *pacep; 150727dd1e87SMark Shellenbaum void *acep; 150827dd1e87SMark Shellenbaum zfs_acl_node_t *aclnode; 1509fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1510da6c28aaSamw uint64_t who; 1511da6c28aaSamw uint32_t access_mask; 1512da6c28aaSamw uint16_t iflags, newflags, type; 1513da6c28aaSamw size_t ace_size; 1514da6c28aaSamw void *data1, *data2; 1515da6c28aaSamw size_t data1sz, data2sz; 151689459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 151789459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1518d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1519d0f3f37eSMark Shellenbaum 1520d0f3f37eSMark Shellenbaum passthrough_x = 1521d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1522d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1523d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1524d0f3f37eSMark Shellenbaum noallow = 1525d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1526fa9e4066Sahrens 1527b3d141f8Smarks *need_chmod = B_TRUE; 1528da6c28aaSamw pacep = NULL; 1529003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 15300a586ceaSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK) 1531d0f3f37eSMark Shellenbaum return (aclp); 1532da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1533da6c28aaSamw &access_mask, &iflags, &type)) { 1534fa9e4066Sahrens 1535003c2582SMark Shellenbaum /* 1536003c2582SMark Shellenbaum * don't inherit bogus ACEs 1537003c2582SMark Shellenbaum */ 1538003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1539003c2582SMark Shellenbaum continue; 1540003c2582SMark Shellenbaum 1541d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1542fa9e4066Sahrens continue; 1543fa9e4066Sahrens 1544da6c28aaSamw ace_size = aclp->z_ops.ace_size(pacep); 1545fa9e4066Sahrens 154689459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1547b3d141f8Smarks continue; 1548fa9e4066Sahrens 1549b3d141f8Smarks /* 1550b3d141f8Smarks * If owner@, group@, or everyone@ inheritable 1551b3d141f8Smarks * then zfs_acl_chmod() isn't needed. 1552b3d141f8Smarks */ 1553d0f3f37eSMark Shellenbaum if (passthrough && 1554b3d141f8Smarks ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1555b3d141f8Smarks ((iflags & OWNING_GROUP) == 1556d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1557d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1558b3d141f8Smarks *need_chmod = B_FALSE; 1559c694df91SMark Shellenbaum } 1560b3d141f8Smarks 1561d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1562d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1563d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1564d0f3f37eSMark Shellenbaum } 1565d0f3f37eSMark Shellenbaum 1566b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1567da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1568da6c28aaSamw acep = aclnode->z_acldata; 1569d0f3f37eSMark Shellenbaum 1570da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1571da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1572169cdae2Smarks 1573fa9e4066Sahrens /* 1574da6c28aaSamw * Copy special opaque data if any 1575fa9e4066Sahrens */ 1576d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1577b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1578da6c28aaSamw &data2)) == data1sz); 1579da6c28aaSamw bcopy(data1, data2, data2sz); 1580da6c28aaSamw } 158127dd1e87SMark Shellenbaum 1582da6c28aaSamw aclp->z_acl_count++; 1583da6c28aaSamw aclnode->z_ace_count++; 1584da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1585da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1586b3d141f8Smarks 1587d0f3f37eSMark Shellenbaum if (vdir) 1588b3d141f8Smarks aclp->z_hints |= ZFS_INHERIT_ACE; 1589b3d141f8Smarks 1590d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1591da6c28aaSamw newflags &= ~ALL_INHERIT; 1592da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1593da6c28aaSamw newflags|ACE_INHERITED_ACE); 1594b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep); 1595fa9e4066Sahrens continue; 1596fa9e4066Sahrens } 1597fa9e4066Sahrens 1598d0f3f37eSMark Shellenbaum ASSERT(vdir); 1599fa9e4066Sahrens 1600da6c28aaSamw /* 160127dd1e87SMark Shellenbaum * If only FILE_INHERIT is set then turn on 160227dd1e87SMark Shellenbaum * inherit_only 1603da6c28aaSamw */ 160427dd1e87SMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE | 1605485adf61SMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) { 1606da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1607da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1608da6c28aaSamw newflags|ACE_INHERITED_ACE); 1609485adf61SMark Shellenbaum } else { 1610485adf61SMark Shellenbaum newflags &= ~ACE_INHERIT_ONLY_ACE; 1611485adf61SMark Shellenbaum aclp->z_ops.ace_flags_set(acep, 1612485adf61SMark Shellenbaum newflags|ACE_INHERITED_ACE); 1613da6c28aaSamw } 1614da6c28aaSamw } 1615fa9e4066Sahrens return (aclp); 1616fa9e4066Sahrens } 1617fa9e4066Sahrens 1618fa9e4066Sahrens /* 1619fa9e4066Sahrens * Create file system object initial permissions 1620fa9e4066Sahrens * including inheritable ACEs. 1621fa9e4066Sahrens */ 162289459e17SMark Shellenbaum int 162389459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 162489459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1625fa9e4066Sahrens { 1626fa9e4066Sahrens int error; 162789459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1628da6c28aaSamw zfs_acl_t *paclp; 1629e0d35c44Smarks gid_t gid; 1630b3d141f8Smarks boolean_t need_chmod = B_TRUE; 16310a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE; 1632da6c28aaSamw 163389459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 163489459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1635fa9e4066Sahrens 163689459e17SMark Shellenbaum if (vsecp) 163789459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 163889459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 163989459e17SMark Shellenbaum return (error); 1640fa9e4066Sahrens /* 1641fa9e4066Sahrens * Determine uid and gid. 1642fa9e4066Sahrens */ 16434a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1644fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 164589459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 164689459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 164789459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 164889459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 164989459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 165089459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1651e0d35c44Smarks gid = vap->va_gid; 1652fa9e4066Sahrens } else { 165389459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 165489459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 165589459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1656e0d35c44Smarks if (vap->va_mask & AT_GID) { 165789459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 165889459e17SMark Shellenbaum (uint64_t)vap->va_gid, 165989459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1660e0d35c44Smarks gid = vap->va_gid; 1661f1696b23SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_gid && 1662e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1663e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 166489459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1665e0d35c44Smarks } 166689459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 16670a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) { 1668b3874165SJohn Harres char *domain; 1669b3874165SJohn Harres uint32_t rid; 1670b3874165SJohn Harres 1671f1696b23SMark Shellenbaum acl_ids->z_fgid = dzp->z_gid; 167289459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1673e0d35c44Smarks cr, ZFS_GROUP); 1674b3874165SJohn Harres 1675b3874165SJohn Harres if (zfsvfs->z_use_fuids && 1676b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) { 1677b3874165SJohn Harres domain = zfs_fuid_idx_domain( 1678b3874165SJohn Harres &zfsvfs->z_fuid_idx, 1679b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid)); 1680b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid); 1681b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp, 1682b3874165SJohn Harres domain, rid, 1683b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid), 1684b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP); 1685b3874165SJohn Harres } 1686da6c28aaSamw } else { 168789459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 168889459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1689e0d35c44Smarks gid = crgetgid(cr); 1690e0d35c44Smarks } 1691da6c28aaSamw } 1692fa9e4066Sahrens } 1693fa9e4066Sahrens 1694fa9e4066Sahrens /* 1695fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1696fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1697fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1698fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1699fa9e4066Sahrens */ 1700fa9e4066Sahrens 17010a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) && 170289459e17SMark Shellenbaum (vap->va_type == VDIR)) { 170389459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1704e0d35c44Smarks } else { 170589459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1706fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 170789459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1708fa9e4066Sahrens } 1709fa9e4066Sahrens 171089459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 17111412a1a2SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 171289459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 1713a3c49ce1SAlbert Lee if (!(flag & IS_ROOT_NODE) && 1714a3c49ce1SAlbert Lee (dzp->z_pflags & ZFS_INHERIT_ACE) && 17150a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) { 17161412a1a2SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE, 17171412a1a2SMark Shellenbaum &paclp, B_FALSE)); 171889459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 171989459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 17200a586ceaSMark Shellenbaum inherited = B_TRUE; 1721fa9e4066Sahrens } else { 172289459e17SMark Shellenbaum acl_ids->z_aclp = 172389459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 17240a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 1725fa9e4066Sahrens } 172689459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 17271412a1a2SMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 172889459e17SMark Shellenbaum if (need_chmod) { 17290a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ? 173089459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 1731a3c49ce1SAlbert Lee zfs_acl_chmod(vap->va_type, acl_ids->z_mode, 1732a3c49ce1SAlbert Lee (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED), 1733a3c49ce1SAlbert Lee acl_ids->z_aclp); 173489459e17SMark Shellenbaum } 1735da6c28aaSamw } 1736da6c28aaSamw 17370a586ceaSMark Shellenbaum if (inherited || vsecp) { 17380a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode, 173927dd1e87SMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints, 174027dd1e87SMark Shellenbaum acl_ids->z_fuid, acl_ids->z_fgid); 17410a586ceaSMark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0) 17420a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 17430a586ceaSMark Shellenbaum } 17440a586ceaSMark Shellenbaum 174589459e17SMark Shellenbaum return (0); 1746fa9e4066Sahrens } 1747fa9e4066Sahrens 1748fa9e4066Sahrens /* 174989459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 175089459e17SMark Shellenbaum */ 175189459e17SMark Shellenbaum void 175289459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 175389459e17SMark Shellenbaum { 175489459e17SMark Shellenbaum if (acl_ids->z_aclp) 175589459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 175689459e17SMark Shellenbaum if (acl_ids->z_fuidp) 175789459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 175889459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 175989459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 176089459e17SMark Shellenbaum } 176189459e17SMark Shellenbaum 176214843421SMatthew Ahrens boolean_t 176314843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 176414843421SMatthew Ahrens { 17650a586ceaSMark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 17660a586ceaSMark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 176714843421SMatthew Ahrens } 176889459e17SMark Shellenbaum 176989459e17SMark Shellenbaum /* 1770*f7170741SWill Andrews * Retrieve a file's ACL 1771fa9e4066Sahrens */ 1772fa9e4066Sahrens int 1773da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1774fa9e4066Sahrens { 1775fa9e4066Sahrens zfs_acl_t *aclp; 1776da6c28aaSamw ulong_t mask; 1777fa9e4066Sahrens int error; 1778da6c28aaSamw int count = 0; 1779da6c28aaSamw int largeace = 0; 1780fa9e4066Sahrens 1781da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1782da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1783da6c28aaSamw 1784fa9e4066Sahrens if (mask == 0) 1785be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 1786fa9e4066Sahrens 17870a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 17880a586ceaSMark Shellenbaum return (error); 17890a586ceaSMark Shellenbaum 1790fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1791fa9e4066Sahrens 17921412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 1793ea8dc4b6Seschrock if (error != 0) { 1794ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1795ea8dc4b6Seschrock return (error); 1796ea8dc4b6Seschrock } 1797ea8dc4b6Seschrock 1798da6c28aaSamw /* 1799da6c28aaSamw * Scan ACL to determine number of ACEs 1800da6c28aaSamw */ 18010a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) { 1802da6c28aaSamw void *zacep = NULL; 1803da6c28aaSamw uint64_t who; 1804da6c28aaSamw uint32_t access_mask; 1805da6c28aaSamw uint16_t type, iflags; 1806da6c28aaSamw 1807da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1808da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1809da6c28aaSamw switch (type) { 1810da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1811da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1812da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1813da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1814da6c28aaSamw largeace++; 1815da6c28aaSamw continue; 1816da6c28aaSamw default: 1817da6c28aaSamw count++; 1818da6c28aaSamw } 1819da6c28aaSamw } 1820da6c28aaSamw vsecp->vsa_aclcnt = count; 1821da6c28aaSamw } else 18220a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count; 1823fa9e4066Sahrens 1824fa9e4066Sahrens if (mask & VSA_ACECNT) { 1825da6c28aaSamw vsecp->vsa_aclcnt = count; 1826fa9e4066Sahrens } 1827fa9e4066Sahrens 1828fa9e4066Sahrens if (mask & VSA_ACE) { 1829da6c28aaSamw size_t aclsz; 1830da6c28aaSamw 1831da6c28aaSamw aclsz = count * sizeof (ace_t) + 1832da6c28aaSamw sizeof (ace_object_t) * largeace; 1833da6c28aaSamw 1834da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 1835da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 1836da6c28aaSamw 1837da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 1838bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 1839da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 1840da6c28aaSamw else { 18412e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode; 18422e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp; 18432e7d9b42SMark Shellenbaum 18442e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode; 18452e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) { 18462e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start, 18472e7d9b42SMark Shellenbaum aclnode->z_size); 18482e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size; 18492e7d9b42SMark Shellenbaum } 18502e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 18512e7d9b42SMark Shellenbaum aclp->z_acl_bytes); 1852da6c28aaSamw } 1853da6c28aaSamw } 1854da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 1855da6c28aaSamw vsecp->vsa_aclflags = 0; 18560a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED) 1857da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 18580a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED) 1859da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 18600a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT) 1861da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 1862fa9e4066Sahrens } 1863fa9e4066Sahrens 1864fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1865fa9e4066Sahrens 1866fa9e4066Sahrens return (0); 1867fa9e4066Sahrens } 1868fa9e4066Sahrens 1869da6c28aaSamw int 1870da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 187189459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 1872da6c28aaSamw { 1873da6c28aaSamw zfs_acl_t *aclp; 1874da6c28aaSamw zfs_acl_node_t *aclnode; 1875da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 1876da6c28aaSamw int error; 1877da6c28aaSamw 1878da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 1879be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1880da6c28aaSamw 1881da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 1882da6c28aaSamw 1883da6c28aaSamw aclp->z_hints = 0; 1884da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 1885da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1886da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 1887da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 1888da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 1889da6c28aaSamw zfs_acl_free(aclp); 1890da6c28aaSamw zfs_acl_node_free(aclnode); 1891da6c28aaSamw return (error); 1892da6c28aaSamw } 1893da6c28aaSamw } else { 189489459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 1895da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 189689459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 1897da6c28aaSamw zfs_acl_free(aclp); 1898da6c28aaSamw zfs_acl_node_free(aclnode); 1899da6c28aaSamw return (error); 1900da6c28aaSamw } 1901da6c28aaSamw } 1902da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 1903da6c28aaSamw aclnode->z_ace_count = aclcnt; 1904da6c28aaSamw aclp->z_acl_count = aclcnt; 1905da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1906da6c28aaSamw 1907da6c28aaSamw /* 1908da6c28aaSamw * If flags are being set then add them to z_hints 1909da6c28aaSamw */ 1910da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 1911da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 1912da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 1913da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 1914da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 1915da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 1916da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 1917da6c28aaSamw } 1918da6c28aaSamw 1919da6c28aaSamw *zaclp = aclp; 1920da6c28aaSamw 1921da6c28aaSamw return (0); 1922da6c28aaSamw } 1923da6c28aaSamw 1924fa9e4066Sahrens /* 1925*f7170741SWill Andrews * Set a file's ACL 1926fa9e4066Sahrens */ 1927fa9e4066Sahrens int 1928da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1929fa9e4066Sahrens { 1930fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1931fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 1932fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 1933fa9e4066Sahrens dmu_tx_t *tx; 1934fa9e4066Sahrens int error; 1935fa9e4066Sahrens zfs_acl_t *aclp; 1936da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 193789459e17SMark Shellenbaum boolean_t fuid_dirtied; 19381412a1a2SMark Shellenbaum uint64_t acl_obj; 1939fa9e4066Sahrens 1940fa9e4066Sahrens if (mask == 0) 1941be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 1942fa9e4066Sahrens 19430a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE) 1944be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 1945da6c28aaSamw 1946da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 1947fa9e4066Sahrens return (error); 1948da6c28aaSamw 194989459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 195089459e17SMark Shellenbaum &aclp); 1951da6c28aaSamw if (error) 1952da6c28aaSamw return (error); 1953da6c28aaSamw 1954da6c28aaSamw /* 1955da6c28aaSamw * If ACL wide flags aren't being set then preserve any 1956da6c28aaSamw * existing flags. 1957da6c28aaSamw */ 1958da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 19590a586ceaSMark Shellenbaum aclp->z_hints |= 19600a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS); 1961fa9e4066Sahrens } 1962da6c28aaSamw top: 1963fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 19641412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1965fa9e4066Sahrens 1966fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 1967fa9e4066Sahrens 19680a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); 19690a586ceaSMark Shellenbaum 197089459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 197114843421SMatthew Ahrens if (fuid_dirtied) 197214843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 1973fa9e4066Sahrens 19740a586ceaSMark Shellenbaum /* 19750a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't 19760a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds 19770a586ceaSMark Shellenbaum */ 19780a586ceaSMark Shellenbaum 19791412a1a2SMark Shellenbaum if ((acl_obj = zfs_external_acl(zp)) != 0) { 19802bd6c4deSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_FUID && 19811412a1a2SMark Shellenbaum zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) { 19821412a1a2SMark Shellenbaum dmu_tx_hold_free(tx, acl_obj, 0, 19830a586ceaSMark Shellenbaum DMU_OBJECT_END); 19842bd6c4deSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 19852bd6c4deSMark Shellenbaum aclp->z_acl_bytes); 19860a586ceaSMark Shellenbaum } else { 19871412a1a2SMark Shellenbaum dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes); 19880a586ceaSMark Shellenbaum } 19890a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { 19900a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 19910a586ceaSMark Shellenbaum } 19920a586ceaSMark Shellenbaum 19930a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp); 19941209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 1995fa9e4066Sahrens if (error) { 1996fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1997fa9e4066Sahrens mutex_exit(&zp->z_lock); 1998fa9e4066Sahrens 19991209a471SNeil Perrin if (error == ERESTART) { 20008a2f1b91Sahrens dmu_tx_wait(tx); 20018a2f1b91Sahrens dmu_tx_abort(tx); 2002fa9e4066Sahrens goto top; 2003fa9e4066Sahrens } 20048a2f1b91Sahrens dmu_tx_abort(tx); 2005da6c28aaSamw zfs_acl_free(aclp); 2006fa9e4066Sahrens return (error); 2007fa9e4066Sahrens } 2008fa9e4066Sahrens 200989459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2010fa9e4066Sahrens ASSERT(error == 0); 20110b2a8171SMark Shellenbaum ASSERT(zp->z_acl_cached == NULL); 20124929fd5eSTim Haley zp->z_acl_cached = aclp; 2013fa9e4066Sahrens 201489459e17SMark Shellenbaum if (fuid_dirtied) 201589459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 201689459e17SMark Shellenbaum 2017da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2018da6c28aaSamw 2019da6c28aaSamw if (fuidp) 2020da6c28aaSamw zfs_fuid_info_free(fuidp); 2021fa9e4066Sahrens dmu_tx_commit(tx); 2022fa9e4066Sahrens done: 2023fa9e4066Sahrens mutex_exit(&zp->z_lock); 20241412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 2025fa9e4066Sahrens 2026fa9e4066Sahrens return (error); 2027fa9e4066Sahrens } 2028fa9e4066Sahrens 2029fa9e4066Sahrens /* 2030e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2031e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2032e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2033fa9e4066Sahrens */ 2034fa9e4066Sahrens static int 2035e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2036fa9e4066Sahrens { 2037fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2038fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2039f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2040f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2041be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS)); 2042fa9e4066Sahrens } 2043fa9e4066Sahrens 2044da6c28aaSamw /* 2045da6c28aaSamw * Only check for READONLY on non-directories. 2046da6c28aaSamw */ 2047da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2048da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 20490a586ceaSMark Shellenbaum (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2050da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 20510a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_IMMUTABLE)))) { 2052be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2053da6c28aaSamw } 2054da6c28aaSamw 2055da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 20560a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) { 2057be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2058da6c28aaSamw } 2059da6c28aaSamw 2060da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 20610a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) { 2062be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2063da6c28aaSamw } 2064da6c28aaSamw 2065da6c28aaSamw return (0); 2066da6c28aaSamw } 2067da6c28aaSamw 2068e802abbdSTim Haley /* 2069e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2070e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2071e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2072e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2073e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2074e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2075e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2076e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2077e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2078e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2079e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2080e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2081e802abbdSTim Haley * accesses. Returns: 2082e802abbdSTim Haley * 0 if all AoI granted 2083e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2084e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2085e802abbdSTim Haley * 2086e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2087e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2088e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2089e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2090e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2091e802abbdSTim Haley * is used in this manner. 2092e802abbdSTim Haley */ 2093e802abbdSTim Haley static int 2094e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2095e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2096e802abbdSTim Haley { 2097e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2098e802abbdSTim Haley zfs_acl_t *aclp; 2099e802abbdSTim Haley int error; 2100e802abbdSTim Haley uid_t uid = crgetuid(cr); 2101e802abbdSTim Haley uint64_t who; 2102e802abbdSTim Haley uint16_t type, iflags; 2103e802abbdSTim Haley uint16_t entry_type; 2104e802abbdSTim Haley uint32_t access_mask; 2105e802abbdSTim Haley uint32_t deny_mask = 0; 2106e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2107e802abbdSTim Haley boolean_t checkit; 2108f1696b23SMark Shellenbaum uid_t gowner; 2109f1696b23SMark Shellenbaum uid_t fowner; 2110f1696b23SMark Shellenbaum 2111f1696b23SMark Shellenbaum zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 2112da6c28aaSamw 2113fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2114fa9e4066Sahrens 21151412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 2116ea8dc4b6Seschrock if (error != 0) { 2117ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2118ea8dc4b6Seschrock return (error); 2119ea8dc4b6Seschrock } 2120ea8dc4b6Seschrock 21210a586ceaSMark Shellenbaum ASSERT(zp->z_acl_cached); 21220a586ceaSMark Shellenbaum 2123da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2124da6c28aaSamw &iflags, &type)) { 2125e802abbdSTim Haley uint32_t mask_matched; 2126fa9e4066Sahrens 2127003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2128003c2582SMark Shellenbaum continue; 2129003c2582SMark Shellenbaum 2130b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2131fa9e4066Sahrens continue; 2132fa9e4066Sahrens 2133e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2134e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2135e802abbdSTim Haley if (!mask_matched) 2136e802abbdSTim Haley continue; 2137e802abbdSTim Haley 2138da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2139da6c28aaSamw 2140da6c28aaSamw checkit = B_FALSE; 2141da6c28aaSamw 2142fa9e4066Sahrens switch (entry_type) { 2143fa9e4066Sahrens case ACE_OWNER: 2144f1696b23SMark Shellenbaum if (uid == fowner) 2145da6c28aaSamw checkit = B_TRUE; 2146fa9e4066Sahrens break; 2147da6c28aaSamw case OWNING_GROUP: 2148da6c28aaSamw who = gowner; 2149da6c28aaSamw /*FALLTHROUGH*/ 2150fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2151da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2152fa9e4066Sahrens break; 2153fa9e4066Sahrens case ACE_EVERYONE: 2154da6c28aaSamw checkit = B_TRUE; 2155fa9e4066Sahrens break; 2156fa9e4066Sahrens 2157fa9e4066Sahrens /* USER Entry */ 2158fa9e4066Sahrens default: 2159fa9e4066Sahrens if (entry_type == 0) { 2160da6c28aaSamw uid_t newid; 2161da6c28aaSamw 2162e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2163e0d35c44Smarks ZFS_ACE_USER); 2164da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2165da6c28aaSamw uid == newid) 2166da6c28aaSamw checkit = B_TRUE; 2167fa9e4066Sahrens break; 2168da6c28aaSamw } else { 2169fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2170be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 2171fa9e4066Sahrens } 2172da6c28aaSamw } 2173da6c28aaSamw 2174da6c28aaSamw if (checkit) { 2175e802abbdSTim Haley if (type == DENY) { 2176e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2177e802abbdSTim Haley znode_t *, zp, 2178e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2179e802abbdSTim Haley uint32_t, mask_matched); 218090fafcf0Smarks deny_mask |= mask_matched; 2181e802abbdSTim Haley } else { 2182e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2183e802abbdSTim Haley znode_t *, zp, 2184e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2185e802abbdSTim Haley uint32_t, mask_matched); 2186e802abbdSTim Haley if (anyaccess) { 2187e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2188e802abbdSTim Haley return (0); 2189da6c28aaSamw } 2190da6c28aaSamw } 2191e802abbdSTim Haley *working_mode &= ~mask_matched; 2192e802abbdSTim Haley } 2193fa9e4066Sahrens 219490fafcf0Smarks /* Are we done? */ 219590fafcf0Smarks if (*working_mode == 0) 2196fa9e4066Sahrens break; 2197fa9e4066Sahrens } 2198fa9e4066Sahrens 2199fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 220090fafcf0Smarks 220190fafcf0Smarks /* Put the found 'denies' back on the working mode */ 22027ed7e920Smarks if (deny_mask) { 220390fafcf0Smarks *working_mode |= deny_mask; 2204be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 22057ed7e920Smarks } else if (*working_mode) { 22067ed7e920Smarks return (-1); 22077ed7e920Smarks } 220890fafcf0Smarks 220990fafcf0Smarks return (0); 2210fa9e4066Sahrens } 2211fa9e4066Sahrens 2212e802abbdSTim Haley /* 2213e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2214e802abbdSTim Haley * care what access is granted. 2215e802abbdSTim Haley */ 2216e802abbdSTim Haley boolean_t 2217e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2218e802abbdSTim Haley { 2219e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2220e802abbdSTim Haley 2221e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2222f1696b23SMark Shellenbaum uid_t owner; 2223f1696b23SMark Shellenbaum 2224f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2225f1696b23SMark Shellenbaum return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0); 2226e802abbdSTim Haley } 2227e802abbdSTim Haley return (B_TRUE); 2228e802abbdSTim Haley } 2229e802abbdSTim Haley 2230e802abbdSTim Haley static int 2231e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2232e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2233e802abbdSTim Haley { 2234e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2235e802abbdSTim Haley int err; 2236e802abbdSTim Haley 2237e802abbdSTim Haley *working_mode = v4_mode; 2238e802abbdSTim Haley *check_privs = B_TRUE; 2239e802abbdSTim Haley 2240e802abbdSTim Haley /* 2241e802abbdSTim Haley * Short circuit empty requests 2242e802abbdSTim Haley */ 2243e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2244e802abbdSTim Haley *working_mode = 0; 2245e802abbdSTim Haley return (0); 2246e802abbdSTim Haley } 2247e802abbdSTim Haley 2248e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2249e802abbdSTim Haley *check_privs = B_FALSE; 2250e802abbdSTim Haley return (err); 2251e802abbdSTim Haley } 2252e802abbdSTim Haley 2253e802abbdSTim Haley /* 2254e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2255e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2256e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2257e802abbdSTim Haley */ 2258e802abbdSTim Haley if (skipaclchk) { 2259e802abbdSTim Haley *working_mode = 0; 2260e802abbdSTim Haley return (0); 2261e802abbdSTim Haley } 2262e802abbdSTim Haley 2263e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2264e802abbdSTim Haley } 2265e802abbdSTim Haley 2266da6c28aaSamw static int 2267da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2268da6c28aaSamw cred_t *cr) 2269da6c28aaSamw { 2270da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2271be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2272da6c28aaSamw 2273da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2274da6c28aaSamw check_privs, B_FALSE, cr)); 2275da6c28aaSamw } 2276fa9e4066Sahrens 2277d47621a4STim Haley int 2278d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2279d47621a4STim Haley { 2280d47621a4STim Haley boolean_t owner = B_FALSE; 2281d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2282d47621a4STim Haley boolean_t is_attr; 2283d47621a4STim Haley uid_t uid = crgetuid(cr); 2284d47621a4STim Haley int error; 2285d47621a4STim Haley 22860a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED) 2287be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2288d47621a4STim Haley 22890a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) && 2290d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2291d47621a4STim Haley if (is_attr) 2292d47621a4STim Haley goto slow; 2293d47621a4STim Haley 22940a586ceaSMark Shellenbaum 2295d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2296d47621a4STim Haley 22970a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) { 2298d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2299d47621a4STim Haley return (0); 2300d47621a4STim Haley } 2301d47621a4STim Haley 2302f1696b23SMark Shellenbaum if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) { 2303d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2304d47621a4STim Haley goto slow; 2305d47621a4STim Haley } 2306d47621a4STim Haley 23070a586ceaSMark Shellenbaum if (uid == zdp->z_uid) { 2308d47621a4STim Haley owner = B_TRUE; 23090a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) { 2310d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2311d47621a4STim Haley return (0); 2312e4f96946STim Haley } else { 2313e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2314e4f96946STim Haley goto slow; 2315d47621a4STim Haley } 2316d47621a4STim Haley } 23170a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) { 2318d47621a4STim Haley groupmbr = B_TRUE; 23190a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) { 2320d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2321d47621a4STim Haley return (0); 2322e4f96946STim Haley } else { 2323e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2324e4f96946STim Haley goto slow; 2325d47621a4STim Haley } 2326d47621a4STim Haley } 2327d47621a4STim Haley if (!owner && !groupmbr) { 23280a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) { 2329d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2330d47621a4STim Haley return (0); 2331d47621a4STim Haley } 2332d47621a4STim Haley } 2333d47621a4STim Haley 2334d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2335d47621a4STim Haley 2336d47621a4STim Haley slow: 2337d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2338d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2339d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2340d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2341d47621a4STim Haley return (error); 2342d47621a4STim Haley } 2343d47621a4STim Haley 2344fa9e4066Sahrens /* 2345134a1f4eSCasper H.S. Dik * Determine whether Access should be granted/denied. 2346*f7170741SWill Andrews * 2347134a1f4eSCasper H.S. Dik * The least priv subsytem is always consulted as a basic privilege 2348134a1f4eSCasper H.S. Dik * can define any form of access. 2349fa9e4066Sahrens */ 2350fa9e4066Sahrens int 2351da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2352fa9e4066Sahrens { 2353da6c28aaSamw uint32_t working_mode; 2354fa9e4066Sahrens int error; 2355fa9e4066Sahrens int is_attr; 2356da6c28aaSamw boolean_t check_privs; 2357fa9e4066Sahrens znode_t *xzp; 2358fa9e4066Sahrens znode_t *check_zp = zp; 2359134a1f4eSCasper H.S. Dik mode_t needed_bits; 2360f1696b23SMark Shellenbaum uid_t owner; 2361fa9e4066Sahrens 23620a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); 2363fa9e4066Sahrens 2364fa9e4066Sahrens /* 2365fa9e4066Sahrens * If attribute then validate against base file 2366fa9e4066Sahrens */ 2367fa9e4066Sahrens if (is_attr) { 23680a586ceaSMark Shellenbaum uint64_t parent; 23690a586ceaSMark Shellenbaum 23700a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 23710a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent, 23720a586ceaSMark Shellenbaum sizeof (parent))) != 0) 23730a586ceaSMark Shellenbaum return (error); 23740a586ceaSMark Shellenbaum 2375fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 23760a586ceaSMark Shellenbaum parent, &xzp)) != 0) { 2377fa9e4066Sahrens return (error); 2378fa9e4066Sahrens } 2379da6c28aaSamw 2380fa9e4066Sahrens check_zp = xzp; 2381da6c28aaSamw 2382fa9e4066Sahrens /* 2383fa9e4066Sahrens * fixup mode to map to xattr perms 2384fa9e4066Sahrens */ 2385fa9e4066Sahrens 2386fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2387fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2388fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2389fa9e4066Sahrens } 2390fa9e4066Sahrens 2391fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2392fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2393fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2394fa9e4066Sahrens } 2395fa9e4066Sahrens } 2396fa9e4066Sahrens 2397f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2398134a1f4eSCasper H.S. Dik /* 2399134a1f4eSCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC 2400134a1f4eSCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently 2401134a1f4eSCasper H.S. Dik * missing) in missing_bits. 2402134a1f4eSCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode), 2403134a1f4eSCasper H.S. Dik * needed_bits. 2404134a1f4eSCasper H.S. Dik */ 2405134a1f4eSCasper H.S. Dik needed_bits = 0; 2406134a1f4eSCasper H.S. Dik 2407134a1f4eSCasper H.S. Dik working_mode = mode; 2408134a1f4eSCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && 2409f1696b23SMark Shellenbaum owner == crgetuid(cr)) 2410134a1f4eSCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2411134a1f4eSCasper H.S. Dik 2412134a1f4eSCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 2413134a1f4eSCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2414134a1f4eSCasper H.S. Dik needed_bits |= VREAD; 2415134a1f4eSCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 2416134a1f4eSCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2417134a1f4eSCasper H.S. Dik needed_bits |= VWRITE; 2418134a1f4eSCasper H.S. Dik if (working_mode & ACE_EXECUTE) 2419134a1f4eSCasper H.S. Dik needed_bits |= VEXEC; 2420134a1f4eSCasper H.S. Dik 2421da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2422da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2423da6c28aaSamw if (is_attr) 2424da6c28aaSamw VN_RELE(ZTOV(xzp)); 2425f1696b23SMark Shellenbaum return (secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2426134a1f4eSCasper H.S. Dik needed_bits, needed_bits)); 2427da6c28aaSamw } 2428fa9e4066Sahrens 2429e0d35c44Smarks if (error && !check_privs) { 2430fa9e4066Sahrens if (is_attr) 2431fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2432fa9e4066Sahrens return (error); 2433fa9e4066Sahrens } 2434fa9e4066Sahrens 2435da6c28aaSamw if (error && (flags & V_APPEND)) { 2436da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2437fa9e4066Sahrens } 2438fa9e4066Sahrens 2439da6c28aaSamw if (error && check_privs) { 2440da6c28aaSamw mode_t checkmode = 0; 2441fa9e4066Sahrens 2442fa9e4066Sahrens /* 2443da6c28aaSamw * First check for implicit owner permission on 2444da6c28aaSamw * read_acl/read_attributes 2445fa9e4066Sahrens */ 2446fa9e4066Sahrens 2447da6c28aaSamw error = 0; 2448da6c28aaSamw ASSERT(working_mode != 0); 2449da6c28aaSamw 2450da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2451f1696b23SMark Shellenbaum owner == crgetuid(cr))) 2452da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2453da6c28aaSamw 2454da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 245547def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2456da6c28aaSamw checkmode |= VREAD; 2457da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 245847def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2459da6c28aaSamw checkmode |= VWRITE; 2460da6c28aaSamw if (working_mode & ACE_EXECUTE) 2461da6c28aaSamw checkmode |= VEXEC; 2462da6c28aaSamw 2463f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner, 2464134a1f4eSCasper H.S. Dik needed_bits & ~checkmode, needed_bits); 2465da6c28aaSamw 2466da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2467f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 2468da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2469f1696b23SMark Shellenbaum error = secpolicy_vnode_setdac(cr, owner); 2470da6c28aaSamw 2471da6c28aaSamw if (error == 0 && (working_mode & 2472da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2473da6c28aaSamw error = secpolicy_vnode_remove(cr); 2474da6c28aaSamw 247547def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2476f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 247747def0dcSMark Shellenbaum } 2478da6c28aaSamw if (error == 0) { 2479da6c28aaSamw /* 2480da6c28aaSamw * See if any bits other than those already checked 2481da6c28aaSamw * for are still present. If so then return EACCES 2482da6c28aaSamw */ 2483da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2484be6fd75aSMatthew Ahrens error = SET_ERROR(EACCES); 2485da6c28aaSamw } 2486da6c28aaSamw } 2487134a1f4eSCasper H.S. Dik } else if (error == 0) { 2488f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2489134a1f4eSCasper H.S. Dik needed_bits, needed_bits); 2490da6c28aaSamw } 2491da6c28aaSamw 2492134a1f4eSCasper H.S. Dik 2493da6c28aaSamw if (is_attr) 2494da6c28aaSamw VN_RELE(ZTOV(xzp)); 2495da6c28aaSamw 2496da6c28aaSamw return (error); 2497fa9e4066Sahrens } 2498fa9e4066Sahrens 2499fa9e4066Sahrens /* 2500da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2501fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2502fa9e4066Sahrens */ 2503fa9e4066Sahrens int 2504da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2505da6c28aaSamw { 2506da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2507da6c28aaSamw } 2508da6c28aaSamw 2509da6c28aaSamw /* 2510da6c28aaSamw * Access function for secpolicy_vnode_setattr 2511da6c28aaSamw */ 2512da6c28aaSamw int 2513da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2514fa9e4066Sahrens { 2515fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2516fa9e4066Sahrens 2517da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2518fa9e4066Sahrens } 2519fa9e4066Sahrens 252047db7e74Smarks static int 252123d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 2522134a1f4eSCasper H.S. Dik mode_t available_perms, cred_t *cr) 252347db7e74Smarks { 252447db7e74Smarks int error; 2525f1696b23SMark Shellenbaum uid_t downer; 2526f1696b23SMark Shellenbaum 2527f1696b23SMark Shellenbaum downer = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, ZFS_OWNER); 252847db7e74Smarks 2529134a1f4eSCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(dzp), 2530f1696b23SMark Shellenbaum downer, available_perms, VWRITE|VEXEC); 253147db7e74Smarks 253247db7e74Smarks if (error == 0) 253347db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 253447db7e74Smarks 253547db7e74Smarks return (error); 253647db7e74Smarks } 253747db7e74Smarks 2538fa9e4066Sahrens /* 2539fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2540fa9e4066Sahrens * consulting least priv subsystem. 2541fa9e4066Sahrens * 2542fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2543fa9e4066Sahrens * ability to delete an object. 2544fa9e4066Sahrens * 2545fa9e4066Sahrens * ------------------------------------------------------- 2546fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2547fa9e4066Sahrens * | permissions | | 2548fa9e4066Sahrens * ------------------------------------------------------- 2549fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2550fa9e4066Sahrens * | | Delete | Delete | unspecified| 2551fa9e4066Sahrens * ------------------------------------------------------- 2552fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2553fa9e4066Sahrens * | DELETE_CHILD | | 2554fa9e4066Sahrens * ------------------------------------------------------- 2555fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2556fa9e4066Sahrens * | DELETE_CHILD | | | | 2557fa9e4066Sahrens * ------------------------------------------------------- 2558fa9e4066Sahrens * | ACL specifies | | | | 2559fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2560fa9e4066Sahrens * | write and | | | | 2561fa9e4066Sahrens * | execute | | | | 2562fa9e4066Sahrens * ------------------------------------------------------- 2563fa9e4066Sahrens * | ACL denies | | | | 2564fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2565fa9e4066Sahrens * | execute | | | | 2566fa9e4066Sahrens * ------------------------------------------------------- 2567fa9e4066Sahrens * ^ 2568fa9e4066Sahrens * | 2569fa9e4066Sahrens * No search privilege, can't even look up file? 2570fa9e4066Sahrens * 2571fa9e4066Sahrens */ 2572fa9e4066Sahrens int 2573fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2574fa9e4066Sahrens { 2575da6c28aaSamw uint32_t dzp_working_mode = 0; 2576da6c28aaSamw uint32_t zp_working_mode = 0; 2577fa9e4066Sahrens int dzp_error, zp_error; 2578134a1f4eSCasper H.S. Dik mode_t available_perms; 2579da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2580da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2581fa9e4066Sahrens 2582fa9e4066Sahrens /* 258323d5bb1fSmarks * We want specific DELETE permissions to 2584fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2585fa9e4066Sahrens * want an ACL such as this to mess us up. 258647db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2587fa9e4066Sahrens * 2588fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2589fa9e4066Sahrens * by secpolicy_vnode_access(). 259023d5bb1fSmarks * 259123d5bb1fSmarks * We will ask for all of the necessary permissions and then 259223d5bb1fSmarks * look at the working modes from the directory and target object 259323d5bb1fSmarks * to determine what was found. 2594fa9e4066Sahrens */ 2595fa9e4066Sahrens 25960a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2597be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2598fa9e4066Sahrens 259923d5bb1fSmarks /* 26007ed7e920Smarks * First row 260123d5bb1fSmarks * If the directory permissions allow the delete, we are done. 260223d5bb1fSmarks */ 26037ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 260423d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 260523d5bb1fSmarks return (0); 2606da6c28aaSamw 260723d5bb1fSmarks /* 260823d5bb1fSmarks * If target object has delete permission then we are done 260923d5bb1fSmarks */ 261023d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 261123d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 261223d5bb1fSmarks return (0); 261323d5bb1fSmarks 26147ed7e920Smarks ASSERT(dzp_error && zp_error); 26157ed7e920Smarks 261623d5bb1fSmarks if (!dzpcheck_privs) 2617fa9e4066Sahrens return (dzp_error); 26187ed7e920Smarks if (!zpcheck_privs) 261923d5bb1fSmarks return (zp_error); 2620fa9e4066Sahrens 2621fa9e4066Sahrens /* 2622fa9e4066Sahrens * Second row 26237ed7e920Smarks * 26247ed7e920Smarks * If directory returns EACCES then delete_child was denied 26257ed7e920Smarks * due to deny delete_child. In this case send the request through 26267ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 26277ed7e920Smarks * since that *could* allow the delete based on write/execute permission 26287ed7e920Smarks * and we want delete permissions to override write/execute. 2629fa9e4066Sahrens */ 2630fa9e4066Sahrens 263147db7e74Smarks if (dzp_error == EACCES) 26327ed7e920Smarks return (secpolicy_vnode_remove(cr)); 263347db7e74Smarks 263447db7e74Smarks /* 2635fa9e4066Sahrens * Third Row 263623d5bb1fSmarks * only need to see if we have write/execute on directory. 2637fa9e4066Sahrens */ 2638fa9e4066Sahrens 2639134a1f4eSCasper H.S. Dik dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 2640134a1f4eSCasper H.S. Dik &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); 2641fa9e4066Sahrens 2642134a1f4eSCasper H.S. Dik if (dzp_error != 0 && !dzpcheck_privs) 26437ed7e920Smarks return (dzp_error); 26447ed7e920Smarks 2645fa9e4066Sahrens /* 26467ed7e920Smarks * Fourth row 2647fa9e4066Sahrens */ 2648fa9e4066Sahrens 2649134a1f4eSCasper H.S. Dik available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE; 2650134a1f4eSCasper H.S. Dik available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC; 26517ed7e920Smarks 2652134a1f4eSCasper H.S. Dik return (zfs_delete_final_check(zp, dzp, available_perms, cr)); 26537ed7e920Smarks 2654fa9e4066Sahrens } 2655fa9e4066Sahrens 2656fa9e4066Sahrens int 2657fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2658fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2659fa9e4066Sahrens { 2660fa9e4066Sahrens int add_perm; 2661fa9e4066Sahrens int error; 2662fa9e4066Sahrens 26630a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED) 2664be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2665da6c28aaSamw 2666fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2667fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2668fa9e4066Sahrens 2669fa9e4066Sahrens /* 2670fa9e4066Sahrens * Rename permissions are combination of delete permission + 2671fa9e4066Sahrens * add file/subdir permission. 2672fa9e4066Sahrens */ 2673fa9e4066Sahrens 2674fa9e4066Sahrens /* 2675fa9e4066Sahrens * first make sure we do the delete portion. 2676fa9e4066Sahrens * 2677fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2678fa9e4066Sahrens */ 2679fa9e4066Sahrens 2680fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2681fa9e4066Sahrens return (error); 2682fa9e4066Sahrens 2683fa9e4066Sahrens /* 2684fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2685fa9e4066Sahrens */ 2686fa9e4066Sahrens if (tzp) { 2687fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2688fa9e4066Sahrens return (error); 2689fa9e4066Sahrens } 2690fa9e4066Sahrens 2691fa9e4066Sahrens /* 2692fa9e4066Sahrens * Now check for add permissions 2693fa9e4066Sahrens */ 2694da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2695fa9e4066Sahrens 2696fa9e4066Sahrens return (error); 2697fa9e4066Sahrens } 2698