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. 23be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved. 242889ec41SGordon Ross * Copyright 2017 Nexenta Systems, Inc. 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 */ 8910a586ceaSMark Shellenbaum uint64_t 89227dd1e87SMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp, 89327dd1e87SMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid) 894fa9e4066Sahrens { 895fa9e4066Sahrens int entry_type; 896da6c28aaSamw mode_t mode; 897fa9e4066Sahrens mode_t seen = 0; 898da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 899da6c28aaSamw uint64_t who; 900da6c28aaSamw uint16_t iflags, type; 901da6c28aaSamw uint32_t access_mask; 902d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 903fa9e4066Sahrens 9040a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 905da6c28aaSamw 906da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 907da6c28aaSamw &access_mask, &iflags, &type)) { 90829a0b737Smarks 909003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 910003c2582SMark Shellenbaum continue; 911003c2582SMark Shellenbaum 912e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 913e6032be1Smarks 9141ab99678SMark Shellenbaum /* 915de0f1ddbSAlbert Lee * Skip over any inherit_only ACEs 9161ab99678SMark Shellenbaum */ 917de0f1ddbSAlbert Lee if (iflags & ACE_INHERIT_ONLY_ACE) 9181ab99678SMark Shellenbaum continue; 9191ab99678SMark Shellenbaum 92027dd1e87SMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 && 92127dd1e87SMark Shellenbaum who == fuid)) { 922da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 923fa9e4066Sahrens (!(seen & S_IRUSR))) { 924fa9e4066Sahrens seen |= S_IRUSR; 925da6c28aaSamw if (type == ALLOW) { 926fa9e4066Sahrens mode |= S_IRUSR; 927fa9e4066Sahrens } 928fa9e4066Sahrens } 929da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 930fa9e4066Sahrens (!(seen & S_IWUSR))) { 931fa9e4066Sahrens seen |= S_IWUSR; 932da6c28aaSamw if (type == ALLOW) { 933fa9e4066Sahrens mode |= S_IWUSR; 934fa9e4066Sahrens } 935fa9e4066Sahrens } 936da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 937fa9e4066Sahrens (!(seen & S_IXUSR))) { 938fa9e4066Sahrens seen |= S_IXUSR; 939da6c28aaSamw if (type == ALLOW) { 940fa9e4066Sahrens mode |= S_IXUSR; 941fa9e4066Sahrens } 942fa9e4066Sahrens } 94327dd1e87SMark Shellenbaum } else if (entry_type == OWNING_GROUP || 94427dd1e87SMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) { 945da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 946fa9e4066Sahrens (!(seen & S_IRGRP))) { 947fa9e4066Sahrens seen |= S_IRGRP; 948da6c28aaSamw if (type == ALLOW) { 949fa9e4066Sahrens mode |= S_IRGRP; 950fa9e4066Sahrens } 951fa9e4066Sahrens } 952da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 953fa9e4066Sahrens (!(seen & S_IWGRP))) { 954fa9e4066Sahrens seen |= S_IWGRP; 955da6c28aaSamw if (type == ALLOW) { 956fa9e4066Sahrens mode |= S_IWGRP; 957fa9e4066Sahrens } 958fa9e4066Sahrens } 959da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 960fa9e4066Sahrens (!(seen & S_IXGRP))) { 961fa9e4066Sahrens seen |= S_IXGRP; 962da6c28aaSamw if (type == ALLOW) { 963fa9e4066Sahrens mode |= S_IXGRP; 964fa9e4066Sahrens } 965fa9e4066Sahrens } 966fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 967da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 968fa9e4066Sahrens if (!(seen & S_IRUSR)) { 969fa9e4066Sahrens seen |= S_IRUSR; 970da6c28aaSamw if (type == ALLOW) { 971fa9e4066Sahrens mode |= S_IRUSR; 972fa9e4066Sahrens } 973fa9e4066Sahrens } 974fa9e4066Sahrens if (!(seen & S_IRGRP)) { 975fa9e4066Sahrens seen |= S_IRGRP; 976da6c28aaSamw if (type == ALLOW) { 977fa9e4066Sahrens mode |= S_IRGRP; 978fa9e4066Sahrens } 979fa9e4066Sahrens } 980fa9e4066Sahrens if (!(seen & S_IROTH)) { 981fa9e4066Sahrens seen |= S_IROTH; 982da6c28aaSamw if (type == ALLOW) { 983fa9e4066Sahrens mode |= S_IROTH; 984fa9e4066Sahrens } 985fa9e4066Sahrens } 986fa9e4066Sahrens } 987da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 988fa9e4066Sahrens if (!(seen & S_IWUSR)) { 989fa9e4066Sahrens seen |= S_IWUSR; 990da6c28aaSamw if (type == ALLOW) { 991fa9e4066Sahrens mode |= S_IWUSR; 992fa9e4066Sahrens } 993fa9e4066Sahrens } 994fa9e4066Sahrens if (!(seen & S_IWGRP)) { 995fa9e4066Sahrens seen |= S_IWGRP; 996da6c28aaSamw if (type == ALLOW) { 997fa9e4066Sahrens mode |= S_IWGRP; 998fa9e4066Sahrens } 999fa9e4066Sahrens } 1000fa9e4066Sahrens if (!(seen & S_IWOTH)) { 1001fa9e4066Sahrens seen |= S_IWOTH; 1002da6c28aaSamw if (type == ALLOW) { 1003fa9e4066Sahrens mode |= S_IWOTH; 1004fa9e4066Sahrens } 1005fa9e4066Sahrens } 1006fa9e4066Sahrens } 1007da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 1008fa9e4066Sahrens if (!(seen & S_IXUSR)) { 1009fa9e4066Sahrens seen |= S_IXUSR; 1010da6c28aaSamw if (type == ALLOW) { 1011fa9e4066Sahrens mode |= S_IXUSR; 1012fa9e4066Sahrens } 1013fa9e4066Sahrens } 1014fa9e4066Sahrens if (!(seen & S_IXGRP)) { 1015fa9e4066Sahrens seen |= S_IXGRP; 1016da6c28aaSamw if (type == ALLOW) { 1017fa9e4066Sahrens mode |= S_IXGRP; 1018fa9e4066Sahrens } 1019fa9e4066Sahrens } 1020fa9e4066Sahrens if (!(seen & S_IXOTH)) { 1021fa9e4066Sahrens seen |= S_IXOTH; 1022da6c28aaSamw if (type == ALLOW) { 1023fa9e4066Sahrens mode |= S_IXOTH; 1024fa9e4066Sahrens } 1025fa9e4066Sahrens } 1026fa9e4066Sahrens } 1027d47621a4STim Haley } else { 1028d47621a4STim Haley /* 1029d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 1030d47621a4STim Haley * USER ACE denies execute access to someone, 1031d47621a4STim Haley * mode is not affected 1032d47621a4STim Haley */ 1033d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 1034d47621a4STim Haley an_exec_denied = B_TRUE; 1035fa9e4066Sahrens } 1036fa9e4066Sahrens } 1037d47621a4STim Haley 10384929fd5eSTim Haley /* 10394929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 10404929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 10414929fd5eSTim Haley * weren't allowed it. 10424929fd5eSTim Haley */ 10434929fd5eSTim Haley if (!an_exec_denied && 10444929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 10454929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 1046d47621a4STim Haley an_exec_denied = B_TRUE; 1047d47621a4STim Haley 1048d47621a4STim Haley if (an_exec_denied) 10490a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED; 1050d47621a4STim Haley else 10510a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED; 1052d47621a4STim Haley 1053fa9e4066Sahrens return (mode); 1054fa9e4066Sahrens } 1055fa9e4066Sahrens 1056fa9e4066Sahrens /* 10574929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 10584929fd5eSTim Haley * create a new acl and leave any cached acl in place. 1059fa9e4066Sahrens */ 1060ea8dc4b6Seschrock static int 10611412a1a2SMark Shellenbaum zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp, 10621412a1a2SMark Shellenbaum boolean_t will_modify) 1063fa9e4066Sahrens { 1064fa9e4066Sahrens zfs_acl_t *aclp; 10650a586ceaSMark Shellenbaum int aclsize; 10660a586ceaSMark Shellenbaum int acl_count; 1067da6c28aaSamw zfs_acl_node_t *aclnode; 10680a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl; 10690a586ceaSMark Shellenbaum int version; 1070ea8dc4b6Seschrock int error; 10711412a1a2SMark Shellenbaum boolean_t drop_lock = B_FALSE; 1072fa9e4066Sahrens 1073fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 1074fa9e4066Sahrens 10754929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 1076d47621a4STim Haley *aclpp = zp->z_acl_cached; 1077d47621a4STim Haley return (0); 1078d47621a4STim Haley } 1079d47621a4STim Haley 10801412a1a2SMark Shellenbaum /* 10811412a1a2SMark Shellenbaum * close race where znode could be upgrade while trying to 10821412a1a2SMark Shellenbaum * read the znode attributes. 10831412a1a2SMark Shellenbaum * 10841412a1a2SMark Shellenbaum * But this could only happen if the file isn't already an SA 10851412a1a2SMark Shellenbaum * znode 10861412a1a2SMark Shellenbaum */ 10871412a1a2SMark Shellenbaum if (!zp->z_is_sa && !have_lock) { 10881412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 10891412a1a2SMark Shellenbaum drop_lock = B_TRUE; 10901412a1a2SMark Shellenbaum } 10911412a1a2SMark Shellenbaum version = zfs_znode_acl_version(zp); 1092fa9e4066Sahrens 10930a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize, 10941412a1a2SMark Shellenbaum &acl_count, &znode_acl)) != 0) { 10951412a1a2SMark Shellenbaum goto done; 10961412a1a2SMark Shellenbaum } 1097fa9e4066Sahrens 10980a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version); 10990a586ceaSMark Shellenbaum 1100da6c28aaSamw aclp->z_acl_count = acl_count; 1101da6c28aaSamw aclp->z_acl_bytes = aclsize; 1102da6c28aaSamw 11030a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize); 11040a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count; 11050a586ceaSMark Shellenbaum aclnode->z_size = aclsize; 11060a586ceaSMark Shellenbaum 11070a586ceaSMark Shellenbaum if (!zp->z_is_sa) { 11080a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) { 11090a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os, 11100a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size, 11110a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH); 11120a586ceaSMark Shellenbaum } else { 11130a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata, 11140a586ceaSMark Shellenbaum aclnode->z_size); 11150a586ceaSMark Shellenbaum } 11160a586ceaSMark Shellenbaum } else { 11170a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs), 11180a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size); 11190a586ceaSMark Shellenbaum } 11200a586ceaSMark Shellenbaum 1121ea8dc4b6Seschrock if (error != 0) { 1122ea8dc4b6Seschrock zfs_acl_free(aclp); 11230a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode); 1124b87f3af3Sperrin /* convert checksum errors into IO errors */ 1125b87f3af3Sperrin if (error == ECKSUM) 1126be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 11271412a1a2SMark Shellenbaum goto done; 1128ea8dc4b6Seschrock } 1129fa9e4066Sahrens 11300a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode); 11310a586ceaSMark Shellenbaum 11324929fd5eSTim Haley *aclpp = aclp; 11334929fd5eSTim Haley if (!will_modify) 11344929fd5eSTim Haley zp->z_acl_cached = aclp; 11351412a1a2SMark Shellenbaum done: 11361412a1a2SMark Shellenbaum if (drop_lock) 11371412a1a2SMark Shellenbaum mutex_exit(&zp->z_lock); 11381412a1a2SMark Shellenbaum return (error); 1139fa9e4066Sahrens } 1140fa9e4066Sahrens 11410a586ceaSMark Shellenbaum /*ARGSUSED*/ 11420a586ceaSMark Shellenbaum void 11430a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, 11440a586ceaSMark Shellenbaum boolean_t start, void *userdata) 11450a586ceaSMark Shellenbaum { 11460a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata; 11470a586ceaSMark Shellenbaum 11480a586ceaSMark Shellenbaum if (start) { 11490a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl); 11500a586ceaSMark Shellenbaum } else { 11510a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, 11520a586ceaSMark Shellenbaum cb->cb_acl_node); 11530a586ceaSMark Shellenbaum } 11540a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata; 11550a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size; 11560a586ceaSMark Shellenbaum } 11570a586ceaSMark Shellenbaum 115827dd1e87SMark Shellenbaum int 115927dd1e87SMark Shellenbaum zfs_acl_chown_setattr(znode_t *zp) 116027dd1e87SMark Shellenbaum { 116127dd1e87SMark Shellenbaum int error; 116227dd1e87SMark Shellenbaum zfs_acl_t *aclp; 116327dd1e87SMark Shellenbaum 11641412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_lock)); 11651412a1a2SMark Shellenbaum ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 116627dd1e87SMark Shellenbaum 11671412a1a2SMark Shellenbaum if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0) 116827dd1e87SMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp, 1169f1696b23SMark Shellenbaum &zp->z_pflags, zp->z_uid, zp->z_gid); 117027dd1e87SMark Shellenbaum return (error); 117127dd1e87SMark Shellenbaum } 117227dd1e87SMark Shellenbaum 1173fa9e4066Sahrens /* 1174da6c28aaSamw * common code for setting ACLs. 1175fa9e4066Sahrens * 1176fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1177fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1178fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1179fa9e4066Sahrens */ 1180fa9e4066Sahrens int 118189459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1182fa9e4066Sahrens { 1183fa9e4066Sahrens int error; 1184fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1185da6c28aaSamw dmu_object_type_t otype; 11860a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 }; 11870a586ceaSMark Shellenbaum uint64_t mode; 11880a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5]; 11890a586ceaSMark Shellenbaum uint64_t ctime[2]; 11900a586ceaSMark Shellenbaum int count = 0; 119182693e09SWHR zfs_acl_phys_t acl_phys; 1192fa9e4066Sahrens 11930a586ceaSMark Shellenbaum mode = zp->z_mode; 119427dd1e87SMark Shellenbaum 1195f1696b23SMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, 1196f1696b23SMark Shellenbaum zp->z_uid, zp->z_gid); 11970a586ceaSMark Shellenbaum 11980a586ceaSMark Shellenbaum zp->z_mode = mode; 11990a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, 12000a586ceaSMark Shellenbaum &mode, sizeof (mode)); 12010a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, 12020a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags)); 12030a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, 12040a586ceaSMark Shellenbaum &ctime, sizeof (ctime)); 1205fa9e4066Sahrens 12064929fd5eSTim Haley if (zp->z_acl_cached) { 1207d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1208d47621a4STim Haley zp->z_acl_cached = NULL; 1209d47621a4STim Haley } 1210d47621a4STim Haley 1211fa9e4066Sahrens /* 12120a586ceaSMark Shellenbaum * Upgrade needed? 1213fa9e4066Sahrens */ 1214da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1215da6c28aaSamw otype = DMU_OT_OLDACL; 1216da6c28aaSamw } else { 1217da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1218da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 121989459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1220da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1221da6c28aaSamw otype = DMU_OT_ACL; 1222da6c28aaSamw } 1223da6c28aaSamw 12240a586ceaSMark Shellenbaum /* 12250a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format 12260a586ceaSMark Shellenbaum * as well as newer (preferred) SA format. 12270a586ceaSMark Shellenbaum */ 12280a586ceaSMark Shellenbaum 12290a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */ 12300a586ceaSMark Shellenbaum locate.cb_aclp = aclp; 12310a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs), 12320a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes); 12330a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), 12340a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t)); 12350a586ceaSMark Shellenbaum } else { /* Painful legacy way */ 12360a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode; 12370a586ceaSMark Shellenbaum uint64_t off = 0; 12380a586ceaSMark Shellenbaum uint64_t aoid; 12390a586ceaSMark Shellenbaum 12400a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 12410a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0) 12420a586ceaSMark Shellenbaum return (error); 12430a586ceaSMark Shellenbaum 12440a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj; 12450a586ceaSMark Shellenbaum 1246da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1247da6c28aaSamw /* 1248da6c28aaSamw * If ACL was previously external and we are now 1249da6c28aaSamw * converting to new ACL format then release old 1250da6c28aaSamw * ACL object and create a new one. 1251da6c28aaSamw */ 12520a586ceaSMark Shellenbaum if (aoid && 12530a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) { 12540a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx); 1255da6c28aaSamw if (error) 1256da6c28aaSamw return (error); 1257da6c28aaSamw aoid = 0; 1258da6c28aaSamw } 1259fa9e4066Sahrens if (aoid == 0) { 1260fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1261da6c28aaSamw otype, aclp->z_acl_bytes, 12620a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12630a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE, 12640a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 12650a586ceaSMark Shellenbaum DN_MAX_BONUSLEN : 0, tx); 1266fa9e4066Sahrens } else { 12670a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os, 12680a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx); 1269fa9e4066Sahrens } 12700a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid; 1271da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1272da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1273da6c28aaSamw if (aclnode->z_ace_count == 0) 1274da6c28aaSamw continue; 1275da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1276da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1277da6c28aaSamw off += aclnode->z_size; 1278da6c28aaSamw } 1279fa9e4066Sahrens } else { 12800a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data; 1281fa9e4066Sahrens /* 1282fa9e4066Sahrens * Migrating back embedded? 1283fa9e4066Sahrens */ 12840a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) { 1285fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 12860a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx); 1287fa9e4066Sahrens if (error) 1288fa9e4066Sahrens return (error); 12890a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0; 1290fa9e4066Sahrens } 1291da6c28aaSamw 1292da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1293da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1294da6c28aaSamw if (aclnode->z_ace_count == 0) 1295da6c28aaSamw continue; 12960a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start, 12970a586ceaSMark Shellenbaum aclnode->z_size); 1298da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1299da6c28aaSamw } 1300fa9e4066Sahrens } 1301da6c28aaSamw /* 1302da6c28aaSamw * If Old version then swap count/bytes to match old 1303da6c28aaSamw * layout of znode_acl_phys_t. 1304da6c28aaSamw */ 1305da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 13060a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count; 13070a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes; 1308da6c28aaSamw } else { 13090a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes; 13100a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count; 1311da6c28aaSamw } 13120a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version; 1313da6c28aaSamw 13140a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL, 13150a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys)); 13160a586ceaSMark Shellenbaum } 1317da6c28aaSamw 1318da6c28aaSamw /* 1319da6c28aaSamw * Replace ACL wide bits, but first clear them. 1320da6c28aaSamw */ 13210a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS; 1322da6c28aaSamw 13230a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints; 1324da6c28aaSamw 1325da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 13260a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL; 1327fa9e4066Sahrens 13280a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE); 13290a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); 1330fa9e4066Sahrens } 1331fa9e4066Sahrens 1332fa9e4066Sahrens static void 1333de0f1ddbSAlbert Lee zfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t split, boolean_t trim, 1334de0f1ddbSAlbert Lee zfs_acl_t *aclp) 1335fa9e4066Sahrens { 133627dd1e87SMark Shellenbaum void *acep = NULL; 1337da6c28aaSamw uint64_t who; 133827dd1e87SMark Shellenbaum int new_count, new_bytes; 133927dd1e87SMark Shellenbaum int ace_size; 1340fa9e4066Sahrens int entry_type; 1341da6c28aaSamw uint16_t iflags, type; 1342da6c28aaSamw uint32_t access_mask; 134327dd1e87SMark Shellenbaum zfs_acl_node_t *newnode; 134427dd1e87SMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size(); 134527dd1e87SMark Shellenbaum void *zacep; 1346a3c49ce1SAlbert Lee boolean_t isdir; 1347a3c49ce1SAlbert Lee trivial_acl_t masks; 1348fa9e4066Sahrens 134927dd1e87SMark Shellenbaum new_count = new_bytes = 0; 135027dd1e87SMark Shellenbaum 1351a3c49ce1SAlbert Lee isdir = (vtype == VDIR); 1352a3c49ce1SAlbert Lee 1353a3c49ce1SAlbert Lee acl_trivial_access_masks((mode_t)mode, isdir, &masks); 135427dd1e87SMark Shellenbaum 135527dd1e87SMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes); 135627dd1e87SMark Shellenbaum 135727dd1e87SMark Shellenbaum zacep = newnode->z_acldata; 1358a3c49ce1SAlbert Lee if (masks.allow0) { 1359a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER); 136027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136127dd1e87SMark Shellenbaum new_count++; 136227dd1e87SMark Shellenbaum new_bytes += abstract_size; 1363f7170741SWill Andrews } 1364f7170741SWill Andrews if (masks.deny1) { 1365a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER); 136627dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 136727dd1e87SMark Shellenbaum new_count++; 136827dd1e87SMark Shellenbaum new_bytes += abstract_size; 136927dd1e87SMark Shellenbaum } 1370a3c49ce1SAlbert Lee if (masks.deny2) { 1371a3c49ce1SAlbert Lee zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP); 137227dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 137327dd1e87SMark Shellenbaum new_count++; 137427dd1e87SMark Shellenbaum new_bytes += abstract_size; 137527dd1e87SMark Shellenbaum } 13762459a9eaSmarks 1377da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1378da6c28aaSamw &iflags, &type)) { 1379da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 1380de0f1ddbSAlbert Lee /* 1381de0f1ddbSAlbert Lee * ACEs used to represent the file mode may be divided 1382de0f1ddbSAlbert Lee * into an equivalent pair of inherit-only and regular 1383de0f1ddbSAlbert Lee * ACEs, if they are inheritable. 1384de0f1ddbSAlbert Lee * Skip regular ACEs, which are replaced by the new mode. 1385de0f1ddbSAlbert Lee */ 1386de0f1ddbSAlbert Lee if (split && (entry_type == ACE_OWNER || 1387de0f1ddbSAlbert Lee entry_type == OWNING_GROUP || 1388de0f1ddbSAlbert Lee entry_type == ACE_EVERYONE)) { 1389de0f1ddbSAlbert Lee if (!isdir || !(iflags & 1390de0f1ddbSAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 139127dd1e87SMark Shellenbaum continue; 1392de0f1ddbSAlbert Lee /* 1393de0f1ddbSAlbert Lee * We preserve owner@, group@, or @everyone 1394de0f1ddbSAlbert Lee * permissions, if they are inheritable, by 1395de0f1ddbSAlbert Lee * copying them to inherit_only ACEs. This 1396de0f1ddbSAlbert Lee * prevents inheritable permissions from being 1397de0f1ddbSAlbert Lee * altered along with the file mode. 1398de0f1ddbSAlbert Lee */ 1399de0f1ddbSAlbert Lee iflags |= ACE_INHERIT_ONLY_ACE; 140027dd1e87SMark Shellenbaum } 1401da6c28aaSamw 1402a3c49ce1SAlbert Lee /* 1403a3c49ce1SAlbert Lee * If this ACL has any inheritable ACEs, mark that in 1404a3c49ce1SAlbert Lee * the hints (which are later masked into the pflags) 1405a3c49ce1SAlbert Lee * so create knows to do inheritance. 1406a3c49ce1SAlbert Lee */ 1407de0f1ddbSAlbert Lee if (isdir && (iflags & 1408a3c49ce1SAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 1409a3c49ce1SAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE; 1410a3c49ce1SAlbert Lee 1411da6c28aaSamw if ((type != ALLOW && type != DENY) || 1412de0f1ddbSAlbert Lee (iflags & ACE_INHERIT_ONLY_ACE)) { 1413da6c28aaSamw switch (type) { 1414da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1415da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1416da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1417da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1418da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1419da6c28aaSamw break; 1420fa9e4066Sahrens } 1421fa9e4066Sahrens } else { 1422fa9e4066Sahrens /* 1423851632d6SAlbert Lee * Limit permissions granted by ACEs to be no greater 1424851632d6SAlbert Lee * than permissions of the requested group mode. 1425851632d6SAlbert Lee * Applies when the "aclmode" property is set to 1426851632d6SAlbert Lee * "groupmask". 1427fa9e4066Sahrens */ 1428a3c49ce1SAlbert Lee if ((type == ALLOW) && trim) 1429a3c49ce1SAlbert Lee access_mask &= masks.group; 1430fa9e4066Sahrens } 143127dd1e87SMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags); 143227dd1e87SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 143327dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size); 143427dd1e87SMark Shellenbaum new_count++; 143527dd1e87SMark Shellenbaum new_bytes += ace_size; 1436fa9e4066Sahrens } 1437de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.owner, ALLOW, -1, ACE_OWNER); 143827dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1439de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.group, ALLOW, -1, OWNING_GROUP); 144027dd1e87SMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size); 1441de0f1ddbSAlbert Lee zfs_set_ace(aclp, zacep, masks.everyone, ALLOW, -1, ACE_EVERYONE); 1442fa9e4066Sahrens 144327dd1e87SMark Shellenbaum new_count += 3; 144427dd1e87SMark Shellenbaum new_bytes += abstract_size * 3; 144527dd1e87SMark Shellenbaum zfs_acl_release_nodes(aclp); 144627dd1e87SMark Shellenbaum aclp->z_acl_count = new_count; 144727dd1e87SMark Shellenbaum aclp->z_acl_bytes = new_bytes; 144827dd1e87SMark Shellenbaum newnode->z_ace_count = new_count; 144927dd1e87SMark Shellenbaum newnode->z_size = new_bytes; 145027dd1e87SMark Shellenbaum list_insert_tail(&aclp->z_acl, newnode); 1451fa9e4066Sahrens } 1452fa9e4066Sahrens 1453a3c49ce1SAlbert Lee int 14544c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1455fa9e4066Sahrens { 1456a3c49ce1SAlbert Lee int error = 0; 1457a3c49ce1SAlbert Lee 1458fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 14591412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1460a3c49ce1SAlbert Lee if (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 146127dd1e87SMark Shellenbaum *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp)); 1462a3c49ce1SAlbert Lee else 1463a3c49ce1SAlbert Lee error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE); 1464a3c49ce1SAlbert Lee 1465a3c49ce1SAlbert Lee if (error == 0) { 14660a586ceaSMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; 1467de0f1ddbSAlbert Lee zfs_acl_chmod(ZTOV(zp)->v_type, mode, B_TRUE, 1468a3c49ce1SAlbert Lee (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp); 1469a3c49ce1SAlbert Lee } 14704c841f60Smarks mutex_exit(&zp->z_lock); 14711412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 1472a3c49ce1SAlbert Lee 1473a3c49ce1SAlbert Lee return (error); 1474fa9e4066Sahrens } 1475fa9e4066Sahrens 1476fa9e4066Sahrens /* 1477da6c28aaSamw * Should ACE be inherited? 1478da6c28aaSamw */ 1479da6c28aaSamw static int 148089459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1481da6c28aaSamw { 1482da6c28aaSamw int iflags = (acep_flags & 0xf); 1483da6c28aaSamw 1484da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1485da6c28aaSamw return (1); 1486da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1487da6c28aaSamw return (!((vtype == VDIR) && 1488da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1489da6c28aaSamw return (0); 1490fa9e4066Sahrens } 1491fa9e4066Sahrens 1492fa9e4066Sahrens /* 1493fa9e4066Sahrens * inherit inheritable ACEs from parent 1494fa9e4066Sahrens */ 1495fa9e4066Sahrens static zfs_acl_t * 149689459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 1497e9bacc6dSDominik Hassler uint64_t mode, boolean_t *need_chmod) 1498fa9e4066Sahrens { 1499de0f1ddbSAlbert Lee void *pacep = NULL; 150027dd1e87SMark Shellenbaum void *acep; 150127dd1e87SMark Shellenbaum zfs_acl_node_t *aclnode; 1502fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1503da6c28aaSamw uint64_t who; 1504da6c28aaSamw uint32_t access_mask; 1505da6c28aaSamw uint16_t iflags, newflags, type; 1506da6c28aaSamw size_t ace_size; 1507da6c28aaSamw void *data1, *data2; 1508da6c28aaSamw size_t data1sz, data2sz; 1509de0f1ddbSAlbert Lee uint_t aclinherit; 1510de0f1ddbSAlbert Lee boolean_t isdir = (vtype == VDIR); 1511e9bacc6dSDominik Hassler boolean_t isreg = (vtype == VREG); 1512e9bacc6dSDominik Hassler 1513e9bacc6dSDominik Hassler *need_chmod = B_TRUE; 1514d0f3f37eSMark Shellenbaum 1515003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 1516de0f1ddbSAlbert Lee aclinherit = zfsvfs->z_acl_inherit; 1517de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_DISCARD || vtype == VLNK) 1518d0f3f37eSMark Shellenbaum return (aclp); 1519de0f1ddbSAlbert Lee 1520da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1521da6c28aaSamw &access_mask, &iflags, &type)) { 1522fa9e4066Sahrens 1523003c2582SMark Shellenbaum /* 1524003c2582SMark Shellenbaum * don't inherit bogus ACEs 1525003c2582SMark Shellenbaum */ 1526003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1527003c2582SMark Shellenbaum continue; 1528003c2582SMark Shellenbaum 1529de0f1ddbSAlbert Lee /* 1530de0f1ddbSAlbert Lee * Check if ACE is inheritable by this vnode 1531de0f1ddbSAlbert Lee */ 1532de0f1ddbSAlbert Lee if ((aclinherit == ZFS_ACL_NOALLOW && type == ALLOW) || 1533de0f1ddbSAlbert Lee !zfs_ace_can_use(vtype, iflags)) 1534b3d141f8Smarks continue; 1535fa9e4066Sahrens 1536b3d141f8Smarks /* 1537e9bacc6dSDominik Hassler * If owner@, group@, or everyone@ inheritable 1538e9bacc6dSDominik Hassler * then zfs_acl_chmod() isn't needed. 1539e9bacc6dSDominik Hassler */ 1540e9bacc6dSDominik Hassler if ((aclinherit == ZFS_ACL_PASSTHROUGH || 1541e9bacc6dSDominik Hassler aclinherit == ZFS_ACL_PASSTHROUGH_X) && 1542e9bacc6dSDominik Hassler ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1543e9bacc6dSDominik Hassler ((iflags & OWNING_GROUP) == OWNING_GROUP)) && 1544e9bacc6dSDominik Hassler (isreg || (isdir && (iflags & ACE_DIRECTORY_INHERIT_ACE)))) 1545e9bacc6dSDominik Hassler *need_chmod = B_FALSE; 1546e9bacc6dSDominik Hassler 1547e9bacc6dSDominik Hassler /* 1548de0f1ddbSAlbert Lee * Strip inherited execute permission from file if 1549de0f1ddbSAlbert Lee * not in mode 1550b3d141f8Smarks */ 1551de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_PASSTHROUGH_X && type == ALLOW && 1552de0f1ddbSAlbert Lee !isdir && ((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) { 1553d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1554d0f3f37eSMark Shellenbaum } 1555d0f3f37eSMark Shellenbaum 1556de0f1ddbSAlbert Lee /* 1557de0f1ddbSAlbert Lee * Strip write_acl and write_owner from permissions 1558de0f1ddbSAlbert Lee * when inheriting an ACE 1559de0f1ddbSAlbert Lee */ 1560de0f1ddbSAlbert Lee if (aclinherit == ZFS_ACL_RESTRICTED && type == ALLOW) { 1561de0f1ddbSAlbert Lee access_mask &= ~RESTRICTED_CLEAR; 1562de0f1ddbSAlbert Lee } 1563de0f1ddbSAlbert Lee 1564de0f1ddbSAlbert Lee ace_size = aclp->z_ops.ace_size(pacep); 1565b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1566da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1567da6c28aaSamw acep = aclnode->z_acldata; 1568d0f3f37eSMark Shellenbaum 1569da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1570da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1571169cdae2Smarks 1572fa9e4066Sahrens /* 1573da6c28aaSamw * Copy special opaque data if any 1574fa9e4066Sahrens */ 1575d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1576b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1577da6c28aaSamw &data2)) == data1sz); 1578da6c28aaSamw bcopy(data1, data2, data2sz); 1579da6c28aaSamw } 158027dd1e87SMark Shellenbaum 1581da6c28aaSamw aclp->z_acl_count++; 1582da6c28aaSamw aclnode->z_ace_count++; 1583da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1584da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1585b3d141f8Smarks 1586de0f1ddbSAlbert Lee /* 1587de0f1ddbSAlbert Lee * If ACE is not to be inherited further, or if the vnode is 1588de0f1ddbSAlbert Lee * not a directory, remove all inheritance flags 1589de0f1ddbSAlbert Lee */ 1590de0f1ddbSAlbert Lee if (!isdir || (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) { 1591da6c28aaSamw newflags &= ~ALL_INHERIT; 1592da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1593da6c28aaSamw newflags|ACE_INHERITED_ACE); 1594fa9e4066Sahrens continue; 1595fa9e4066Sahrens } 1596fa9e4066Sahrens 1597de0f1ddbSAlbert Lee /* 1598de0f1ddbSAlbert Lee * This directory has an inheritable ACE 1599de0f1ddbSAlbert Lee */ 1600de0f1ddbSAlbert Lee aclp->z_hints |= ZFS_INHERIT_ACE; 1601fa9e4066Sahrens 1602da6c28aaSamw /* 160327dd1e87SMark Shellenbaum * If only FILE_INHERIT is set then turn on 160427dd1e87SMark Shellenbaum * inherit_only 1605da6c28aaSamw */ 160627dd1e87SMark Shellenbaum if ((iflags & (ACE_FILE_INHERIT_ACE | 1607485adf61SMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) { 1608da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1609da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1610da6c28aaSamw newflags|ACE_INHERITED_ACE); 1611485adf61SMark Shellenbaum } else { 1612485adf61SMark Shellenbaum newflags &= ~ACE_INHERIT_ONLY_ACE; 1613485adf61SMark Shellenbaum aclp->z_ops.ace_flags_set(acep, 1614485adf61SMark Shellenbaum newflags|ACE_INHERITED_ACE); 1615da6c28aaSamw } 1616da6c28aaSamw } 1617de0f1ddbSAlbert Lee 1618fa9e4066Sahrens return (aclp); 1619fa9e4066Sahrens } 1620fa9e4066Sahrens 1621fa9e4066Sahrens /* 1622fa9e4066Sahrens * Create file system object initial permissions 1623fa9e4066Sahrens * including inheritable ACEs. 1624de0f1ddbSAlbert Lee * Also, create FUIDs for owner and group. 1625fa9e4066Sahrens */ 162689459e17SMark Shellenbaum int 162789459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 162889459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1629fa9e4066Sahrens { 1630fa9e4066Sahrens int error; 163189459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1632da6c28aaSamw zfs_acl_t *paclp; 1633e0d35c44Smarks gid_t gid; 1634e9bacc6dSDominik Hassler boolean_t need_chmod = B_TRUE; 1635de0f1ddbSAlbert Lee boolean_t trim = B_FALSE; 16360a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE; 1637da6c28aaSamw 163889459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 163989459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1640fa9e4066Sahrens 164189459e17SMark Shellenbaum if (vsecp) 164289459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 164389459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 164489459e17SMark Shellenbaum return (error); 1645fa9e4066Sahrens /* 1646fa9e4066Sahrens * Determine uid and gid. 1647fa9e4066Sahrens */ 16484a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1649fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 165089459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 165189459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 165289459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 165389459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 165489459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 165589459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1656e0d35c44Smarks gid = vap->va_gid; 1657fa9e4066Sahrens } else { 165889459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 165989459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 166089459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1661e0d35c44Smarks if (vap->va_mask & AT_GID) { 166289459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 166389459e17SMark Shellenbaum (uint64_t)vap->va_gid, 166489459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1665e0d35c44Smarks gid = vap->va_gid; 1666f1696b23SMark Shellenbaum if (acl_ids->z_fgid != dzp->z_gid && 1667e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1668e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 166989459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1670e0d35c44Smarks } 167189459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 16720a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) { 1673b3874165SJohn Harres char *domain; 1674b3874165SJohn Harres uint32_t rid; 1675b3874165SJohn Harres 1676f1696b23SMark Shellenbaum acl_ids->z_fgid = dzp->z_gid; 167789459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1678e0d35c44Smarks cr, ZFS_GROUP); 1679b3874165SJohn Harres 1680b3874165SJohn Harres if (zfsvfs->z_use_fuids && 1681b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) { 1682b3874165SJohn Harres domain = zfs_fuid_idx_domain( 1683b3874165SJohn Harres &zfsvfs->z_fuid_idx, 1684b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid)); 1685b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid); 1686b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp, 1687b3874165SJohn Harres domain, rid, 1688b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid), 1689b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP); 1690b3874165SJohn Harres } 1691da6c28aaSamw } else { 169289459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 169389459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 1694e0d35c44Smarks gid = crgetgid(cr); 1695e0d35c44Smarks } 1696da6c28aaSamw } 1697fa9e4066Sahrens } 1698fa9e4066Sahrens 1699fa9e4066Sahrens /* 1700fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 1701fa9e4066Sahrens * set-GID bit set, set in on the new directory. 1702fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 1703fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 1704fa9e4066Sahrens */ 1705fa9e4066Sahrens 17060a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) && 170789459e17SMark Shellenbaum (vap->va_type == VDIR)) { 170889459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 1709e0d35c44Smarks } else { 171089459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 1711fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 171289459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 1713fa9e4066Sahrens } 1714fa9e4066Sahrens 171589459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 17161412a1a2SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 171789459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 1718a3c49ce1SAlbert Lee if (!(flag & IS_ROOT_NODE) && 1719a3c49ce1SAlbert Lee (dzp->z_pflags & ZFS_INHERIT_ACE) && 17200a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) { 17211412a1a2SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, B_TRUE, 17221412a1a2SMark Shellenbaum &paclp, B_FALSE)); 172389459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 1724e9bacc6dSDominik Hassler vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 17250a586ceaSMark Shellenbaum inherited = B_TRUE; 1726fa9e4066Sahrens } else { 172789459e17SMark Shellenbaum acl_ids->z_aclp = 172889459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 17290a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 1730fa9e4066Sahrens } 173189459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 17321412a1a2SMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 1733de0f1ddbSAlbert Lee 1734e9bacc6dSDominik Hassler if (need_chmod) { 1735de0f1ddbSAlbert Lee if (vap->va_type == VDIR) 1736e9bacc6dSDominik Hassler acl_ids->z_aclp->z_hints |= 1737e9bacc6dSDominik Hassler ZFS_ACL_AUTO_INHERIT; 1738de0f1ddbSAlbert Lee 1739de0f1ddbSAlbert Lee if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK && 1740de0f1ddbSAlbert Lee zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH && 1741de0f1ddbSAlbert Lee zfsvfs->z_acl_inherit != ZFS_ACL_PASSTHROUGH_X) 1742de0f1ddbSAlbert Lee trim = B_TRUE; 1743e9bacc6dSDominik Hassler zfs_acl_chmod(vap->va_type, acl_ids->z_mode, B_FALSE, 1744e9bacc6dSDominik Hassler trim, acl_ids->z_aclp); 1745e9bacc6dSDominik Hassler } 174689459e17SMark Shellenbaum } 1747da6c28aaSamw 17480a586ceaSMark Shellenbaum if (inherited || vsecp) { 17490a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode, 175027dd1e87SMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints, 175127dd1e87SMark Shellenbaum acl_ids->z_fuid, acl_ids->z_fgid); 17520a586ceaSMark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0) 17530a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 17540a586ceaSMark Shellenbaum } 17550a586ceaSMark Shellenbaum 175689459e17SMark Shellenbaum return (0); 1757fa9e4066Sahrens } 1758fa9e4066Sahrens 1759fa9e4066Sahrens /* 176089459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 176189459e17SMark Shellenbaum */ 176289459e17SMark Shellenbaum void 176389459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 176489459e17SMark Shellenbaum { 176589459e17SMark Shellenbaum if (acl_ids->z_aclp) 176689459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 176789459e17SMark Shellenbaum if (acl_ids->z_fuidp) 176889459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 176989459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 177089459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 177189459e17SMark Shellenbaum } 177289459e17SMark Shellenbaum 177314843421SMatthew Ahrens boolean_t 177414843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 177514843421SMatthew Ahrens { 17760a586ceaSMark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 17770a586ceaSMark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 177814843421SMatthew Ahrens } 177989459e17SMark Shellenbaum 178089459e17SMark Shellenbaum /* 1781f7170741SWill Andrews * Retrieve a file's ACL 1782fa9e4066Sahrens */ 1783fa9e4066Sahrens int 1784da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1785fa9e4066Sahrens { 1786fa9e4066Sahrens zfs_acl_t *aclp; 1787da6c28aaSamw ulong_t mask; 1788fa9e4066Sahrens int error; 1789da6c28aaSamw int count = 0; 1790da6c28aaSamw int largeace = 0; 1791fa9e4066Sahrens 1792da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 1793da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 1794da6c28aaSamw 1795fa9e4066Sahrens if (mask == 0) 1796be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 1797fa9e4066Sahrens 17980a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 17990a586ceaSMark Shellenbaum return (error); 18000a586ceaSMark Shellenbaum 1801fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1802fa9e4066Sahrens 18031412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 1804ea8dc4b6Seschrock if (error != 0) { 1805ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 1806ea8dc4b6Seschrock return (error); 1807ea8dc4b6Seschrock } 1808ea8dc4b6Seschrock 1809da6c28aaSamw /* 1810da6c28aaSamw * Scan ACL to determine number of ACEs 1811da6c28aaSamw */ 18120a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) { 1813da6c28aaSamw void *zacep = NULL; 1814da6c28aaSamw uint64_t who; 1815da6c28aaSamw uint32_t access_mask; 1816da6c28aaSamw uint16_t type, iflags; 1817da6c28aaSamw 1818da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 1819da6c28aaSamw &who, &access_mask, &iflags, &type)) { 1820da6c28aaSamw switch (type) { 1821da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1822da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1823da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1824da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1825da6c28aaSamw largeace++; 1826da6c28aaSamw continue; 1827da6c28aaSamw default: 1828da6c28aaSamw count++; 1829da6c28aaSamw } 1830da6c28aaSamw } 1831da6c28aaSamw vsecp->vsa_aclcnt = count; 1832da6c28aaSamw } else 18330a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count; 1834fa9e4066Sahrens 1835fa9e4066Sahrens if (mask & VSA_ACECNT) { 1836da6c28aaSamw vsecp->vsa_aclcnt = count; 1837fa9e4066Sahrens } 1838fa9e4066Sahrens 1839fa9e4066Sahrens if (mask & VSA_ACE) { 1840da6c28aaSamw size_t aclsz; 1841da6c28aaSamw 1842da6c28aaSamw aclsz = count * sizeof (ace_t) + 1843da6c28aaSamw sizeof (ace_object_t) * largeace; 1844da6c28aaSamw 1845da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 1846da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 1847da6c28aaSamw 1848da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 1849bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 1850da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 1851da6c28aaSamw else { 18522e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode; 18532e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp; 18542e7d9b42SMark Shellenbaum 18552e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode; 18562e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) { 18572e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start, 18582e7d9b42SMark Shellenbaum aclnode->z_size); 18592e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size; 18602e7d9b42SMark Shellenbaum } 18612e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 18622e7d9b42SMark Shellenbaum aclp->z_acl_bytes); 1863da6c28aaSamw } 1864da6c28aaSamw } 1865da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 1866da6c28aaSamw vsecp->vsa_aclflags = 0; 18670a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED) 1868da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 18690a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED) 1870da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 18710a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT) 1872da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 1873fa9e4066Sahrens } 1874fa9e4066Sahrens 1875fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 1876fa9e4066Sahrens 1877fa9e4066Sahrens return (0); 1878fa9e4066Sahrens } 1879fa9e4066Sahrens 1880da6c28aaSamw int 1881da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 188289459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 1883da6c28aaSamw { 1884da6c28aaSamw zfs_acl_t *aclp; 1885da6c28aaSamw zfs_acl_node_t *aclnode; 1886da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 1887da6c28aaSamw int error; 1888da6c28aaSamw 1889da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 1890be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1891da6c28aaSamw 1892da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 1893da6c28aaSamw 1894da6c28aaSamw aclp->z_hints = 0; 1895da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 1896da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1897da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 1898da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 1899da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 1900da6c28aaSamw zfs_acl_free(aclp); 1901da6c28aaSamw zfs_acl_node_free(aclnode); 1902da6c28aaSamw return (error); 1903da6c28aaSamw } 1904da6c28aaSamw } else { 190589459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 1906da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 190789459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 1908da6c28aaSamw zfs_acl_free(aclp); 1909da6c28aaSamw zfs_acl_node_free(aclnode); 1910da6c28aaSamw return (error); 1911da6c28aaSamw } 1912da6c28aaSamw } 1913da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 1914da6c28aaSamw aclnode->z_ace_count = aclcnt; 1915da6c28aaSamw aclp->z_acl_count = aclcnt; 1916da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 1917da6c28aaSamw 1918da6c28aaSamw /* 1919da6c28aaSamw * If flags are being set then add them to z_hints 1920da6c28aaSamw */ 1921da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 1922da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 1923da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 1924da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 1925da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 1926da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 1927da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 1928da6c28aaSamw } 1929da6c28aaSamw 1930da6c28aaSamw *zaclp = aclp; 1931da6c28aaSamw 1932da6c28aaSamw return (0); 1933da6c28aaSamw } 1934da6c28aaSamw 1935fa9e4066Sahrens /* 1936f7170741SWill Andrews * Set a file's ACL 1937fa9e4066Sahrens */ 1938fa9e4066Sahrens int 1939da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 1940fa9e4066Sahrens { 1941fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1942fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 1943fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 1944fa9e4066Sahrens dmu_tx_t *tx; 1945fa9e4066Sahrens int error; 1946fa9e4066Sahrens zfs_acl_t *aclp; 1947da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 194889459e17SMark Shellenbaum boolean_t fuid_dirtied; 19491412a1a2SMark Shellenbaum uint64_t acl_obj; 1950fa9e4066Sahrens 1951fa9e4066Sahrens if (mask == 0) 1952be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSYS)); 1953fa9e4066Sahrens 19540a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE) 1955be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 1956da6c28aaSamw 1957da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 1958fa9e4066Sahrens return (error); 1959da6c28aaSamw 196089459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 196189459e17SMark Shellenbaum &aclp); 1962da6c28aaSamw if (error) 1963da6c28aaSamw return (error); 1964da6c28aaSamw 1965da6c28aaSamw /* 1966da6c28aaSamw * If ACL wide flags aren't being set then preserve any 1967da6c28aaSamw * existing flags. 1968da6c28aaSamw */ 1969da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 19700a586ceaSMark Shellenbaum aclp->z_hints |= 19710a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS); 1972fa9e4066Sahrens } 1973da6c28aaSamw top: 1974fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 19751412a1a2SMark Shellenbaum mutex_enter(&zp->z_lock); 1976fa9e4066Sahrens 1977fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 1978fa9e4066Sahrens 19790a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); 19800a586ceaSMark Shellenbaum 198189459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 198214843421SMatthew Ahrens if (fuid_dirtied) 198314843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 1984fa9e4066Sahrens 19850a586ceaSMark Shellenbaum /* 19860a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't 19870a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds 19880a586ceaSMark Shellenbaum */ 19890a586ceaSMark Shellenbaum 19901412a1a2SMark Shellenbaum if ((acl_obj = zfs_external_acl(zp)) != 0) { 19912bd6c4deSMark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_FUID && 19921412a1a2SMark Shellenbaum zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) { 19931412a1a2SMark Shellenbaum dmu_tx_hold_free(tx, acl_obj, 0, 19940a586ceaSMark Shellenbaum DMU_OBJECT_END); 19952bd6c4deSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 19962bd6c4deSMark Shellenbaum aclp->z_acl_bytes); 19970a586ceaSMark Shellenbaum } else { 19981412a1a2SMark Shellenbaum dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes); 19990a586ceaSMark Shellenbaum } 20000a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { 20010a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 20020a586ceaSMark Shellenbaum } 20030a586ceaSMark Shellenbaum 20040a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp); 20051209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 2006fa9e4066Sahrens if (error) { 2007fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2008fa9e4066Sahrens mutex_exit(&zp->z_lock); 2009fa9e4066Sahrens 20101209a471SNeil Perrin if (error == ERESTART) { 20118a2f1b91Sahrens dmu_tx_wait(tx); 20128a2f1b91Sahrens dmu_tx_abort(tx); 2013fa9e4066Sahrens goto top; 2014fa9e4066Sahrens } 20158a2f1b91Sahrens dmu_tx_abort(tx); 2016da6c28aaSamw zfs_acl_free(aclp); 2017fa9e4066Sahrens return (error); 2018fa9e4066Sahrens } 2019fa9e4066Sahrens 202089459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2021fa9e4066Sahrens ASSERT(error == 0); 20220b2a8171SMark Shellenbaum ASSERT(zp->z_acl_cached == NULL); 20234929fd5eSTim Haley zp->z_acl_cached = aclp; 2024fa9e4066Sahrens 202589459e17SMark Shellenbaum if (fuid_dirtied) 202689459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 202789459e17SMark Shellenbaum 2028da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2029da6c28aaSamw 2030da6c28aaSamw if (fuidp) 2031da6c28aaSamw zfs_fuid_info_free(fuidp); 2032fa9e4066Sahrens dmu_tx_commit(tx); 2033fa9e4066Sahrens done: 2034fa9e4066Sahrens mutex_exit(&zp->z_lock); 20351412a1a2SMark Shellenbaum mutex_exit(&zp->z_acl_lock); 2036fa9e4066Sahrens 2037fa9e4066Sahrens return (error); 2038fa9e4066Sahrens } 2039fa9e4066Sahrens 2040fa9e4066Sahrens /* 2041e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2042e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2043e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2044fa9e4066Sahrens */ 2045fa9e4066Sahrens static int 2046e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2047fa9e4066Sahrens { 2048fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2049fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2050f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2051f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2052be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS)); 2053fa9e4066Sahrens } 2054fa9e4066Sahrens 2055da6c28aaSamw /* 20562889ec41SGordon Ross * Intentionally allow ZFS_READONLY through here. 20572889ec41SGordon Ross * See zfs_zaccess_common(). 2058da6c28aaSamw */ 2059da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 20602889ec41SGordon Ross (zp->z_pflags & ZFS_IMMUTABLE)) { 2061be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2062da6c28aaSamw } 2063da6c28aaSamw 2064da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 20650a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) { 2066be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2067da6c28aaSamw } 2068da6c28aaSamw 2069da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 20700a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) { 2071be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2072da6c28aaSamw } 2073da6c28aaSamw 2074da6c28aaSamw return (0); 2075da6c28aaSamw } 2076da6c28aaSamw 2077e802abbdSTim Haley /* 2078e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2079e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2080e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2081e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2082e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2083e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2084e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2085e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2086e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2087e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2088e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2089e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2090e802abbdSTim Haley * accesses. Returns: 2091e802abbdSTim Haley * 0 if all AoI granted 20921eb4e906SKevin Crowe * EACCES if the denied mask is non-zero 2093e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2094e802abbdSTim Haley * 2095e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2096e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2097e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2098e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2099e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2100e802abbdSTim Haley * is used in this manner. 2101e802abbdSTim Haley */ 2102e802abbdSTim Haley static int 2103e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2104e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2105e802abbdSTim Haley { 2106e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2107e802abbdSTim Haley zfs_acl_t *aclp; 2108e802abbdSTim Haley int error; 2109e802abbdSTim Haley uid_t uid = crgetuid(cr); 2110e802abbdSTim Haley uint64_t who; 2111e802abbdSTim Haley uint16_t type, iflags; 2112e802abbdSTim Haley uint16_t entry_type; 2113e802abbdSTim Haley uint32_t access_mask; 2114e802abbdSTim Haley uint32_t deny_mask = 0; 2115e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2116e802abbdSTim Haley boolean_t checkit; 2117f1696b23SMark Shellenbaum uid_t gowner; 2118f1696b23SMark Shellenbaum uid_t fowner; 2119f1696b23SMark Shellenbaum 2120f1696b23SMark Shellenbaum zfs_fuid_map_ids(zp, cr, &fowner, &gowner); 2121da6c28aaSamw 2122fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2123fa9e4066Sahrens 21241412a1a2SMark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE); 2125ea8dc4b6Seschrock if (error != 0) { 2126ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2127ea8dc4b6Seschrock return (error); 2128ea8dc4b6Seschrock } 2129ea8dc4b6Seschrock 21300a586ceaSMark Shellenbaum ASSERT(zp->z_acl_cached); 21310a586ceaSMark Shellenbaum 2132da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2133da6c28aaSamw &iflags, &type)) { 2134e802abbdSTim Haley uint32_t mask_matched; 2135fa9e4066Sahrens 2136003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2137003c2582SMark Shellenbaum continue; 2138003c2582SMark Shellenbaum 2139b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2140fa9e4066Sahrens continue; 2141fa9e4066Sahrens 2142e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2143e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2144e802abbdSTim Haley if (!mask_matched) 2145e802abbdSTim Haley continue; 2146e802abbdSTim Haley 2147da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2148da6c28aaSamw 2149da6c28aaSamw checkit = B_FALSE; 2150da6c28aaSamw 2151fa9e4066Sahrens switch (entry_type) { 2152fa9e4066Sahrens case ACE_OWNER: 2153f1696b23SMark Shellenbaum if (uid == fowner) 2154da6c28aaSamw checkit = B_TRUE; 2155fa9e4066Sahrens break; 2156da6c28aaSamw case OWNING_GROUP: 2157da6c28aaSamw who = gowner; 2158da6c28aaSamw /*FALLTHROUGH*/ 2159fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2160da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2161fa9e4066Sahrens break; 2162fa9e4066Sahrens case ACE_EVERYONE: 2163da6c28aaSamw checkit = B_TRUE; 2164fa9e4066Sahrens break; 2165fa9e4066Sahrens 2166fa9e4066Sahrens /* USER Entry */ 2167fa9e4066Sahrens default: 2168fa9e4066Sahrens if (entry_type == 0) { 2169da6c28aaSamw uid_t newid; 2170da6c28aaSamw 2171e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2172e0d35c44Smarks ZFS_ACE_USER); 2173da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2174da6c28aaSamw uid == newid) 2175da6c28aaSamw checkit = B_TRUE; 2176fa9e4066Sahrens break; 2177da6c28aaSamw } else { 2178fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2179be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 2180fa9e4066Sahrens } 2181da6c28aaSamw } 2182da6c28aaSamw 2183da6c28aaSamw if (checkit) { 2184e802abbdSTim Haley if (type == DENY) { 2185e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2186e802abbdSTim Haley znode_t *, zp, 2187e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2188e802abbdSTim Haley uint32_t, mask_matched); 218990fafcf0Smarks deny_mask |= mask_matched; 2190e802abbdSTim Haley } else { 2191e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2192e802abbdSTim Haley znode_t *, zp, 2193e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2194e802abbdSTim Haley uint32_t, mask_matched); 2195e802abbdSTim Haley if (anyaccess) { 2196e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2197e802abbdSTim Haley return (0); 2198da6c28aaSamw } 2199da6c28aaSamw } 2200e802abbdSTim Haley *working_mode &= ~mask_matched; 2201e802abbdSTim Haley } 2202fa9e4066Sahrens 220390fafcf0Smarks /* Are we done? */ 220490fafcf0Smarks if (*working_mode == 0) 2205fa9e4066Sahrens break; 2206fa9e4066Sahrens } 2207fa9e4066Sahrens 2208fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 220990fafcf0Smarks 221090fafcf0Smarks /* Put the found 'denies' back on the working mode */ 22117ed7e920Smarks if (deny_mask) { 221290fafcf0Smarks *working_mode |= deny_mask; 2213be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 22147ed7e920Smarks } else if (*working_mode) { 22157ed7e920Smarks return (-1); 22167ed7e920Smarks } 221790fafcf0Smarks 221890fafcf0Smarks return (0); 2219fa9e4066Sahrens } 2220fa9e4066Sahrens 2221e802abbdSTim Haley /* 2222e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2223e802abbdSTim Haley * care what access is granted. 2224e802abbdSTim Haley */ 2225e802abbdSTim Haley boolean_t 2226e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2227e802abbdSTim Haley { 2228e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2229e802abbdSTim Haley 2230e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2231f1696b23SMark Shellenbaum uid_t owner; 2232f1696b23SMark Shellenbaum 2233f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2234f1696b23SMark Shellenbaum return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0); 2235e802abbdSTim Haley } 2236e802abbdSTim Haley return (B_TRUE); 2237e802abbdSTim Haley } 2238e802abbdSTim Haley 2239e802abbdSTim Haley static int 2240e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2241e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2242e802abbdSTim Haley { 2243e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2244e802abbdSTim Haley int err; 2245e802abbdSTim Haley 2246e802abbdSTim Haley *working_mode = v4_mode; 2247e802abbdSTim Haley *check_privs = B_TRUE; 2248e802abbdSTim Haley 2249e802abbdSTim Haley /* 2250e802abbdSTim Haley * Short circuit empty requests 2251e802abbdSTim Haley */ 2252e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2253e802abbdSTim Haley *working_mode = 0; 2254e802abbdSTim Haley return (0); 2255e802abbdSTim Haley } 2256e802abbdSTim Haley 2257e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2258e802abbdSTim Haley *check_privs = B_FALSE; 2259e802abbdSTim Haley return (err); 2260e802abbdSTim Haley } 2261e802abbdSTim Haley 2262e802abbdSTim Haley /* 2263e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2264e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2265e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2266e802abbdSTim Haley */ 2267e802abbdSTim Haley if (skipaclchk) { 2268e802abbdSTim Haley *working_mode = 0; 2269e802abbdSTim Haley return (0); 2270e802abbdSTim Haley } 2271e802abbdSTim Haley 22722889ec41SGordon Ross /* 22732889ec41SGordon Ross * Note: ZFS_READONLY represents the "DOS R/O" attribute. 22742889ec41SGordon Ross * When that flag is set, we should behave as if write access 22752889ec41SGordon Ross * were not granted by anything in the ACL. In particular: 22762889ec41SGordon Ross * We _must_ allow writes after opening the file r/w, then 22772889ec41SGordon Ross * setting the DOS R/O attribute, and writing some more. 22782889ec41SGordon Ross * (Similar to how you can write after fchmod(fd, 0444).) 22792889ec41SGordon Ross * 22802889ec41SGordon Ross * Therefore ZFS_READONLY is ignored in the dataset check 22812889ec41SGordon Ross * above, and checked here as if part of the ACL check. 22822889ec41SGordon Ross * Also note: DOS R/O is ignored for directories. 22832889ec41SGordon Ross */ 22842889ec41SGordon Ross if ((v4_mode & WRITE_MASK_DATA) && 22852889ec41SGordon Ross (ZTOV(zp)->v_type != VDIR) && 22862889ec41SGordon Ross (zp->z_pflags & ZFS_READONLY)) { 22872889ec41SGordon Ross return (SET_ERROR(EPERM)); 22882889ec41SGordon Ross } 22892889ec41SGordon Ross 2290e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2291e802abbdSTim Haley } 2292e802abbdSTim Haley 2293da6c28aaSamw static int 2294da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2295da6c28aaSamw cred_t *cr) 2296da6c28aaSamw { 2297da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2298be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2299da6c28aaSamw 2300da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2301da6c28aaSamw check_privs, B_FALSE, cr)); 2302da6c28aaSamw } 2303fa9e4066Sahrens 2304d47621a4STim Haley int 2305d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2306d47621a4STim Haley { 2307d47621a4STim Haley boolean_t owner = B_FALSE; 2308d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2309d47621a4STim Haley boolean_t is_attr; 2310d47621a4STim Haley uid_t uid = crgetuid(cr); 2311d47621a4STim Haley int error; 2312d47621a4STim Haley 23130a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED) 2314be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2315d47621a4STim Haley 23160a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) && 2317d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2318d47621a4STim Haley if (is_attr) 2319d47621a4STim Haley goto slow; 2320d47621a4STim Haley 23210a586ceaSMark Shellenbaum 2322d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2323d47621a4STim Haley 23240a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) { 2325d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2326d47621a4STim Haley return (0); 2327d47621a4STim Haley } 2328d47621a4STim Haley 2329f1696b23SMark Shellenbaum if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) { 2330d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2331d47621a4STim Haley goto slow; 2332d47621a4STim Haley } 2333d47621a4STim Haley 23340a586ceaSMark Shellenbaum if (uid == zdp->z_uid) { 2335d47621a4STim Haley owner = B_TRUE; 23360a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) { 2337d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2338d47621a4STim Haley return (0); 2339e4f96946STim Haley } else { 2340e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2341e4f96946STim Haley goto slow; 2342d47621a4STim Haley } 2343d47621a4STim Haley } 23440a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) { 2345d47621a4STim Haley groupmbr = B_TRUE; 23460a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) { 2347d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2348d47621a4STim Haley return (0); 2349e4f96946STim Haley } else { 2350e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2351e4f96946STim Haley goto slow; 2352d47621a4STim Haley } 2353d47621a4STim Haley } 2354d47621a4STim Haley if (!owner && !groupmbr) { 23550a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) { 2356d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2357d47621a4STim Haley return (0); 2358d47621a4STim Haley } 2359d47621a4STim Haley } 2360d47621a4STim Haley 2361d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2362d47621a4STim Haley 2363d47621a4STim Haley slow: 2364d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2365d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2366d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2367d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2368d47621a4STim Haley return (error); 2369d47621a4STim Haley } 2370d47621a4STim Haley 2371fa9e4066Sahrens /* 2372134a1f4eSCasper H.S. Dik * Determine whether Access should be granted/denied. 2373f7170741SWill Andrews * 2374*edc8ef7dSToomas Soome * The least priv subsystem is always consulted as a basic privilege 2375134a1f4eSCasper H.S. Dik * can define any form of access. 2376fa9e4066Sahrens */ 2377fa9e4066Sahrens int 2378da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2379fa9e4066Sahrens { 2380da6c28aaSamw uint32_t working_mode; 2381fa9e4066Sahrens int error; 2382fa9e4066Sahrens int is_attr; 2383da6c28aaSamw boolean_t check_privs; 2384fa9e4066Sahrens znode_t *xzp; 2385fa9e4066Sahrens znode_t *check_zp = zp; 2386134a1f4eSCasper H.S. Dik mode_t needed_bits; 2387f1696b23SMark Shellenbaum uid_t owner; 2388fa9e4066Sahrens 23890a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); 2390fa9e4066Sahrens 2391fa9e4066Sahrens /* 2392fa9e4066Sahrens * If attribute then validate against base file 2393fa9e4066Sahrens */ 2394fa9e4066Sahrens if (is_attr) { 23950a586ceaSMark Shellenbaum uint64_t parent; 23960a586ceaSMark Shellenbaum 23970a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 23980a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent, 23990a586ceaSMark Shellenbaum sizeof (parent))) != 0) 24000a586ceaSMark Shellenbaum return (error); 24010a586ceaSMark Shellenbaum 2402fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 24030a586ceaSMark Shellenbaum parent, &xzp)) != 0) { 2404fa9e4066Sahrens return (error); 2405fa9e4066Sahrens } 2406da6c28aaSamw 2407fa9e4066Sahrens check_zp = xzp; 2408da6c28aaSamw 2409fa9e4066Sahrens /* 2410fa9e4066Sahrens * fixup mode to map to xattr perms 2411fa9e4066Sahrens */ 2412fa9e4066Sahrens 2413fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2414fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2415fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2416fa9e4066Sahrens } 2417fa9e4066Sahrens 2418fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2419fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2420fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2421fa9e4066Sahrens } 2422fa9e4066Sahrens } 2423fa9e4066Sahrens 2424f1696b23SMark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER); 2425134a1f4eSCasper H.S. Dik /* 2426134a1f4eSCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC 2427134a1f4eSCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently 2428134a1f4eSCasper H.S. Dik * missing) in missing_bits. 2429134a1f4eSCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode), 2430134a1f4eSCasper H.S. Dik * needed_bits. 2431134a1f4eSCasper H.S. Dik */ 2432134a1f4eSCasper H.S. Dik needed_bits = 0; 2433134a1f4eSCasper H.S. Dik 2434134a1f4eSCasper H.S. Dik working_mode = mode; 2435134a1f4eSCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && 2436f1696b23SMark Shellenbaum owner == crgetuid(cr)) 2437134a1f4eSCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2438134a1f4eSCasper H.S. Dik 2439134a1f4eSCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 2440134a1f4eSCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2441134a1f4eSCasper H.S. Dik needed_bits |= VREAD; 2442134a1f4eSCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 2443134a1f4eSCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2444134a1f4eSCasper H.S. Dik needed_bits |= VWRITE; 2445134a1f4eSCasper H.S. Dik if (working_mode & ACE_EXECUTE) 2446134a1f4eSCasper H.S. Dik needed_bits |= VEXEC; 2447134a1f4eSCasper H.S. Dik 2448da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2449da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2450da6c28aaSamw if (is_attr) 2451da6c28aaSamw VN_RELE(ZTOV(xzp)); 2452f1696b23SMark Shellenbaum return (secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2453134a1f4eSCasper H.S. Dik needed_bits, needed_bits)); 2454da6c28aaSamw } 2455fa9e4066Sahrens 2456e0d35c44Smarks if (error && !check_privs) { 2457fa9e4066Sahrens if (is_attr) 2458fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2459fa9e4066Sahrens return (error); 2460fa9e4066Sahrens } 2461fa9e4066Sahrens 2462da6c28aaSamw if (error && (flags & V_APPEND)) { 2463da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2464fa9e4066Sahrens } 2465fa9e4066Sahrens 2466da6c28aaSamw if (error && check_privs) { 2467da6c28aaSamw mode_t checkmode = 0; 2468fa9e4066Sahrens 2469fa9e4066Sahrens /* 2470da6c28aaSamw * First check for implicit owner permission on 2471da6c28aaSamw * read_acl/read_attributes 2472fa9e4066Sahrens */ 2473fa9e4066Sahrens 2474da6c28aaSamw error = 0; 2475da6c28aaSamw ASSERT(working_mode != 0); 2476da6c28aaSamw 2477da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2478f1696b23SMark Shellenbaum owner == crgetuid(cr))) 2479da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2480da6c28aaSamw 2481da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 248247def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2483da6c28aaSamw checkmode |= VREAD; 2484da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 248547def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2486da6c28aaSamw checkmode |= VWRITE; 2487da6c28aaSamw if (working_mode & ACE_EXECUTE) 2488da6c28aaSamw checkmode |= VEXEC; 2489da6c28aaSamw 2490f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner, 2491134a1f4eSCasper H.S. Dik needed_bits & ~checkmode, needed_bits); 2492da6c28aaSamw 2493da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2494f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 2495da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2496f1696b23SMark Shellenbaum error = secpolicy_vnode_setdac(cr, owner); 2497da6c28aaSamw 2498da6c28aaSamw if (error == 0 && (working_mode & 2499da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2500da6c28aaSamw error = secpolicy_vnode_remove(cr); 2501da6c28aaSamw 250247def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2503f1696b23SMark Shellenbaum error = secpolicy_vnode_chown(cr, owner); 250447def0dcSMark Shellenbaum } 2505da6c28aaSamw if (error == 0) { 2506da6c28aaSamw /* 2507da6c28aaSamw * See if any bits other than those already checked 2508da6c28aaSamw * for are still present. If so then return EACCES 2509da6c28aaSamw */ 2510da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2511be6fd75aSMatthew Ahrens error = SET_ERROR(EACCES); 2512da6c28aaSamw } 2513da6c28aaSamw } 2514134a1f4eSCasper H.S. Dik } else if (error == 0) { 2515f1696b23SMark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(zp), owner, 2516134a1f4eSCasper H.S. Dik needed_bits, needed_bits); 2517da6c28aaSamw } 2518da6c28aaSamw 2519134a1f4eSCasper H.S. Dik 2520da6c28aaSamw if (is_attr) 2521da6c28aaSamw VN_RELE(ZTOV(xzp)); 2522da6c28aaSamw 2523da6c28aaSamw return (error); 2524fa9e4066Sahrens } 2525fa9e4066Sahrens 2526fa9e4066Sahrens /* 2527da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2528fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2529fa9e4066Sahrens */ 2530fa9e4066Sahrens int 2531da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2532da6c28aaSamw { 2533da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2534da6c28aaSamw } 2535da6c28aaSamw 2536da6c28aaSamw /* 2537da6c28aaSamw * Access function for secpolicy_vnode_setattr 2538da6c28aaSamw */ 2539da6c28aaSamw int 2540da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2541fa9e4066Sahrens { 2542fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2543fa9e4066Sahrens 2544da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2545fa9e4066Sahrens } 2546fa9e4066Sahrens 25471eb4e906SKevin Crowe /* See zfs_zaccess_delete() */ 25481eb4e906SKevin Crowe int zfs_write_implies_delete_child = 1; 254947db7e74Smarks 2550fa9e4066Sahrens /* 25511eb4e906SKevin Crowe * Determine whether delete access should be granted. 2552fa9e4066Sahrens * 2553da412744SKevin Crowe * The following chart outlines how we handle delete permissions which is 2554da412744SKevin Crowe * how recent versions of windows (Windows 2008) handles it. The efficiency 2555da412744SKevin Crowe * comes from not having to check the parent ACL where the object itself grants 2556da412744SKevin Crowe * delete: 2557fa9e4066Sahrens * 2558fa9e4066Sahrens * ------------------------------------------------------- 2559fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2560fa9e4066Sahrens * | permissions | | 2561fa9e4066Sahrens * ------------------------------------------------------- 2562fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2563fa9e4066Sahrens * | | Delete | Delete | unspecified| 2564fa9e4066Sahrens * ------------------------------------------------------- 2565da412744SKevin Crowe * | ACL Allows | Permit | Deny * | Permit | 25661eb4e906SKevin Crowe * | DELETE_CHILD | | | | 2567fa9e4066Sahrens * ------------------------------------------------------- 2568da412744SKevin Crowe * | ACL Denies | Permit | Deny | Deny | 2569fa9e4066Sahrens * | DELETE_CHILD | | | | 2570fa9e4066Sahrens * ------------------------------------------------------- 2571fa9e4066Sahrens * | ACL specifies | | | | 2572da412744SKevin Crowe * | only allow | Permit | Deny * | Permit | 2573fa9e4066Sahrens * | write and | | | | 2574fa9e4066Sahrens * | execute | | | | 2575fa9e4066Sahrens * ------------------------------------------------------- 2576fa9e4066Sahrens * | ACL denies | | | | 2577fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2578fa9e4066Sahrens * | execute | | | | 2579fa9e4066Sahrens * ------------------------------------------------------- 2580fa9e4066Sahrens * ^ 2581fa9e4066Sahrens * | 25821eb4e906SKevin Crowe * Re. execute permission on the directory: if that's missing, 25831eb4e906SKevin Crowe * the vnode lookup of the target will fail before we get here. 2584fa9e4066Sahrens * 2585da412744SKevin Crowe * Re [*] in the table above: NFSv4 would normally Permit delete for 2586da412744SKevin Crowe * these two cells of the matrix. 2587da412744SKevin Crowe * See acl.h for notes on which ACE_... flags should be checked for which 2588da412744SKevin Crowe * operations. Specifically, the NFSv4 committee recommendation is in 2589da412744SKevin Crowe * conflict with the Windows interpretation of DENY ACEs, where DENY ACEs 25901eb4e906SKevin Crowe * should take precedence ahead of ALLOW ACEs. 25911eb4e906SKevin Crowe * 2592da412744SKevin Crowe * This implementation always consults the target object's ACL first. 2593da412744SKevin Crowe * If a DENY ACE is present on the target object that specifies ACE_DELETE, 2594da412744SKevin Crowe * delete access is denied. If an ALLOW ACE with ACE_DELETE is present on 2595da412744SKevin Crowe * the target object, access is allowed. If and only if no entries with 2596da412744SKevin Crowe * ACE_DELETE are present in the object's ACL, check the container's ACL 2597da412744SKevin Crowe * for entries with ACE_DELETE_CHILD. 25981eb4e906SKevin Crowe * 2599da412744SKevin Crowe * A summary of the logic implemented from the table above is as follows: 26001eb4e906SKevin Crowe * 26011eb4e906SKevin Crowe * First check for DENY ACEs that apply. 26021eb4e906SKevin Crowe * If either target or container has a deny, EACCES. 26031eb4e906SKevin Crowe * 26041eb4e906SKevin Crowe * Delete access can then be summarized as follows: 26051eb4e906SKevin Crowe * 1: The object to be deleted grants ACE_DELETE, or 26061eb4e906SKevin Crowe * 2: The containing directory grants ACE_DELETE_CHILD. 26071eb4e906SKevin Crowe * In a Windows system, that would be the end of the story. 26081eb4e906SKevin Crowe * In this system, (2) has some complications... 26091eb4e906SKevin Crowe * 2a: "sticky" bit on a directory adds restrictions, and 26101eb4e906SKevin Crowe * 2b: existing ACEs from previous versions of ZFS may 26111eb4e906SKevin Crowe * not carry ACE_DELETE_CHILD where they should, so we 26121eb4e906SKevin Crowe * also allow delete when ACE_WRITE_DATA is granted. 26131eb4e906SKevin Crowe * 26141eb4e906SKevin Crowe * Note: 2b is technically a work-around for a prior bug, 26151eb4e906SKevin Crowe * which hopefully can go away some day. For those who 26161eb4e906SKevin Crowe * no longer need the work around, and for testing, this 26171eb4e906SKevin Crowe * work-around is made conditional via the tunable: 26181eb4e906SKevin Crowe * zfs_write_implies_delete_child 2619fa9e4066Sahrens */ 2620fa9e4066Sahrens int 2621fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2622fa9e4066Sahrens { 26231eb4e906SKevin Crowe uint32_t wanted_dirperms; 2624da6c28aaSamw uint32_t dzp_working_mode = 0; 2625da6c28aaSamw uint32_t zp_working_mode = 0; 2626fa9e4066Sahrens int dzp_error, zp_error; 26271eb4e906SKevin Crowe boolean_t dzpcheck_privs; 26281eb4e906SKevin Crowe boolean_t zpcheck_privs; 2629fa9e4066Sahrens 26300a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2631be6fd75aSMatthew Ahrens return (SET_ERROR(EPERM)); 2632fa9e4066Sahrens 263323d5bb1fSmarks /* 26341eb4e906SKevin Crowe * Case 1: 26351eb4e906SKevin Crowe * If target object grants ACE_DELETE then we are done. This is 26361eb4e906SKevin Crowe * indicated by a return value of 0. For this case we don't worry 26371eb4e906SKevin Crowe * about the sticky bit because sticky only applies to the parent 26381eb4e906SKevin Crowe * directory and this is the child access result. 26397ed7e920Smarks * 26401eb4e906SKevin Crowe * If we encounter a DENY ACE here, we're also done (EACCES). 26411eb4e906SKevin Crowe * Note that if we hit a DENY ACE here (on the target) it should 26421eb4e906SKevin Crowe * take precedence over a DENY ACE on the container, so that when 26431eb4e906SKevin Crowe * we have more complete auditing support we will be able to 26441eb4e906SKevin Crowe * report an access failure against the specific target. 26451eb4e906SKevin Crowe * (This is part of why we're checking the target first.) 2646fa9e4066Sahrens */ 26471eb4e906SKevin Crowe zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 26481eb4e906SKevin Crowe &zpcheck_privs, B_FALSE, cr); 26491eb4e906SKevin Crowe if (zp_error == EACCES) { 26501eb4e906SKevin Crowe /* We hit a DENY ACE. */ 26511eb4e906SKevin Crowe if (!zpcheck_privs) 26521eb4e906SKevin Crowe return (SET_ERROR(zp_error)); 26537ed7e920Smarks return (secpolicy_vnode_remove(cr)); 265447db7e74Smarks 26551eb4e906SKevin Crowe } 26561eb4e906SKevin Crowe if (zp_error == 0) 26571eb4e906SKevin Crowe return (0); 2658fa9e4066Sahrens 26591eb4e906SKevin Crowe /* 26601eb4e906SKevin Crowe * Case 2: 26611eb4e906SKevin Crowe * If the containing directory grants ACE_DELETE_CHILD, 26621eb4e906SKevin Crowe * or we're in backward compatibility mode and the 26631eb4e906SKevin Crowe * containing directory has ACE_WRITE_DATA, allow. 26641eb4e906SKevin Crowe * Case 2b is handled with wanted_dirperms. 26651eb4e906SKevin Crowe */ 26661eb4e906SKevin Crowe wanted_dirperms = ACE_DELETE_CHILD; 26671eb4e906SKevin Crowe if (zfs_write_implies_delete_child) 26681eb4e906SKevin Crowe wanted_dirperms |= ACE_WRITE_DATA; 26691eb4e906SKevin Crowe dzp_error = zfs_zaccess_common(dzp, wanted_dirperms, 2670134a1f4eSCasper H.S. Dik &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); 26711eb4e906SKevin Crowe if (dzp_error == EACCES) { 26721eb4e906SKevin Crowe /* We hit a DENY ACE. */ 26731eb4e906SKevin Crowe if (!dzpcheck_privs) 26741eb4e906SKevin Crowe return (SET_ERROR(dzp_error)); 26751eb4e906SKevin Crowe return (secpolicy_vnode_remove(cr)); 26761eb4e906SKevin Crowe } 26777ed7e920Smarks 2678fa9e4066Sahrens /* 26791eb4e906SKevin Crowe * Cases 2a, 2b (continued) 26801eb4e906SKevin Crowe * 26811eb4e906SKevin Crowe * Note: dzp_working_mode now contains any permissions 26821eb4e906SKevin Crowe * that were NOT granted. Therefore, if any of the 26831eb4e906SKevin Crowe * wanted_dirperms WERE granted, we will have: 26841eb4e906SKevin Crowe * dzp_working_mode != wanted_dirperms 26851eb4e906SKevin Crowe * We're really asking if ANY of those permissions 26861eb4e906SKevin Crowe * were granted, and if so, grant delete access. 2687fa9e4066Sahrens */ 26881eb4e906SKevin Crowe if (dzp_working_mode != wanted_dirperms) 26891eb4e906SKevin Crowe dzp_error = 0; 2690fa9e4066Sahrens 26911eb4e906SKevin Crowe /* 26921eb4e906SKevin Crowe * dzp_error is 0 if the container granted us permissions to "modify". 26931eb4e906SKevin Crowe * If we do not have permission via one or more ACEs, our current 26941eb4e906SKevin Crowe * privileges may still permit us to modify the container. 26951eb4e906SKevin Crowe * 26961eb4e906SKevin Crowe * dzpcheck_privs is false when i.e. the FS is read-only. 26971eb4e906SKevin Crowe * Otherwise, do privilege checks for the container. 26981eb4e906SKevin Crowe */ 26991eb4e906SKevin Crowe if (dzp_error != 0 && dzpcheck_privs) { 27001eb4e906SKevin Crowe uid_t owner; 27017ed7e920Smarks 27021eb4e906SKevin Crowe /* 27031eb4e906SKevin Crowe * The secpolicy call needs the requested access and 27041eb4e906SKevin Crowe * the current access mode of the container, but it 27051eb4e906SKevin Crowe * only knows about Unix-style modes (VEXEC, VWRITE), 27061eb4e906SKevin Crowe * so this must condense the fine-grained ACE bits into 27071eb4e906SKevin Crowe * Unix modes. 27081eb4e906SKevin Crowe * 27091eb4e906SKevin Crowe * The VEXEC flag is easy, because we know that has 27101eb4e906SKevin Crowe * always been checked before we get here (during the 27111eb4e906SKevin Crowe * lookup of the target vnode). The container has not 27121eb4e906SKevin Crowe * granted us permissions to "modify", so we do not set 27131eb4e906SKevin Crowe * the VWRITE flag in the current access mode. 27141eb4e906SKevin Crowe */ 27151eb4e906SKevin Crowe owner = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr, 27161eb4e906SKevin Crowe ZFS_OWNER); 27171eb4e906SKevin Crowe dzp_error = secpolicy_vnode_access2(cr, ZTOV(dzp), 27181eb4e906SKevin Crowe owner, VEXEC, VWRITE|VEXEC); 27191eb4e906SKevin Crowe } 27201eb4e906SKevin Crowe if (dzp_error != 0) { 27211eb4e906SKevin Crowe /* 27221eb4e906SKevin Crowe * Note: We may have dzp_error = -1 here (from 27231eb4e906SKevin Crowe * zfs_zacess_common). Don't return that. 27241eb4e906SKevin Crowe */ 27251eb4e906SKevin Crowe return (SET_ERROR(EACCES)); 27261eb4e906SKevin Crowe } 27277ed7e920Smarks 27281eb4e906SKevin Crowe /* 27291eb4e906SKevin Crowe * At this point, we know that the directory permissions allow 27301eb4e906SKevin Crowe * us to modify, but we still need to check for the additional 27311eb4e906SKevin Crowe * restrictions that apply when the "sticky bit" is set. 27321eb4e906SKevin Crowe * 27331eb4e906SKevin Crowe * Yes, zfs_sticky_remove_access() also checks this bit, but 27341eb4e906SKevin Crowe * checking it here and skipping the call below is nice when 27351eb4e906SKevin Crowe * you're watching all of this with dtrace. 27361eb4e906SKevin Crowe */ 27371eb4e906SKevin Crowe if ((dzp->z_mode & S_ISVTX) == 0) 27381eb4e906SKevin Crowe return (0); 27391eb4e906SKevin Crowe 27401eb4e906SKevin Crowe /* 27411eb4e906SKevin Crowe * zfs_sticky_remove_access will succeed if: 27421eb4e906SKevin Crowe * 1. The sticky bit is absent. 27431eb4e906SKevin Crowe * 2. We pass the sticky bit restrictions. 27441eb4e906SKevin Crowe * 3. We have privileges that always allow file removal. 27451eb4e906SKevin Crowe */ 27461eb4e906SKevin Crowe return (zfs_sticky_remove_access(dzp, zp, cr)); 2747fa9e4066Sahrens } 2748fa9e4066Sahrens 2749fa9e4066Sahrens int 2750fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2751fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2752fa9e4066Sahrens { 2753fa9e4066Sahrens int add_perm; 2754fa9e4066Sahrens int error; 2755fa9e4066Sahrens 27560a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED) 2757be6fd75aSMatthew Ahrens return (SET_ERROR(EACCES)); 2758da6c28aaSamw 2759fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2760fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2761fa9e4066Sahrens 2762fa9e4066Sahrens /* 2763fa9e4066Sahrens * Rename permissions are combination of delete permission + 2764fa9e4066Sahrens * add file/subdir permission. 2765fa9e4066Sahrens */ 2766fa9e4066Sahrens 2767fa9e4066Sahrens /* 2768fa9e4066Sahrens * first make sure we do the delete portion. 2769fa9e4066Sahrens * 2770fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2771fa9e4066Sahrens */ 2772fa9e4066Sahrens 2773fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2774fa9e4066Sahrens return (error); 2775fa9e4066Sahrens 2776fa9e4066Sahrens /* 2777fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2778fa9e4066Sahrens */ 2779fa9e4066Sahrens if (tzp) { 2780fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2781fa9e4066Sahrens return (error); 2782fa9e4066Sahrens } 2783fa9e4066Sahrens 2784fa9e4066Sahrens /* 2785fa9e4066Sahrens * Now check for add permissions 2786fa9e4066Sahrens */ 2787da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2788fa9e4066Sahrens 2789fa9e4066Sahrens return (error); 2790fa9e4066Sahrens } 2791