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 /* 22b3874165SJohn Harres * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/types.h> 27fa9e4066Sahrens #include <sys/param.h> 28fa9e4066Sahrens #include <sys/time.h> 29fa9e4066Sahrens #include <sys/systm.h> 30fa9e4066Sahrens #include <sys/sysmacros.h> 31fa9e4066Sahrens #include <sys/resource.h> 32fa9e4066Sahrens #include <sys/vfs.h> 33fa9e4066Sahrens #include <sys/vnode.h> 34da6c28aaSamw #include <sys/sid.h> 35fa9e4066Sahrens #include <sys/file.h> 36fa9e4066Sahrens #include <sys/stat.h> 37fa9e4066Sahrens #include <sys/kmem.h> 38fa9e4066Sahrens #include <sys/cmn_err.h> 39fa9e4066Sahrens #include <sys/errno.h> 40fa9e4066Sahrens #include <sys/unistd.h> 41169cdae2Smarks #include <sys/sdt.h> 42fa9e4066Sahrens #include <sys/fs/zfs.h> 43fa9e4066Sahrens #include <sys/mode.h> 44fa9e4066Sahrens #include <sys/policy.h> 45fa9e4066Sahrens #include <sys/zfs_znode.h> 46da6c28aaSamw #include <sys/zfs_fuid.h> 47fa9e4066Sahrens #include <sys/zfs_acl.h> 48fa9e4066Sahrens #include <sys/zfs_dir.h> 49fa9e4066Sahrens #include <sys/zfs_vfsops.h> 50fa9e4066Sahrens #include <sys/dmu.h> 51da6c28aaSamw #include <sys/dnode.h> 52fa9e4066Sahrens #include <sys/zap.h> 53*0a586ceaSMark Shellenbaum #include <sys/sa.h> 54fa9e4066Sahrens #include "fs/fs_subr.h" 55fa9e4066Sahrens #include <acl/acl_common.h> 56fa9e4066Sahrens 57fa9e4066Sahrens #define ALLOW ACE_ACCESS_ALLOWED_ACE_TYPE 58fa9e4066Sahrens #define DENY ACE_ACCESS_DENIED_ACE_TYPE 59da6c28aaSamw #define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE 60003c2582SMark Shellenbaum #define MIN_ACE_TYPE ALLOW 61fa9e4066Sahrens 62fa9e4066Sahrens #define OWNING_GROUP (ACE_GROUP|ACE_IDENTIFIER_GROUP) 63fa9e4066Sahrens #define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \ 64fa9e4066Sahrens ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE) 65fa9e4066Sahrens #define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \ 66fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 67fa9e4066Sahrens #define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \ 68fa9e4066Sahrens ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS) 69da6c28aaSamw 70da6c28aaSamw #define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \ 71da6c28aaSamw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \ 72da6c28aaSamw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \ 73da6c28aaSamw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE) 74da6c28aaSamw 75f52e0e2bSMark Shellenbaum #define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS) 76f52e0e2bSMark Shellenbaum #define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \ 77f52e0e2bSMark Shellenbaum ACE_DELETE|ACE_DELETE_CHILD) 78f52e0e2bSMark Shellenbaum #define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS) 79fa9e4066Sahrens 80fa9e4066Sahrens #define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 81fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 82fa9e4066Sahrens 83fa9e4066Sahrens #define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ 84fa9e4066Sahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE) 85fa9e4066Sahrens 86fa9e4066Sahrens #define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \ 87da6c28aaSamw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE) 88fa9e4066Sahrens 89b3d141f8Smarks #define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER) 90fa9e4066Sahrens 91da6c28aaSamw #define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\ 92da6c28aaSamw ZFS_ACL_PROTECTED) 93fa9e4066Sahrens 94da6c28aaSamw #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ 95da6c28aaSamw ZFS_ACL_OBJ_ACE) 96da6c28aaSamw 974929fd5eSTim Haley #define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) 984929fd5eSTim Haley 99da6c28aaSamw static uint16_t 100da6c28aaSamw zfs_ace_v0_get_type(void *acep) 101da6c28aaSamw { 102da6c28aaSamw return (((zfs_oldace_t *)acep)->z_type); 103da6c28aaSamw } 104da6c28aaSamw 105da6c28aaSamw static uint16_t 106da6c28aaSamw zfs_ace_v0_get_flags(void *acep) 107da6c28aaSamw { 108da6c28aaSamw return (((zfs_oldace_t *)acep)->z_flags); 109da6c28aaSamw } 110da6c28aaSamw 111da6c28aaSamw static uint32_t 112da6c28aaSamw zfs_ace_v0_get_mask(void *acep) 113da6c28aaSamw { 114da6c28aaSamw return (((zfs_oldace_t *)acep)->z_access_mask); 115da6c28aaSamw } 116da6c28aaSamw 117da6c28aaSamw static uint64_t 118da6c28aaSamw zfs_ace_v0_get_who(void *acep) 119da6c28aaSamw { 120da6c28aaSamw return (((zfs_oldace_t *)acep)->z_fuid); 121da6c28aaSamw } 122da6c28aaSamw 123da6c28aaSamw static void 124da6c28aaSamw zfs_ace_v0_set_type(void *acep, uint16_t type) 125da6c28aaSamw { 126da6c28aaSamw ((zfs_oldace_t *)acep)->z_type = type; 127da6c28aaSamw } 128da6c28aaSamw 129da6c28aaSamw static void 130da6c28aaSamw zfs_ace_v0_set_flags(void *acep, uint16_t flags) 131da6c28aaSamw { 132da6c28aaSamw ((zfs_oldace_t *)acep)->z_flags = flags; 133da6c28aaSamw } 134da6c28aaSamw 135da6c28aaSamw static void 136da6c28aaSamw zfs_ace_v0_set_mask(void *acep, uint32_t mask) 137da6c28aaSamw { 138da6c28aaSamw ((zfs_oldace_t *)acep)->z_access_mask = mask; 139da6c28aaSamw } 140da6c28aaSamw 141da6c28aaSamw static void 142da6c28aaSamw zfs_ace_v0_set_who(void *acep, uint64_t who) 143da6c28aaSamw { 144da6c28aaSamw ((zfs_oldace_t *)acep)->z_fuid = who; 145da6c28aaSamw } 146da6c28aaSamw 147da6c28aaSamw /*ARGSUSED*/ 148da6c28aaSamw static size_t 149da6c28aaSamw zfs_ace_v0_size(void *acep) 150da6c28aaSamw { 151da6c28aaSamw return (sizeof (zfs_oldace_t)); 152da6c28aaSamw } 153da6c28aaSamw 154da6c28aaSamw static size_t 155da6c28aaSamw zfs_ace_v0_abstract_size(void) 156da6c28aaSamw { 157da6c28aaSamw return (sizeof (zfs_oldace_t)); 158da6c28aaSamw } 159da6c28aaSamw 160da6c28aaSamw static int 161da6c28aaSamw zfs_ace_v0_mask_off(void) 162da6c28aaSamw { 163da6c28aaSamw return (offsetof(zfs_oldace_t, z_access_mask)); 164da6c28aaSamw } 165da6c28aaSamw 166da6c28aaSamw /*ARGSUSED*/ 167da6c28aaSamw static int 168da6c28aaSamw zfs_ace_v0_data(void *acep, void **datap) 169da6c28aaSamw { 170da6c28aaSamw *datap = NULL; 171da6c28aaSamw return (0); 172da6c28aaSamw } 173da6c28aaSamw 174da6c28aaSamw static acl_ops_t zfs_acl_v0_ops = { 175da6c28aaSamw zfs_ace_v0_get_mask, 176da6c28aaSamw zfs_ace_v0_set_mask, 177da6c28aaSamw zfs_ace_v0_get_flags, 178da6c28aaSamw zfs_ace_v0_set_flags, 179da6c28aaSamw zfs_ace_v0_get_type, 180da6c28aaSamw zfs_ace_v0_set_type, 181da6c28aaSamw zfs_ace_v0_get_who, 182da6c28aaSamw zfs_ace_v0_set_who, 183da6c28aaSamw zfs_ace_v0_size, 184da6c28aaSamw zfs_ace_v0_abstract_size, 185da6c28aaSamw zfs_ace_v0_mask_off, 186da6c28aaSamw zfs_ace_v0_data 187da6c28aaSamw }; 188da6c28aaSamw 189da6c28aaSamw static uint16_t 190da6c28aaSamw zfs_ace_fuid_get_type(void *acep) 191da6c28aaSamw { 192da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_type); 193da6c28aaSamw } 194da6c28aaSamw 195da6c28aaSamw static uint16_t 196da6c28aaSamw zfs_ace_fuid_get_flags(void *acep) 197da6c28aaSamw { 198da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_flags); 199da6c28aaSamw } 200da6c28aaSamw 201da6c28aaSamw static uint32_t 202da6c28aaSamw zfs_ace_fuid_get_mask(void *acep) 203da6c28aaSamw { 204da6c28aaSamw return (((zfs_ace_hdr_t *)acep)->z_access_mask); 205da6c28aaSamw } 206da6c28aaSamw 207da6c28aaSamw static uint64_t 208da6c28aaSamw zfs_ace_fuid_get_who(void *args) 209da6c28aaSamw { 210da6c28aaSamw uint16_t entry_type; 211da6c28aaSamw zfs_ace_t *acep = args; 212da6c28aaSamw 213da6c28aaSamw entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 214da6c28aaSamw 215da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 216da6c28aaSamw entry_type == ACE_EVERYONE) 217da6c28aaSamw return (-1); 218da6c28aaSamw return (((zfs_ace_t *)acep)->z_fuid); 219da6c28aaSamw } 220da6c28aaSamw 221da6c28aaSamw static void 222da6c28aaSamw zfs_ace_fuid_set_type(void *acep, uint16_t type) 223da6c28aaSamw { 224da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_type = type; 225da6c28aaSamw } 226da6c28aaSamw 227da6c28aaSamw static void 228da6c28aaSamw zfs_ace_fuid_set_flags(void *acep, uint16_t flags) 229da6c28aaSamw { 230da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_flags = flags; 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw static void 234da6c28aaSamw zfs_ace_fuid_set_mask(void *acep, uint32_t mask) 235da6c28aaSamw { 236da6c28aaSamw ((zfs_ace_hdr_t *)acep)->z_access_mask = mask; 237da6c28aaSamw } 238da6c28aaSamw 239da6c28aaSamw static void 240da6c28aaSamw zfs_ace_fuid_set_who(void *arg, uint64_t who) 241da6c28aaSamw { 242da6c28aaSamw zfs_ace_t *acep = arg; 243da6c28aaSamw 244da6c28aaSamw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS; 245da6c28aaSamw 246da6c28aaSamw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP || 247da6c28aaSamw entry_type == ACE_EVERYONE) 248da6c28aaSamw return; 249da6c28aaSamw acep->z_fuid = who; 250da6c28aaSamw } 251da6c28aaSamw 252da6c28aaSamw static size_t 253da6c28aaSamw zfs_ace_fuid_size(void *acep) 254da6c28aaSamw { 255da6c28aaSamw zfs_ace_hdr_t *zacep = acep; 256da6c28aaSamw uint16_t entry_type; 257da6c28aaSamw 258da6c28aaSamw switch (zacep->z_type) { 259da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 260da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 261da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 262da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 263da6c28aaSamw return (sizeof (zfs_object_ace_t)); 264da6c28aaSamw case ALLOW: 265da6c28aaSamw case DENY: 266da6c28aaSamw entry_type = 267da6c28aaSamw (((zfs_ace_hdr_t *)acep)->z_flags & ACE_TYPE_FLAGS); 268da6c28aaSamw if (entry_type == ACE_OWNER || 2691ab99678SMark Shellenbaum entry_type == OWNING_GROUP || 270da6c28aaSamw entry_type == ACE_EVERYONE) 271da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 272da6c28aaSamw /*FALLTHROUGH*/ 273da6c28aaSamw default: 274da6c28aaSamw return (sizeof (zfs_ace_t)); 275da6c28aaSamw } 276da6c28aaSamw } 277da6c28aaSamw 278da6c28aaSamw static size_t 279da6c28aaSamw zfs_ace_fuid_abstract_size(void) 280da6c28aaSamw { 281da6c28aaSamw return (sizeof (zfs_ace_hdr_t)); 282da6c28aaSamw } 283da6c28aaSamw 284da6c28aaSamw static int 285da6c28aaSamw zfs_ace_fuid_mask_off(void) 286da6c28aaSamw { 287da6c28aaSamw return (offsetof(zfs_ace_hdr_t, z_access_mask)); 288da6c28aaSamw } 289da6c28aaSamw 290da6c28aaSamw static int 291da6c28aaSamw zfs_ace_fuid_data(void *acep, void **datap) 292da6c28aaSamw { 293da6c28aaSamw zfs_ace_t *zacep = acep; 294da6c28aaSamw zfs_object_ace_t *zobjp; 295da6c28aaSamw 296da6c28aaSamw switch (zacep->z_hdr.z_type) { 297da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 298da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 299da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 300da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 301da6c28aaSamw zobjp = acep; 302da6c28aaSamw *datap = (caddr_t)zobjp + sizeof (zfs_ace_t); 303da6c28aaSamw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t)); 304da6c28aaSamw default: 305da6c28aaSamw *datap = NULL; 306da6c28aaSamw return (0); 307da6c28aaSamw } 308da6c28aaSamw } 309da6c28aaSamw 310da6c28aaSamw static acl_ops_t zfs_acl_fuid_ops = { 311da6c28aaSamw zfs_ace_fuid_get_mask, 312da6c28aaSamw zfs_ace_fuid_set_mask, 313da6c28aaSamw zfs_ace_fuid_get_flags, 314da6c28aaSamw zfs_ace_fuid_set_flags, 315da6c28aaSamw zfs_ace_fuid_get_type, 316da6c28aaSamw zfs_ace_fuid_set_type, 317da6c28aaSamw zfs_ace_fuid_get_who, 318da6c28aaSamw zfs_ace_fuid_set_who, 319da6c28aaSamw zfs_ace_fuid_size, 320da6c28aaSamw zfs_ace_fuid_abstract_size, 321da6c28aaSamw zfs_ace_fuid_mask_off, 322da6c28aaSamw zfs_ace_fuid_data 323da6c28aaSamw }; 324da6c28aaSamw 325*0a586ceaSMark Shellenbaum /* 326*0a586ceaSMark Shellenbaum * The following three functions are provided for compatibility with 327*0a586ceaSMark Shellenbaum * older ZPL version in order to determine if the file use to have 328*0a586ceaSMark Shellenbaum * an external ACL and what version of ACL previously existed on the 329*0a586ceaSMark Shellenbaum * file. Would really be nice to not need this, sigh. 330*0a586ceaSMark Shellenbaum */ 331*0a586ceaSMark Shellenbaum 332*0a586ceaSMark Shellenbaum uint64_t 333*0a586ceaSMark Shellenbaum zfs_external_acl(znode_t *zp) 334*0a586ceaSMark Shellenbaum { 335*0a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 336*0a586ceaSMark Shellenbaum 337*0a586ceaSMark Shellenbaum if (zp->z_is_sa) 338*0a586ceaSMark Shellenbaum return (0); 339*0a586ceaSMark Shellenbaum 340*0a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 341*0a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))); 342*0a586ceaSMark Shellenbaum 343*0a586ceaSMark Shellenbaum return (acl_phys.z_acl_extern_obj); 344*0a586ceaSMark Shellenbaum } 345*0a586ceaSMark Shellenbaum 346*0a586ceaSMark Shellenbaum /* 347*0a586ceaSMark Shellenbaum * Determine size of ACL in bytes 348*0a586ceaSMark Shellenbaum * 349*0a586ceaSMark Shellenbaum * This is more complicated than it should be since we have to deal 350*0a586ceaSMark Shellenbaum * with old external ACLs. 351*0a586ceaSMark Shellenbaum */ 352*0a586ceaSMark Shellenbaum static int 353*0a586ceaSMark Shellenbaum zfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount, 354*0a586ceaSMark Shellenbaum zfs_acl_phys_t *aclphys) 355*0a586ceaSMark Shellenbaum { 356*0a586ceaSMark Shellenbaum zfsvfs_t *zfsvfs = zp->z_zfsvfs; 357*0a586ceaSMark Shellenbaum uint64_t acl_count; 358*0a586ceaSMark Shellenbaum int size; 359*0a586ceaSMark Shellenbaum int error; 360*0a586ceaSMark Shellenbaum 361*0a586ceaSMark Shellenbaum if (zp->z_is_sa) { 362*0a586ceaSMark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs), 363*0a586ceaSMark Shellenbaum &size)) != 0) 364*0a586ceaSMark Shellenbaum return (error); 365*0a586ceaSMark Shellenbaum *aclsize = size; 366*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs), 367*0a586ceaSMark Shellenbaum &acl_count, sizeof (acl_count))) != 0) 368*0a586ceaSMark Shellenbaum return (error); 369*0a586ceaSMark Shellenbaum *aclcount = acl_count; 370*0a586ceaSMark Shellenbaum } else { 371*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 372*0a586ceaSMark Shellenbaum aclphys, sizeof (*aclphys))) != 0) 373*0a586ceaSMark Shellenbaum return (error); 374*0a586ceaSMark Shellenbaum 375*0a586ceaSMark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) { 376*0a586ceaSMark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size); 377*0a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_size; 378*0a586ceaSMark Shellenbaum } else { 379*0a586ceaSMark Shellenbaum *aclsize = aclphys->z_acl_size; 380*0a586ceaSMark Shellenbaum *aclcount = aclphys->z_acl_count; 381*0a586ceaSMark Shellenbaum } 382*0a586ceaSMark Shellenbaum } 383*0a586ceaSMark Shellenbaum return (0); 384*0a586ceaSMark Shellenbaum } 385*0a586ceaSMark Shellenbaum 386*0a586ceaSMark Shellenbaum int 387*0a586ceaSMark Shellenbaum zfs_znode_acl_version(znode_t *zp) 388*0a586ceaSMark Shellenbaum { 389*0a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 390*0a586ceaSMark Shellenbaum 391*0a586ceaSMark Shellenbaum if (zp->z_is_sa) { 392*0a586ceaSMark Shellenbaum return (ZFS_ACL_VERSION_FUID); 393*0a586ceaSMark Shellenbaum } else { 394*0a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(zp->z_sa_hdl, 395*0a586ceaSMark Shellenbaum SA_ZPL_ZNODE_ACL(zp->z_zfsvfs), 396*0a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))); 397*0a586ceaSMark Shellenbaum return (acl_phys.z_acl_version); 398*0a586ceaSMark Shellenbaum } 399*0a586ceaSMark Shellenbaum } 400*0a586ceaSMark Shellenbaum 401da6c28aaSamw static int 402da6c28aaSamw zfs_acl_version(int version) 403da6c28aaSamw { 404da6c28aaSamw if (version < ZPL_VERSION_FUID) 405da6c28aaSamw return (ZFS_ACL_VERSION_INITIAL); 406da6c28aaSamw else 407da6c28aaSamw return (ZFS_ACL_VERSION_FUID); 408da6c28aaSamw } 409da6c28aaSamw 410da6c28aaSamw static int 411da6c28aaSamw zfs_acl_version_zp(znode_t *zp) 412da6c28aaSamw { 413da6c28aaSamw return (zfs_acl_version(zp->z_zfsvfs->z_version)); 414da6c28aaSamw } 415fa9e4066Sahrens 416*0a586ceaSMark Shellenbaum zfs_acl_t * 417da6c28aaSamw zfs_acl_alloc(int vers) 418fa9e4066Sahrens { 419fa9e4066Sahrens zfs_acl_t *aclp; 420fa9e4066Sahrens 421fa9e4066Sahrens aclp = kmem_zalloc(sizeof (zfs_acl_t), KM_SLEEP); 422da6c28aaSamw list_create(&aclp->z_acl, sizeof (zfs_acl_node_t), 423da6c28aaSamw offsetof(zfs_acl_node_t, z_next)); 424da6c28aaSamw aclp->z_version = vers; 425da6c28aaSamw if (vers == ZFS_ACL_VERSION_FUID) 426da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 427da6c28aaSamw else 428da6c28aaSamw aclp->z_ops = zfs_acl_v0_ops; 429fa9e4066Sahrens return (aclp); 430fa9e4066Sahrens } 431fa9e4066Sahrens 432*0a586ceaSMark Shellenbaum zfs_acl_node_t * 433da6c28aaSamw zfs_acl_node_alloc(size_t bytes) 434da6c28aaSamw { 435da6c28aaSamw zfs_acl_node_t *aclnode; 436da6c28aaSamw 437da6c28aaSamw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP); 438da6c28aaSamw if (bytes) { 439da6c28aaSamw aclnode->z_acldata = kmem_alloc(bytes, KM_SLEEP); 440da6c28aaSamw aclnode->z_allocdata = aclnode->z_acldata; 441da6c28aaSamw aclnode->z_allocsize = bytes; 442da6c28aaSamw aclnode->z_size = bytes; 443da6c28aaSamw } 444da6c28aaSamw 445da6c28aaSamw return (aclnode); 446da6c28aaSamw } 447da6c28aaSamw 448da6c28aaSamw static void 449da6c28aaSamw zfs_acl_node_free(zfs_acl_node_t *aclnode) 450da6c28aaSamw { 451da6c28aaSamw if (aclnode->z_allocsize) 452da6c28aaSamw kmem_free(aclnode->z_allocdata, aclnode->z_allocsize); 453da6c28aaSamw kmem_free(aclnode, sizeof (zfs_acl_node_t)); 454da6c28aaSamw } 455da6c28aaSamw 4562459a9eaSmarks static void 4572459a9eaSmarks zfs_acl_release_nodes(zfs_acl_t *aclp) 458fa9e4066Sahrens { 459da6c28aaSamw zfs_acl_node_t *aclnode; 460da6c28aaSamw 461da6c28aaSamw while (aclnode = list_head(&aclp->z_acl)) { 462da6c28aaSamw list_remove(&aclp->z_acl, aclnode); 463da6c28aaSamw zfs_acl_node_free(aclnode); 464fa9e4066Sahrens } 4652459a9eaSmarks aclp->z_acl_count = 0; 4662459a9eaSmarks aclp->z_acl_bytes = 0; 4672459a9eaSmarks } 468da6c28aaSamw 4692459a9eaSmarks void 4702459a9eaSmarks zfs_acl_free(zfs_acl_t *aclp) 4712459a9eaSmarks { 4722459a9eaSmarks zfs_acl_release_nodes(aclp); 473da6c28aaSamw list_destroy(&aclp->z_acl); 474fa9e4066Sahrens kmem_free(aclp, sizeof (zfs_acl_t)); 475fa9e4066Sahrens } 476fa9e4066Sahrens 477da6c28aaSamw static boolean_t 478003c2582SMark Shellenbaum zfs_acl_valid_ace_type(uint_t type, uint_t flags) 479003c2582SMark Shellenbaum { 480003c2582SMark Shellenbaum uint16_t entry_type; 481003c2582SMark Shellenbaum 482003c2582SMark Shellenbaum switch (type) { 483003c2582SMark Shellenbaum case ALLOW: 484003c2582SMark Shellenbaum case DENY: 485003c2582SMark Shellenbaum case ACE_SYSTEM_AUDIT_ACE_TYPE: 486003c2582SMark Shellenbaum case ACE_SYSTEM_ALARM_ACE_TYPE: 487003c2582SMark Shellenbaum entry_type = flags & ACE_TYPE_FLAGS; 488003c2582SMark Shellenbaum return (entry_type == ACE_OWNER || 489003c2582SMark Shellenbaum entry_type == OWNING_GROUP || 490003c2582SMark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 || 491003c2582SMark Shellenbaum entry_type == ACE_IDENTIFIER_GROUP); 492003c2582SMark Shellenbaum default: 493003c2582SMark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE) 494003c2582SMark Shellenbaum return (B_TRUE); 495003c2582SMark Shellenbaum } 496003c2582SMark Shellenbaum return (B_FALSE); 497003c2582SMark Shellenbaum } 498003c2582SMark Shellenbaum 499003c2582SMark Shellenbaum static boolean_t 500da6c28aaSamw zfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags) 501fa9e4066Sahrens { 502da6c28aaSamw /* 503da6c28aaSamw * first check type of entry 504da6c28aaSamw */ 505da6c28aaSamw 506003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 507da6c28aaSamw return (B_FALSE); 508da6c28aaSamw 509da6c28aaSamw switch (type) { 510da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 511da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 512da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 513da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 514da6c28aaSamw if (aclp->z_version < ZFS_ACL_VERSION_FUID) 515da6c28aaSamw return (B_FALSE); 516da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 517da6c28aaSamw } 518da6c28aaSamw 519003c2582SMark Shellenbaum /* 520003c2582SMark Shellenbaum * next check inheritance level flags 521003c2582SMark Shellenbaum */ 522003c2582SMark Shellenbaum 523b249c65cSmarks if (obj_type == VDIR && 524b249c65cSmarks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))) 525da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 526da6c28aaSamw 527da6c28aaSamw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) { 528da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE| 529da6c28aaSamw ACE_DIRECTORY_INHERIT_ACE)) == 0) { 530da6c28aaSamw return (B_FALSE); 531da6c28aaSamw } 532da6c28aaSamw } 533da6c28aaSamw 534da6c28aaSamw return (B_TRUE); 535da6c28aaSamw } 536da6c28aaSamw 537da6c28aaSamw static void * 538da6c28aaSamw zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, 539da6c28aaSamw uint32_t *access_mask, uint16_t *iflags, uint16_t *type) 540da6c28aaSamw { 541da6c28aaSamw zfs_acl_node_t *aclnode; 542da6c28aaSamw 543*0a586ceaSMark Shellenbaum ASSERT(aclp); 544*0a586ceaSMark Shellenbaum 545da6c28aaSamw if (start == NULL) { 546da6c28aaSamw aclnode = list_head(&aclp->z_acl); 547da6c28aaSamw if (aclnode == NULL) 548da6c28aaSamw return (NULL); 549da6c28aaSamw 550da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 551da6c28aaSamw aclp->z_curr_node = aclnode; 552da6c28aaSamw aclnode->z_ace_idx = 0; 553da6c28aaSamw } 554da6c28aaSamw 555da6c28aaSamw aclnode = aclp->z_curr_node; 556da6c28aaSamw 557da6c28aaSamw if (aclnode == NULL) 558da6c28aaSamw return (NULL); 559da6c28aaSamw 560da6c28aaSamw if (aclnode->z_ace_idx >= aclnode->z_ace_count) { 561da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode); 562da6c28aaSamw if (aclnode == NULL) 563da6c28aaSamw return (NULL); 564da6c28aaSamw else { 565da6c28aaSamw aclp->z_curr_node = aclnode; 566da6c28aaSamw aclnode->z_ace_idx = 0; 567da6c28aaSamw aclp->z_next_ace = aclnode->z_acldata; 568da6c28aaSamw } 569da6c28aaSamw } 570da6c28aaSamw 571da6c28aaSamw if (aclnode->z_ace_idx < aclnode->z_ace_count) { 572da6c28aaSamw void *acep = aclp->z_next_ace; 573003c2582SMark Shellenbaum size_t ace_size; 574003c2582SMark Shellenbaum 575003c2582SMark Shellenbaum /* 576003c2582SMark Shellenbaum * Make sure we don't overstep our bounds 577003c2582SMark Shellenbaum */ 578003c2582SMark Shellenbaum ace_size = aclp->z_ops.ace_size(acep); 579003c2582SMark Shellenbaum 580003c2582SMark Shellenbaum if (((caddr_t)acep + ace_size) > 581003c2582SMark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) { 582003c2582SMark Shellenbaum return (NULL); 583003c2582SMark Shellenbaum } 584003c2582SMark Shellenbaum 585da6c28aaSamw *iflags = aclp->z_ops.ace_flags_get(acep); 586da6c28aaSamw *type = aclp->z_ops.ace_type_get(acep); 587da6c28aaSamw *access_mask = aclp->z_ops.ace_mask_get(acep); 588da6c28aaSamw *who = aclp->z_ops.ace_who_get(acep); 589003c2582SMark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size; 590da6c28aaSamw aclnode->z_ace_idx++; 591*0a586ceaSMark Shellenbaum 592da6c28aaSamw return ((void *)acep); 593da6c28aaSamw } 594da6c28aaSamw return (NULL); 595da6c28aaSamw } 596da6c28aaSamw 597da6c28aaSamw /*ARGSUSED*/ 598da6c28aaSamw static uint64_t 599da6c28aaSamw zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, 600da6c28aaSamw uint16_t *flags, uint16_t *type, uint32_t *mask) 601da6c28aaSamw { 602da6c28aaSamw zfs_acl_t *aclp = datap; 603da6c28aaSamw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; 604da6c28aaSamw uint64_t who; 605da6c28aaSamw 606da6c28aaSamw acep = zfs_acl_next_ace(aclp, acep, &who, mask, 607da6c28aaSamw flags, type); 608da6c28aaSamw return ((uint64_t)(uintptr_t)acep); 609da6c28aaSamw } 610da6c28aaSamw 611da6c28aaSamw static zfs_acl_node_t * 612da6c28aaSamw zfs_acl_curr_node(zfs_acl_t *aclp) 613da6c28aaSamw { 614da6c28aaSamw ASSERT(aclp->z_curr_node); 615da6c28aaSamw return (aclp->z_curr_node); 616da6c28aaSamw } 617da6c28aaSamw 618da6c28aaSamw /* 619da6c28aaSamw * Copy ACE to internal ZFS format. 620da6c28aaSamw * While processing the ACL each ACE will be validated for correctness. 621da6c28aaSamw * ACE FUIDs will be created later. 622da6c28aaSamw */ 623da6c28aaSamw int 62489459e17SMark Shellenbaum zfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp, 625*0a586ceaSMark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size, 62689459e17SMark Shellenbaum zfs_fuid_info_t **fuidp, cred_t *cr) 627da6c28aaSamw { 628da6c28aaSamw int i; 629da6c28aaSamw uint16_t entry_type; 630da6c28aaSamw zfs_ace_t *aceptr = z_acl; 631da6c28aaSamw ace_t *acep = datap; 632da6c28aaSamw zfs_object_ace_t *zobjacep; 633da6c28aaSamw ace_object_t *aceobjp; 634da6c28aaSamw 635da6c28aaSamw for (i = 0; i != aclcnt; i++) { 636da6c28aaSamw aceptr->z_hdr.z_access_mask = acep->a_access_mask; 637da6c28aaSamw aceptr->z_hdr.z_flags = acep->a_flags; 638da6c28aaSamw aceptr->z_hdr.z_type = acep->a_type; 639da6c28aaSamw entry_type = aceptr->z_hdr.z_flags & ACE_TYPE_FLAGS; 640da6c28aaSamw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP && 6414c841f60Smarks entry_type != ACE_EVERYONE) { 64289459e17SMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who, 64389459e17SMark Shellenbaum cr, (entry_type == 0) ? 64489459e17SMark Shellenbaum ZFS_ACE_USER : ZFS_ACE_GROUP, fuidp); 6454c841f60Smarks } 6464c841f60Smarks 647da6c28aaSamw /* 648da6c28aaSamw * Make sure ACE is valid 649da6c28aaSamw */ 650da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_hdr.z_type, 651da6c28aaSamw aceptr->z_hdr.z_flags) != B_TRUE) 652da6c28aaSamw return (EINVAL); 653da6c28aaSamw 654da6c28aaSamw switch (acep->a_type) { 655da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 656da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 657da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 658da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 659da6c28aaSamw zobjacep = (zfs_object_ace_t *)aceptr; 660da6c28aaSamw aceobjp = (ace_object_t *)acep; 661da6c28aaSamw 662da6c28aaSamw bcopy(aceobjp->a_obj_type, zobjacep->z_object_type, 663da6c28aaSamw sizeof (aceobjp->a_obj_type)); 664da6c28aaSamw bcopy(aceobjp->a_inherit_obj_type, 665da6c28aaSamw zobjacep->z_inherit_type, 666da6c28aaSamw sizeof (aceobjp->a_inherit_obj_type)); 667da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t)); 668da6c28aaSamw break; 669da6c28aaSamw default: 670da6c28aaSamw acep = (ace_t *)((caddr_t)acep + sizeof (ace_t)); 671da6c28aaSamw } 672da6c28aaSamw 673da6c28aaSamw aceptr = (zfs_ace_t *)((caddr_t)aceptr + 674da6c28aaSamw aclp->z_ops.ace_size(aceptr)); 675da6c28aaSamw } 676da6c28aaSamw 677da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 678da6c28aaSamw 679da6c28aaSamw return (0); 680da6c28aaSamw } 681da6c28aaSamw 682da6c28aaSamw /* 683da6c28aaSamw * Copy ZFS ACEs to fixed size ace_t layout 684da6c28aaSamw */ 685da6c28aaSamw static void 686bda89588Sjp151216 zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr, 687bda89588Sjp151216 void *datap, int filter) 688da6c28aaSamw { 689da6c28aaSamw uint64_t who; 690da6c28aaSamw uint32_t access_mask; 691da6c28aaSamw uint16_t iflags, type; 692da6c28aaSamw zfs_ace_hdr_t *zacep = NULL; 693da6c28aaSamw ace_t *acep = datap; 694da6c28aaSamw ace_object_t *objacep; 695da6c28aaSamw zfs_object_ace_t *zobjacep; 696da6c28aaSamw size_t ace_size; 697da6c28aaSamw uint16_t entry_type; 698da6c28aaSamw 699da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 700da6c28aaSamw &who, &access_mask, &iflags, &type)) { 701da6c28aaSamw 702da6c28aaSamw switch (type) { 703da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 704da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 705da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 706da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 707da6c28aaSamw if (filter) { 708da6c28aaSamw continue; 709da6c28aaSamw } 710da6c28aaSamw zobjacep = (zfs_object_ace_t *)zacep; 711da6c28aaSamw objacep = (ace_object_t *)acep; 712da6c28aaSamw bcopy(zobjacep->z_object_type, 713da6c28aaSamw objacep->a_obj_type, 714da6c28aaSamw sizeof (zobjacep->z_object_type)); 715da6c28aaSamw bcopy(zobjacep->z_inherit_type, 716da6c28aaSamw objacep->a_inherit_obj_type, 717da6c28aaSamw sizeof (zobjacep->z_inherit_type)); 718da6c28aaSamw ace_size = sizeof (ace_object_t); 719da6c28aaSamw break; 720da6c28aaSamw default: 721da6c28aaSamw ace_size = sizeof (ace_t); 722da6c28aaSamw break; 723da6c28aaSamw } 724da6c28aaSamw 725da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 726da6c28aaSamw if ((entry_type != ACE_OWNER && 7271ab99678SMark Shellenbaum entry_type != OWNING_GROUP && 728e0d35c44Smarks entry_type != ACE_EVERYONE)) { 729e0d35c44Smarks acep->a_who = zfs_fuid_map_id(zfsvfs, who, 730e0d35c44Smarks cr, (entry_type & ACE_IDENTIFIER_GROUP) ? 731e0d35c44Smarks ZFS_ACE_GROUP : ZFS_ACE_USER); 732e0d35c44Smarks } else { 733da6c28aaSamw acep->a_who = (uid_t)(int64_t)who; 734e0d35c44Smarks } 735da6c28aaSamw acep->a_access_mask = access_mask; 736da6c28aaSamw acep->a_flags = iflags; 737da6c28aaSamw acep->a_type = type; 738da6c28aaSamw acep = (ace_t *)((caddr_t)acep + ace_size); 739da6c28aaSamw } 740da6c28aaSamw } 741da6c28aaSamw 742da6c28aaSamw static int 743da6c28aaSamw zfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep, 744da6c28aaSamw zfs_oldace_t *z_acl, int aclcnt, size_t *size) 745da6c28aaSamw { 746da6c28aaSamw int i; 747da6c28aaSamw zfs_oldace_t *aceptr = z_acl; 748da6c28aaSamw 749da6c28aaSamw for (i = 0; i != aclcnt; i++, aceptr++) { 750da6c28aaSamw aceptr->z_access_mask = acep[i].a_access_mask; 751da6c28aaSamw aceptr->z_type = acep[i].a_type; 752da6c28aaSamw aceptr->z_flags = acep[i].a_flags; 753da6c28aaSamw aceptr->z_fuid = acep[i].a_who; 754da6c28aaSamw /* 755da6c28aaSamw * Make sure ACE is valid 756da6c28aaSamw */ 757da6c28aaSamw if (zfs_ace_valid(obj_type, aclp, aceptr->z_type, 758da6c28aaSamw aceptr->z_flags) != B_TRUE) 759da6c28aaSamw return (EINVAL); 760da6c28aaSamw } 761da6c28aaSamw *size = (caddr_t)aceptr - (caddr_t)z_acl; 762da6c28aaSamw return (0); 763da6c28aaSamw } 764da6c28aaSamw 765da6c28aaSamw /* 766da6c28aaSamw * convert old ACL format to new 767da6c28aaSamw */ 768da6c28aaSamw void 76989459e17SMark Shellenbaum zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr) 770da6c28aaSamw { 771da6c28aaSamw zfs_oldace_t *oldaclp; 772da6c28aaSamw int i; 773da6c28aaSamw uint16_t type, iflags; 774da6c28aaSamw uint32_t access_mask; 775da6c28aaSamw uint64_t who; 776da6c28aaSamw void *cookie = NULL; 7772459a9eaSmarks zfs_acl_node_t *newaclnode; 778da6c28aaSamw 779da6c28aaSamw ASSERT(aclp->z_version == ZFS_ACL_VERSION_INITIAL); 780da6c28aaSamw /* 781da6c28aaSamw * First create the ACE in a contiguous piece of memory 782da6c28aaSamw * for zfs_copy_ace_2_fuid(). 783da6c28aaSamw * 784da6c28aaSamw * We only convert an ACL once, so this won't happen 785da6c28aaSamw * everytime. 786da6c28aaSamw */ 787da6c28aaSamw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count, 788da6c28aaSamw KM_SLEEP); 789da6c28aaSamw i = 0; 790da6c28aaSamw while (cookie = zfs_acl_next_ace(aclp, cookie, &who, 791da6c28aaSamw &access_mask, &iflags, &type)) { 792da6c28aaSamw oldaclp[i].z_flags = iflags; 793da6c28aaSamw oldaclp[i].z_type = type; 794da6c28aaSamw oldaclp[i].z_fuid = who; 795da6c28aaSamw oldaclp[i++].z_access_mask = access_mask; 796da6c28aaSamw } 797da6c28aaSamw 798da6c28aaSamw newaclnode = zfs_acl_node_alloc(aclp->z_acl_count * 799da6c28aaSamw sizeof (zfs_object_ace_t)); 800da6c28aaSamw aclp->z_ops = zfs_acl_fuid_ops; 80189459e17SMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp, 80289459e17SMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count, 80389459e17SMark Shellenbaum &newaclnode->z_size, NULL, cr) == 0); 804da6c28aaSamw newaclnode->z_ace_count = aclp->z_acl_count; 805da6c28aaSamw aclp->z_version = ZFS_ACL_VERSION; 806da6c28aaSamw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t)); 807da6c28aaSamw 808da6c28aaSamw /* 809da6c28aaSamw * Release all previous ACL nodes 810da6c28aaSamw */ 811da6c28aaSamw 8122459a9eaSmarks zfs_acl_release_nodes(aclp); 8132459a9eaSmarks 814da6c28aaSamw list_insert_head(&aclp->z_acl, newaclnode); 8152459a9eaSmarks 8162459a9eaSmarks aclp->z_acl_bytes = newaclnode->z_size; 8172459a9eaSmarks aclp->z_acl_count = newaclnode->z_ace_count; 8182459a9eaSmarks 819fa9e4066Sahrens } 820fa9e4066Sahrens 821fa9e4066Sahrens /* 822fa9e4066Sahrens * Convert unix access mask to v4 access mask 823fa9e4066Sahrens */ 824fa9e4066Sahrens static uint32_t 825fa9e4066Sahrens zfs_unix_to_v4(uint32_t access_mask) 826fa9e4066Sahrens { 827fa9e4066Sahrens uint32_t new_mask = 0; 828fa9e4066Sahrens 829da6c28aaSamw if (access_mask & S_IXOTH) 830da6c28aaSamw new_mask |= ACE_EXECUTE; 831da6c28aaSamw if (access_mask & S_IWOTH) 832da6c28aaSamw new_mask |= ACE_WRITE_DATA; 833da6c28aaSamw if (access_mask & S_IROTH) 834fa9e4066Sahrens new_mask |= ACE_READ_DATA; 835fa9e4066Sahrens return (new_mask); 836fa9e4066Sahrens } 837fa9e4066Sahrens 838fa9e4066Sahrens static void 839da6c28aaSamw zfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask, 840da6c28aaSamw uint16_t access_type, uint64_t fuid, uint16_t entry_type) 841fa9e4066Sahrens { 842da6c28aaSamw uint16_t type = entry_type & ACE_TYPE_FLAGS; 843da6c28aaSamw 844da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 845da6c28aaSamw aclp->z_ops.ace_type_set(acep, access_type); 846da6c28aaSamw aclp->z_ops.ace_flags_set(acep, entry_type); 8471ab99678SMark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP && 848da6c28aaSamw type != ACE_EVERYONE)) 849da6c28aaSamw aclp->z_ops.ace_who_set(acep, fuid); 850fa9e4066Sahrens } 851fa9e4066Sahrens 852da6c28aaSamw /* 853da6c28aaSamw * Determine mode of file based on ACL. 854da6c28aaSamw * Also, create FUIDs for any User/Group ACEs 855da6c28aaSamw */ 856*0a586ceaSMark Shellenbaum uint64_t 857*0a586ceaSMark Shellenbaum zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp, uint64_t *pflags) 858fa9e4066Sahrens { 859fa9e4066Sahrens int entry_type; 860da6c28aaSamw mode_t mode; 861fa9e4066Sahrens mode_t seen = 0; 862da6c28aaSamw zfs_ace_hdr_t *acep = NULL; 863da6c28aaSamw uint64_t who; 864da6c28aaSamw uint16_t iflags, type; 865da6c28aaSamw uint32_t access_mask; 866d47621a4STim Haley boolean_t an_exec_denied = B_FALSE; 867fa9e4066Sahrens 868*0a586ceaSMark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); 869da6c28aaSamw 870da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, 871da6c28aaSamw &access_mask, &iflags, &type)) { 87229a0b737Smarks 873003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 874003c2582SMark Shellenbaum continue; 875003c2582SMark Shellenbaum 876e6032be1Smarks entry_type = (iflags & ACE_TYPE_FLAGS); 877e6032be1Smarks 8781ab99678SMark Shellenbaum /* 8791ab99678SMark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs 8801ab99678SMark Shellenbaum */ 8811ab99678SMark Shellenbaum if ((iflags & ACE_INHERIT_ONLY_ACE) && 8821ab99678SMark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 8831ab99678SMark Shellenbaum entry_type == OWNING_GROUP)) 8841ab99678SMark Shellenbaum continue; 8851ab99678SMark Shellenbaum 886fa9e4066Sahrens if (entry_type == ACE_OWNER) { 887da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 888fa9e4066Sahrens (!(seen & S_IRUSR))) { 889fa9e4066Sahrens seen |= S_IRUSR; 890da6c28aaSamw if (type == ALLOW) { 891fa9e4066Sahrens mode |= S_IRUSR; 892fa9e4066Sahrens } 893fa9e4066Sahrens } 894da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 895fa9e4066Sahrens (!(seen & S_IWUSR))) { 896fa9e4066Sahrens seen |= S_IWUSR; 897da6c28aaSamw if (type == ALLOW) { 898fa9e4066Sahrens mode |= S_IWUSR; 899fa9e4066Sahrens } 900fa9e4066Sahrens } 901da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 902fa9e4066Sahrens (!(seen & S_IXUSR))) { 903fa9e4066Sahrens seen |= S_IXUSR; 904da6c28aaSamw if (type == ALLOW) { 905fa9e4066Sahrens mode |= S_IXUSR; 906fa9e4066Sahrens } 907fa9e4066Sahrens } 908fa9e4066Sahrens } else if (entry_type == OWNING_GROUP) { 909da6c28aaSamw if ((access_mask & ACE_READ_DATA) && 910fa9e4066Sahrens (!(seen & S_IRGRP))) { 911fa9e4066Sahrens seen |= S_IRGRP; 912da6c28aaSamw if (type == ALLOW) { 913fa9e4066Sahrens mode |= S_IRGRP; 914fa9e4066Sahrens } 915fa9e4066Sahrens } 916da6c28aaSamw if ((access_mask & ACE_WRITE_DATA) && 917fa9e4066Sahrens (!(seen & S_IWGRP))) { 918fa9e4066Sahrens seen |= S_IWGRP; 919da6c28aaSamw if (type == ALLOW) { 920fa9e4066Sahrens mode |= S_IWGRP; 921fa9e4066Sahrens } 922fa9e4066Sahrens } 923da6c28aaSamw if ((access_mask & ACE_EXECUTE) && 924fa9e4066Sahrens (!(seen & S_IXGRP))) { 925fa9e4066Sahrens seen |= S_IXGRP; 926da6c28aaSamw if (type == ALLOW) { 927fa9e4066Sahrens mode |= S_IXGRP; 928fa9e4066Sahrens } 929fa9e4066Sahrens } 930fa9e4066Sahrens } else if (entry_type == ACE_EVERYONE) { 931da6c28aaSamw if ((access_mask & ACE_READ_DATA)) { 932fa9e4066Sahrens if (!(seen & S_IRUSR)) { 933fa9e4066Sahrens seen |= S_IRUSR; 934da6c28aaSamw if (type == ALLOW) { 935fa9e4066Sahrens mode |= S_IRUSR; 936fa9e4066Sahrens } 937fa9e4066Sahrens } 938fa9e4066Sahrens if (!(seen & S_IRGRP)) { 939fa9e4066Sahrens seen |= S_IRGRP; 940da6c28aaSamw if (type == ALLOW) { 941fa9e4066Sahrens mode |= S_IRGRP; 942fa9e4066Sahrens } 943fa9e4066Sahrens } 944fa9e4066Sahrens if (!(seen & S_IROTH)) { 945fa9e4066Sahrens seen |= S_IROTH; 946da6c28aaSamw if (type == ALLOW) { 947fa9e4066Sahrens mode |= S_IROTH; 948fa9e4066Sahrens } 949fa9e4066Sahrens } 950fa9e4066Sahrens } 951da6c28aaSamw if ((access_mask & ACE_WRITE_DATA)) { 952fa9e4066Sahrens if (!(seen & S_IWUSR)) { 953fa9e4066Sahrens seen |= S_IWUSR; 954da6c28aaSamw if (type == ALLOW) { 955fa9e4066Sahrens mode |= S_IWUSR; 956fa9e4066Sahrens } 957fa9e4066Sahrens } 958fa9e4066Sahrens if (!(seen & S_IWGRP)) { 959fa9e4066Sahrens seen |= S_IWGRP; 960da6c28aaSamw if (type == ALLOW) { 961fa9e4066Sahrens mode |= S_IWGRP; 962fa9e4066Sahrens } 963fa9e4066Sahrens } 964fa9e4066Sahrens if (!(seen & S_IWOTH)) { 965fa9e4066Sahrens seen |= S_IWOTH; 966da6c28aaSamw if (type == ALLOW) { 967fa9e4066Sahrens mode |= S_IWOTH; 968fa9e4066Sahrens } 969fa9e4066Sahrens } 970fa9e4066Sahrens } 971da6c28aaSamw if ((access_mask & ACE_EXECUTE)) { 972fa9e4066Sahrens if (!(seen & S_IXUSR)) { 973fa9e4066Sahrens seen |= S_IXUSR; 974da6c28aaSamw if (type == ALLOW) { 975fa9e4066Sahrens mode |= S_IXUSR; 976fa9e4066Sahrens } 977fa9e4066Sahrens } 978fa9e4066Sahrens if (!(seen & S_IXGRP)) { 979fa9e4066Sahrens seen |= S_IXGRP; 980da6c28aaSamw if (type == ALLOW) { 981fa9e4066Sahrens mode |= S_IXGRP; 982fa9e4066Sahrens } 983fa9e4066Sahrens } 984fa9e4066Sahrens if (!(seen & S_IXOTH)) { 985fa9e4066Sahrens seen |= S_IXOTH; 986da6c28aaSamw if (type == ALLOW) { 987fa9e4066Sahrens mode |= S_IXOTH; 988fa9e4066Sahrens } 989fa9e4066Sahrens } 990fa9e4066Sahrens } 991d47621a4STim Haley } else { 992d47621a4STim Haley /* 993d47621a4STim Haley * Only care if this IDENTIFIER_GROUP or 994d47621a4STim Haley * USER ACE denies execute access to someone, 995d47621a4STim Haley * mode is not affected 996d47621a4STim Haley */ 997d47621a4STim Haley if ((access_mask & ACE_EXECUTE) && type == DENY) 998d47621a4STim Haley an_exec_denied = B_TRUE; 999fa9e4066Sahrens } 1000fa9e4066Sahrens } 1001d47621a4STim Haley 10024929fd5eSTim Haley /* 10034929fd5eSTim Haley * Failure to allow is effectively a deny, so execute permission 10044929fd5eSTim Haley * is denied if it was never mentioned or if we explicitly 10054929fd5eSTim Haley * weren't allowed it. 10064929fd5eSTim Haley */ 10074929fd5eSTim Haley if (!an_exec_denied && 10084929fd5eSTim Haley ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || 10094929fd5eSTim Haley (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) 1010d47621a4STim Haley an_exec_denied = B_TRUE; 1011d47621a4STim Haley 1012d47621a4STim Haley if (an_exec_denied) 1013*0a586ceaSMark Shellenbaum *pflags &= ~ZFS_NO_EXECS_DENIED; 1014d47621a4STim Haley else 1015*0a586ceaSMark Shellenbaum *pflags |= ZFS_NO_EXECS_DENIED; 1016d47621a4STim Haley 1017fa9e4066Sahrens return (mode); 1018fa9e4066Sahrens } 1019fa9e4066Sahrens 1020fa9e4066Sahrens /* 10214929fd5eSTim Haley * Read an external acl object. If the intent is to modify, always 10224929fd5eSTim Haley * create a new acl and leave any cached acl in place. 1023fa9e4066Sahrens */ 1024ea8dc4b6Seschrock static int 1025da6c28aaSamw zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) 1026fa9e4066Sahrens { 1027fa9e4066Sahrens zfs_acl_t *aclp; 1028*0a586ceaSMark Shellenbaum int aclsize; 1029*0a586ceaSMark Shellenbaum int acl_count; 1030da6c28aaSamw zfs_acl_node_t *aclnode; 1031*0a586ceaSMark Shellenbaum zfs_acl_phys_t znode_acl; 1032*0a586ceaSMark Shellenbaum int version; 1033ea8dc4b6Seschrock int error; 1034fa9e4066Sahrens 1035fa9e4066Sahrens ASSERT(MUTEX_HELD(&zp->z_acl_lock)); 1036fa9e4066Sahrens 10374929fd5eSTim Haley if (zp->z_acl_cached && !will_modify) { 1038d47621a4STim Haley *aclpp = zp->z_acl_cached; 1039d47621a4STim Haley return (0); 1040d47621a4STim Haley } 1041d47621a4STim Haley 1042*0a586ceaSMark Shellenbaum version = ZNODE_ACL_VERSION(zp); 1043fa9e4066Sahrens 1044*0a586ceaSMark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize, 1045*0a586ceaSMark Shellenbaum &acl_count, &znode_acl)) != 0) 1046*0a586ceaSMark Shellenbaum return (error); 1047fa9e4066Sahrens 1048*0a586ceaSMark Shellenbaum aclp = zfs_acl_alloc(version); 1049*0a586ceaSMark Shellenbaum 1050da6c28aaSamw aclp->z_acl_count = acl_count; 1051da6c28aaSamw aclp->z_acl_bytes = aclsize; 1052da6c28aaSamw 1053*0a586ceaSMark Shellenbaum aclnode = zfs_acl_node_alloc(aclsize); 1054*0a586ceaSMark Shellenbaum aclnode->z_ace_count = aclp->z_acl_count; 1055*0a586ceaSMark Shellenbaum aclnode->z_size = aclsize; 1056*0a586ceaSMark Shellenbaum 1057*0a586ceaSMark Shellenbaum if (!zp->z_is_sa) { 1058*0a586ceaSMark Shellenbaum if (znode_acl.z_acl_extern_obj) { 1059*0a586ceaSMark Shellenbaum error = dmu_read(zp->z_zfsvfs->z_os, 1060*0a586ceaSMark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size, 1061*0a586ceaSMark Shellenbaum aclnode->z_acldata, DMU_READ_PREFETCH); 1062*0a586ceaSMark Shellenbaum } else { 1063*0a586ceaSMark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata, 1064*0a586ceaSMark Shellenbaum aclnode->z_size); 1065*0a586ceaSMark Shellenbaum } 1066*0a586ceaSMark Shellenbaum } else { 1067*0a586ceaSMark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs), 1068*0a586ceaSMark Shellenbaum aclnode->z_acldata, aclnode->z_size); 1069*0a586ceaSMark Shellenbaum } 1070*0a586ceaSMark Shellenbaum 1071ea8dc4b6Seschrock if (error != 0) { 1072ea8dc4b6Seschrock zfs_acl_free(aclp); 1073*0a586ceaSMark Shellenbaum zfs_acl_node_free(aclnode); 1074b87f3af3Sperrin /* convert checksum errors into IO errors */ 1075b87f3af3Sperrin if (error == ECKSUM) 1076b87f3af3Sperrin error = EIO; 1077ea8dc4b6Seschrock return (error); 1078ea8dc4b6Seschrock } 1079fa9e4066Sahrens 1080*0a586ceaSMark Shellenbaum list_insert_head(&aclp->z_acl, aclnode); 1081*0a586ceaSMark Shellenbaum 10824929fd5eSTim Haley *aclpp = aclp; 10834929fd5eSTim Haley if (!will_modify) 10844929fd5eSTim Haley zp->z_acl_cached = aclp; 1085ea8dc4b6Seschrock return (0); 1086fa9e4066Sahrens } 1087fa9e4066Sahrens 1088*0a586ceaSMark Shellenbaum /*ARGSUSED*/ 1089*0a586ceaSMark Shellenbaum void 1090*0a586ceaSMark Shellenbaum zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, 1091*0a586ceaSMark Shellenbaum boolean_t start, void *userdata) 1092*0a586ceaSMark Shellenbaum { 1093*0a586ceaSMark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata; 1094*0a586ceaSMark Shellenbaum 1095*0a586ceaSMark Shellenbaum if (start) { 1096*0a586ceaSMark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl); 1097*0a586ceaSMark Shellenbaum } else { 1098*0a586ceaSMark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, 1099*0a586ceaSMark Shellenbaum cb->cb_acl_node); 1100*0a586ceaSMark Shellenbaum } 1101*0a586ceaSMark Shellenbaum *dataptr = cb->cb_acl_node->z_acldata; 1102*0a586ceaSMark Shellenbaum *length = cb->cb_acl_node->z_size; 1103*0a586ceaSMark Shellenbaum } 1104*0a586ceaSMark Shellenbaum 1105fa9e4066Sahrens /* 1106da6c28aaSamw * common code for setting ACLs. 1107fa9e4066Sahrens * 1108fa9e4066Sahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl. 1109fa9e4066Sahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's 1110fa9e4066Sahrens * already checked the acl and knows whether to inherit. 1111fa9e4066Sahrens */ 1112fa9e4066Sahrens int 111389459e17SMark Shellenbaum zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) 1114fa9e4066Sahrens { 1115fa9e4066Sahrens int error; 1116fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 1117da6c28aaSamw dmu_object_type_t otype; 1118*0a586ceaSMark Shellenbaum zfs_acl_locator_cb_t locate = { 0 }; 1119*0a586ceaSMark Shellenbaum uint64_t mode; 1120*0a586ceaSMark Shellenbaum sa_bulk_attr_t bulk[5]; 1121*0a586ceaSMark Shellenbaum uint64_t ctime[2]; 1122*0a586ceaSMark Shellenbaum int count = 0; 1123fa9e4066Sahrens 1124*0a586ceaSMark Shellenbaum mode = zp->z_mode; 1125*0a586ceaSMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags); 1126*0a586ceaSMark Shellenbaum 1127*0a586ceaSMark Shellenbaum zp->z_mode = mode; 1128*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL, 1129*0a586ceaSMark Shellenbaum &mode, sizeof (mode)); 1130*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, 1131*0a586ceaSMark Shellenbaum &zp->z_pflags, sizeof (zp->z_pflags)); 1132*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, 1133*0a586ceaSMark Shellenbaum &ctime, sizeof (ctime)); 1134fa9e4066Sahrens 11354929fd5eSTim Haley if (zp->z_acl_cached) { 1136d47621a4STim Haley zfs_acl_free(zp->z_acl_cached); 1137d47621a4STim Haley zp->z_acl_cached = NULL; 1138d47621a4STim Haley } 1139d47621a4STim Haley 1140fa9e4066Sahrens /* 1141*0a586ceaSMark Shellenbaum * Upgrade needed? 1142fa9e4066Sahrens */ 1143da6c28aaSamw if (!zfsvfs->z_use_fuids) { 1144da6c28aaSamw otype = DMU_OT_OLDACL; 1145da6c28aaSamw } else { 1146da6c28aaSamw if ((aclp->z_version == ZFS_ACL_VERSION_INITIAL) && 1147da6c28aaSamw (zfsvfs->z_version >= ZPL_VERSION_FUID)) 114889459e17SMark Shellenbaum zfs_acl_xform(zp, aclp, cr); 1149da6c28aaSamw ASSERT(aclp->z_version >= ZFS_ACL_VERSION_FUID); 1150da6c28aaSamw otype = DMU_OT_ACL; 1151da6c28aaSamw } 1152da6c28aaSamw 1153*0a586ceaSMark Shellenbaum /* 1154*0a586ceaSMark Shellenbaum * Arrgh, we have to handle old on disk format 1155*0a586ceaSMark Shellenbaum * as well as newer (preferred) SA format. 1156*0a586ceaSMark Shellenbaum */ 1157*0a586ceaSMark Shellenbaum 1158*0a586ceaSMark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */ 1159*0a586ceaSMark Shellenbaum locate.cb_aclp = aclp; 1160*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs), 1161*0a586ceaSMark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes); 1162*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs), 1163*0a586ceaSMark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t)); 1164*0a586ceaSMark Shellenbaum } else { /* Painful legacy way */ 1165*0a586ceaSMark Shellenbaum zfs_acl_node_t *aclnode; 1166*0a586ceaSMark Shellenbaum uint64_t off = 0; 1167*0a586ceaSMark Shellenbaum zfs_acl_phys_t acl_phys; 1168*0a586ceaSMark Shellenbaum uint64_t aoid; 1169*0a586ceaSMark Shellenbaum 1170*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs), 1171*0a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys))) != 0) 1172*0a586ceaSMark Shellenbaum return (error); 1173*0a586ceaSMark Shellenbaum 1174*0a586ceaSMark Shellenbaum aoid = acl_phys.z_acl_extern_obj; 1175*0a586ceaSMark Shellenbaum 1176da6c28aaSamw if (aclp->z_acl_bytes > ZFS_ACE_SPACE) { 1177da6c28aaSamw /* 1178da6c28aaSamw * If ACL was previously external and we are now 1179da6c28aaSamw * converting to new ACL format then release old 1180da6c28aaSamw * ACL object and create a new one. 1181da6c28aaSamw */ 1182*0a586ceaSMark Shellenbaum if (aoid && 1183*0a586ceaSMark Shellenbaum aclp->z_version != acl_phys.z_acl_version) { 1184*0a586ceaSMark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx); 1185da6c28aaSamw if (error) 1186da6c28aaSamw return (error); 1187da6c28aaSamw aoid = 0; 1188da6c28aaSamw } 1189fa9e4066Sahrens if (aoid == 0) { 1190fa9e4066Sahrens aoid = dmu_object_alloc(zfsvfs->z_os, 1191da6c28aaSamw otype, aclp->z_acl_bytes, 1192*0a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 1193*0a586ceaSMark Shellenbaum DMU_OT_SYSACL : DMU_OT_NONE, 1194*0a586ceaSMark Shellenbaum otype == DMU_OT_ACL ? 1195*0a586ceaSMark Shellenbaum DN_MAX_BONUSLEN : 0, tx); 1196fa9e4066Sahrens } else { 1197*0a586ceaSMark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os, 1198*0a586ceaSMark Shellenbaum aoid, aclp->z_acl_bytes, 0, tx); 1199fa9e4066Sahrens } 1200*0a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = aoid; 1201da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1202da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1203da6c28aaSamw if (aclnode->z_ace_count == 0) 1204da6c28aaSamw continue; 1205da6c28aaSamw dmu_write(zfsvfs->z_os, aoid, off, 1206da6c28aaSamw aclnode->z_size, aclnode->z_acldata, tx); 1207da6c28aaSamw off += aclnode->z_size; 1208da6c28aaSamw } 1209fa9e4066Sahrens } else { 1210*0a586ceaSMark Shellenbaum void *start = acl_phys.z_ace_data; 1211fa9e4066Sahrens /* 1212fa9e4066Sahrens * Migrating back embedded? 1213fa9e4066Sahrens */ 1214*0a586ceaSMark Shellenbaum if (acl_phys.z_acl_extern_obj) { 1215fa9e4066Sahrens error = dmu_object_free(zfsvfs->z_os, 1216*0a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj, tx); 1217fa9e4066Sahrens if (error) 1218fa9e4066Sahrens return (error); 1219*0a586ceaSMark Shellenbaum acl_phys.z_acl_extern_obj = 0; 1220fa9e4066Sahrens } 1221da6c28aaSamw 1222da6c28aaSamw for (aclnode = list_head(&aclp->z_acl); aclnode; 1223da6c28aaSamw aclnode = list_next(&aclp->z_acl, aclnode)) { 1224da6c28aaSamw if (aclnode->z_ace_count == 0) 1225da6c28aaSamw continue; 1226*0a586ceaSMark Shellenbaum bcopy(aclnode->z_acldata, start, 1227*0a586ceaSMark Shellenbaum aclnode->z_size); 1228da6c28aaSamw start = (caddr_t)start + aclnode->z_size; 1229da6c28aaSamw } 1230fa9e4066Sahrens } 1231da6c28aaSamw /* 1232da6c28aaSamw * If Old version then swap count/bytes to match old 1233da6c28aaSamw * layout of znode_acl_phys_t. 1234da6c28aaSamw */ 1235da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 1236*0a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_count; 1237*0a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_bytes; 1238da6c28aaSamw } else { 1239*0a586ceaSMark Shellenbaum acl_phys.z_acl_size = aclp->z_acl_bytes; 1240*0a586ceaSMark Shellenbaum acl_phys.z_acl_count = aclp->z_acl_count; 1241da6c28aaSamw } 1242*0a586ceaSMark Shellenbaum acl_phys.z_acl_version = aclp->z_version; 1243da6c28aaSamw 1244*0a586ceaSMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL, 1245*0a586ceaSMark Shellenbaum &acl_phys, sizeof (acl_phys)); 1246*0a586ceaSMark Shellenbaum } 1247da6c28aaSamw 1248da6c28aaSamw /* 1249da6c28aaSamw * Replace ACL wide bits, but first clear them. 1250da6c28aaSamw */ 1251*0a586ceaSMark Shellenbaum zp->z_pflags &= ~ZFS_ACL_WIDE_FLAGS; 1252da6c28aaSamw 1253*0a586ceaSMark Shellenbaum zp->z_pflags |= aclp->z_hints; 1254da6c28aaSamw 1255da6c28aaSamw if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0) 1256*0a586ceaSMark Shellenbaum zp->z_pflags |= ZFS_ACL_TRIVIAL; 1257fa9e4066Sahrens 1258*0a586ceaSMark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE); 1259*0a586ceaSMark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx)); 1260fa9e4066Sahrens } 1261fa9e4066Sahrens 1262fa9e4066Sahrens /* 1263fa9e4066Sahrens * Update access mask for prepended ACE 1264fa9e4066Sahrens * 1265fa9e4066Sahrens * This applies the "groupmask" value for aclmode property. 1266fa9e4066Sahrens */ 1267fa9e4066Sahrens static void 1268da6c28aaSamw zfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep, 1269da6c28aaSamw mode_t mode, uint64_t owner) 1270fa9e4066Sahrens { 1271fa9e4066Sahrens int rmask, wmask, xmask; 1272fa9e4066Sahrens int user_ace; 1273da6c28aaSamw uint16_t aceflags; 1274da6c28aaSamw uint32_t origmask, acepmask; 1275da6c28aaSamw uint64_t fuid; 1276fa9e4066Sahrens 1277da6c28aaSamw aceflags = aclp->z_ops.ace_flags_get(acep); 1278da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1279da6c28aaSamw origmask = aclp->z_ops.ace_mask_get(origacep); 1280da6c28aaSamw acepmask = aclp->z_ops.ace_mask_get(acep); 1281da6c28aaSamw 1282da6c28aaSamw user_ace = (!(aceflags & 1283fa9e4066Sahrens (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP))); 1284fa9e4066Sahrens 1285da6c28aaSamw if (user_ace && (fuid == owner)) { 1286fa9e4066Sahrens rmask = S_IRUSR; 1287fa9e4066Sahrens wmask = S_IWUSR; 1288fa9e4066Sahrens xmask = S_IXUSR; 1289fa9e4066Sahrens } else { 1290fa9e4066Sahrens rmask = S_IRGRP; 1291fa9e4066Sahrens wmask = S_IWGRP; 1292fa9e4066Sahrens xmask = S_IXGRP; 1293fa9e4066Sahrens } 1294fa9e4066Sahrens 1295da6c28aaSamw if (origmask & ACE_READ_DATA) { 1296da6c28aaSamw if (mode & rmask) { 1297da6c28aaSamw acepmask &= ~ACE_READ_DATA; 1298da6c28aaSamw } else { 1299da6c28aaSamw acepmask |= ACE_READ_DATA; 1300da6c28aaSamw } 1301fa9e4066Sahrens } 1302fa9e4066Sahrens 1303da6c28aaSamw if (origmask & ACE_WRITE_DATA) { 1304da6c28aaSamw if (mode & wmask) { 1305da6c28aaSamw acepmask &= ~ACE_WRITE_DATA; 1306da6c28aaSamw } else { 1307da6c28aaSamw acepmask |= ACE_WRITE_DATA; 1308da6c28aaSamw } 1309fa9e4066Sahrens } 1310fa9e4066Sahrens 1311da6c28aaSamw if (origmask & ACE_APPEND_DATA) { 1312da6c28aaSamw if (mode & wmask) { 1313da6c28aaSamw acepmask &= ~ACE_APPEND_DATA; 1314da6c28aaSamw } else { 1315da6c28aaSamw acepmask |= ACE_APPEND_DATA; 1316da6c28aaSamw } 1317fa9e4066Sahrens } 1318fa9e4066Sahrens 1319da6c28aaSamw if (origmask & ACE_EXECUTE) { 1320da6c28aaSamw if (mode & xmask) { 1321da6c28aaSamw acepmask &= ~ACE_EXECUTE; 1322da6c28aaSamw } else { 1323da6c28aaSamw acepmask |= ACE_EXECUTE; 1324fa9e4066Sahrens } 1325fa9e4066Sahrens } 1326da6c28aaSamw aclp->z_ops.ace_mask_set(acep, acepmask); 1327da6c28aaSamw } 1328fa9e4066Sahrens 1329fa9e4066Sahrens /* 1330fa9e4066Sahrens * Apply mode to canonical six ACEs. 1331fa9e4066Sahrens */ 1332fa9e4066Sahrens static void 1333fa9e4066Sahrens zfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode) 1334fa9e4066Sahrens { 1335da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1336da6c28aaSamw void *acep; 1337da6c28aaSamw int maskoff = aclp->z_ops.ace_mask_off(); 1338da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1339fa9e4066Sahrens 1340da6c28aaSamw ASSERT(aclnode != NULL); 1341da6c28aaSamw 1342da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1343da6c28aaSamw aclnode->z_size - (abstract_size * 6)); 1344fa9e4066Sahrens 1345fa9e4066Sahrens /* 1346fa9e4066Sahrens * Fixup final ACEs to match the mode 1347fa9e4066Sahrens */ 1348fa9e4066Sahrens 1349da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1350da6c28aaSamw (mode & 0700) >> 6); /* owner@ */ 1351da6c28aaSamw 1352da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1353da6c28aaSamw 1354da6c28aaSamw adjust_ace_pair_common(acep, maskoff, abstract_size, 1355da6c28aaSamw (mode & 0070) >> 3); /* group@ */ 1356da6c28aaSamw 1357da6c28aaSamw acep = (caddr_t)acep + (abstract_size * 2); 1358da6c28aaSamw adjust_ace_pair_common(acep, maskoff, 1359da6c28aaSamw abstract_size, mode); /* everyone@ */ 1360fa9e4066Sahrens } 1361fa9e4066Sahrens 1362fa9e4066Sahrens 1363fa9e4066Sahrens static int 1364da6c28aaSamw zfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny, 1365da6c28aaSamw int entry_type, int accessmask) 1366fa9e4066Sahrens { 1367da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1368da6c28aaSamw uint16_t type = aclp->z_ops.ace_type_get(acep); 1369da6c28aaSamw uint16_t flags = aclp->z_ops.ace_flags_get(acep); 1370da6c28aaSamw 1371da6c28aaSamw return (mask == accessmask && type == allow_deny && 1372da6c28aaSamw ((flags & ACE_TYPE_FLAGS) == entry_type)); 1373fa9e4066Sahrens } 1374fa9e4066Sahrens 1375fa9e4066Sahrens /* 1376fa9e4066Sahrens * Can prepended ACE be reused? 1377fa9e4066Sahrens */ 1378fa9e4066Sahrens static int 1379da6c28aaSamw zfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep) 1380fa9e4066Sahrens { 1381fa9e4066Sahrens int okay_masks; 1382da6c28aaSamw uint16_t prevtype; 1383da6c28aaSamw uint16_t prevflags; 1384da6c28aaSamw uint16_t flags; 1385da6c28aaSamw uint32_t mask, prevmask; 1386fa9e4066Sahrens 1387da6c28aaSamw if (prevacep == NULL) 1388fa9e4066Sahrens return (B_FALSE); 1389fa9e4066Sahrens 1390da6c28aaSamw prevtype = aclp->z_ops.ace_type_get(prevacep); 1391da6c28aaSamw prevflags = aclp->z_ops.ace_flags_get(prevacep); 1392da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1393da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1394da6c28aaSamw prevmask = aclp->z_ops.ace_mask_get(prevacep); 1395da6c28aaSamw 1396da6c28aaSamw if (prevtype != DENY) 1397fa9e4066Sahrens return (B_FALSE); 1398fa9e4066Sahrens 1399da6c28aaSamw if (prevflags != (flags & ACE_IDENTIFIER_GROUP)) 1400fa9e4066Sahrens return (B_FALSE); 1401fa9e4066Sahrens 1402da6c28aaSamw okay_masks = (mask & OKAY_MASK_BITS); 1403fa9e4066Sahrens 1404da6c28aaSamw if (prevmask & ~okay_masks) 1405fa9e4066Sahrens return (B_FALSE); 1406fa9e4066Sahrens 1407fa9e4066Sahrens return (B_TRUE); 1408fa9e4066Sahrens } 1409fa9e4066Sahrens 1410da6c28aaSamw 1411fa9e4066Sahrens /* 1412da6c28aaSamw * Insert new ACL node into chain of zfs_acl_node_t's 1413da6c28aaSamw * 1414da6c28aaSamw * This will result in two possible results. 1415da6c28aaSamw * 1. If the ACL is currently just a single zfs_acl_node and 1416da6c28aaSamw * we are prepending the entry then current acl node will have 1417da6c28aaSamw * a new node inserted above it. 1418da6c28aaSamw * 1419da6c28aaSamw * 2. If we are inserting in the middle of current acl node then 1420da6c28aaSamw * the current node will be split in two and new node will be inserted 1421da6c28aaSamw * in between the two split nodes. 1422fa9e4066Sahrens */ 1423da6c28aaSamw static zfs_acl_node_t * 1424da6c28aaSamw zfs_acl_ace_insert(zfs_acl_t *aclp, void *acep) 1425fa9e4066Sahrens { 1426da6c28aaSamw zfs_acl_node_t *newnode; 1427da6c28aaSamw zfs_acl_node_t *trailernode = NULL; 1428da6c28aaSamw zfs_acl_node_t *currnode = zfs_acl_curr_node(aclp); 1429da6c28aaSamw int curr_idx = aclp->z_curr_node->z_ace_idx; 1430da6c28aaSamw int trailer_count; 1431da6c28aaSamw size_t oldsize; 1432fa9e4066Sahrens 1433da6c28aaSamw newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep)); 1434da6c28aaSamw newnode->z_ace_count = 1; 1435fa9e4066Sahrens 1436da6c28aaSamw oldsize = currnode->z_size; 1437fa9e4066Sahrens 1438da6c28aaSamw if (curr_idx != 1) { 1439da6c28aaSamw trailernode = zfs_acl_node_alloc(0); 1440da6c28aaSamw trailernode->z_acldata = acep; 1441da6c28aaSamw 1442da6c28aaSamw trailer_count = currnode->z_ace_count - curr_idx + 1; 1443da6c28aaSamw currnode->z_ace_count = curr_idx - 1; 1444da6c28aaSamw currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata; 1445da6c28aaSamw trailernode->z_size = oldsize - currnode->z_size; 1446da6c28aaSamw trailernode->z_ace_count = trailer_count; 1447fa9e4066Sahrens } 1448fa9e4066Sahrens 1449da6c28aaSamw aclp->z_acl_count += 1; 1450da6c28aaSamw aclp->z_acl_bytes += aclp->z_ops.ace_size(acep); 1451fa9e4066Sahrens 1452da6c28aaSamw if (curr_idx == 1) 1453da6c28aaSamw list_insert_before(&aclp->z_acl, currnode, newnode); 1454da6c28aaSamw else 1455da6c28aaSamw list_insert_after(&aclp->z_acl, currnode, newnode); 1456da6c28aaSamw if (trailernode) { 1457da6c28aaSamw list_insert_after(&aclp->z_acl, newnode, trailernode); 1458da6c28aaSamw aclp->z_curr_node = trailernode; 1459da6c28aaSamw trailernode->z_ace_idx = 1; 1460fa9e4066Sahrens } 1461fa9e4066Sahrens 1462da6c28aaSamw return (newnode); 1463fa9e4066Sahrens } 1464fa9e4066Sahrens 1465fa9e4066Sahrens /* 1466fa9e4066Sahrens * Prepend deny ACE 1467fa9e4066Sahrens */ 1468da6c28aaSamw static void * 146989459e17SMark Shellenbaum zfs_acl_prepend_deny(uint64_t uid, zfs_acl_t *aclp, void *acep, 1470fa9e4066Sahrens mode_t mode) 1471fa9e4066Sahrens { 1472da6c28aaSamw zfs_acl_node_t *aclnode; 1473da6c28aaSamw void *newacep; 1474da6c28aaSamw uint64_t fuid; 1475da6c28aaSamw uint16_t flags; 1476fa9e4066Sahrens 1477da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1478da6c28aaSamw newacep = aclnode->z_acldata; 1479da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1480da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1481da6c28aaSamw zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS)); 148289459e17SMark Shellenbaum zfs_acl_prepend_fixup(aclp, newacep, acep, mode, uid); 1483fa9e4066Sahrens 1484da6c28aaSamw return (newacep); 1485fa9e4066Sahrens } 1486fa9e4066Sahrens 1487fa9e4066Sahrens /* 1488fa9e4066Sahrens * Split an inherited ACE into inherit_only ACE 1489fa9e4066Sahrens * and original ACE with inheritance flags stripped off. 1490fa9e4066Sahrens */ 1491fa9e4066Sahrens static void 1492da6c28aaSamw zfs_acl_split_ace(zfs_acl_t *aclp, zfs_ace_hdr_t *acep) 1493fa9e4066Sahrens { 1494da6c28aaSamw zfs_acl_node_t *aclnode; 1495569e6c63Smarks zfs_acl_node_t *currnode; 1496da6c28aaSamw void *newacep; 1497da6c28aaSamw uint16_t type, flags; 1498da6c28aaSamw uint32_t mask; 1499da6c28aaSamw uint64_t fuid; 1500fa9e4066Sahrens 1501da6c28aaSamw type = aclp->z_ops.ace_type_get(acep); 1502da6c28aaSamw flags = aclp->z_ops.ace_flags_get(acep); 1503da6c28aaSamw mask = aclp->z_ops.ace_mask_get(acep); 1504da6c28aaSamw fuid = aclp->z_ops.ace_who_get(acep); 1505da6c28aaSamw 1506da6c28aaSamw aclnode = zfs_acl_ace_insert(aclp, acep); 1507da6c28aaSamw newacep = aclnode->z_acldata; 1508da6c28aaSamw 1509da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1510da6c28aaSamw aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE); 1511da6c28aaSamw aclp->z_ops.ace_mask_set(newacep, mask); 1512da6c28aaSamw aclp->z_ops.ace_type_set(newacep, type); 1513da6c28aaSamw aclp->z_ops.ace_who_set(newacep, fuid); 1514da6c28aaSamw aclp->z_next_ace = acep; 1515da6c28aaSamw flags &= ~ALL_INHERIT; 1516da6c28aaSamw aclp->z_ops.ace_flags_set(acep, flags); 1517569e6c63Smarks currnode = zfs_acl_curr_node(aclp); 1518569e6c63Smarks ASSERT(currnode->z_ace_idx >= 1); 1519da6c28aaSamw currnode->z_ace_idx -= 1; 1520fa9e4066Sahrens } 1521fa9e4066Sahrens 1522fa9e4066Sahrens /* 1523fa9e4066Sahrens * Are ACES started at index i, the canonical six ACES? 1524fa9e4066Sahrens */ 1525fa9e4066Sahrens static int 1526da6c28aaSamw zfs_have_canonical_six(zfs_acl_t *aclp) 1527fa9e4066Sahrens { 1528da6c28aaSamw void *acep; 1529da6c28aaSamw zfs_acl_node_t *aclnode = list_tail(&aclp->z_acl); 1530da6c28aaSamw int i = 0; 1531da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1532fa9e4066Sahrens 1533da6c28aaSamw ASSERT(aclnode != NULL); 1534da6c28aaSamw 1535da6c28aaSamw if (aclnode->z_ace_count < 6) 1536da6c28aaSamw return (0); 1537da6c28aaSamw 1538da6c28aaSamw acep = (void *)((caddr_t)aclnode->z_acldata + 1539da6c28aaSamw aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6)); 1540da6c28aaSamw 1541da6c28aaSamw if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1542fa9e4066Sahrens DENY, ACE_OWNER, 0) && 1543da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1544da6c28aaSamw ALLOW, ACE_OWNER, OWNER_ALLOW_MASK) && 1545da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY, 1546da6c28aaSamw OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep + 1547da6c28aaSamw (abstract_size * i++), 1548da6c28aaSamw ALLOW, OWNING_GROUP, 0) && 1549da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1550fa9e4066Sahrens DENY, ACE_EVERYONE, EVERYONE_DENY_MASK) && 1551da6c28aaSamw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), 1552da6c28aaSamw ALLOW, ACE_EVERYONE, EVERYONE_ALLOW_MASK))) { 1553fa9e4066Sahrens return (1); 1554fa9e4066Sahrens } else { 1555fa9e4066Sahrens return (0); 1556fa9e4066Sahrens } 1557fa9e4066Sahrens } 1558fa9e4066Sahrens 1559da6c28aaSamw 1560fa9e4066Sahrens /* 1561fa9e4066Sahrens * Apply step 1g, to group entries 1562fa9e4066Sahrens * 1563fa9e4066Sahrens * Need to deal with corner case where group may have 1564fa9e4066Sahrens * greater permissions than owner. If so then limit 1565fa9e4066Sahrens * group permissions, based on what extra permissions 1566fa9e4066Sahrens * group has. 1567fa9e4066Sahrens */ 1568fa9e4066Sahrens static void 1569da6c28aaSamw zfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep, 1570da6c28aaSamw mode_t mode) 1571fa9e4066Sahrens { 1572da6c28aaSamw uint32_t prevmask = aclp->z_ops.ace_mask_get(prevacep); 1573da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1574da6c28aaSamw uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep); 1575fa9e4066Sahrens mode_t extramode = (mode >> 3) & 07; 1576fa9e4066Sahrens mode_t ownermode = (mode >> 6); 1577fa9e4066Sahrens 1578da6c28aaSamw if (prevflags & ACE_IDENTIFIER_GROUP) { 1579fa9e4066Sahrens 1580fa9e4066Sahrens extramode &= ~ownermode; 1581fa9e4066Sahrens 1582fa9e4066Sahrens if (extramode) { 1583da6c28aaSamw if (extramode & S_IROTH) { 1584da6c28aaSamw prevmask &= ~ACE_READ_DATA; 1585da6c28aaSamw mask &= ~ACE_READ_DATA; 1586fa9e4066Sahrens } 1587da6c28aaSamw if (extramode & S_IWOTH) { 1588da6c28aaSamw prevmask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1589da6c28aaSamw mask &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 1590fa9e4066Sahrens } 1591da6c28aaSamw if (extramode & S_IXOTH) { 1592da6c28aaSamw prevmask &= ~ACE_EXECUTE; 1593da6c28aaSamw mask &= ~ACE_EXECUTE; 1594fa9e4066Sahrens } 1595fa9e4066Sahrens } 1596fa9e4066Sahrens } 1597da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1598da6c28aaSamw aclp->z_ops.ace_mask_set(prevacep, prevmask); 1599fa9e4066Sahrens } 1600fa9e4066Sahrens 1601fa9e4066Sahrens /* 1602fa9e4066Sahrens * Apply the chmod algorithm as described 1603fa9e4066Sahrens * in PSARC/2002/240 1604fa9e4066Sahrens */ 16054c841f60Smarks static void 160689459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t uid, 160789459e17SMark Shellenbaum uint64_t mode, zfs_acl_t *aclp) 1608fa9e4066Sahrens { 1609da6c28aaSamw void *acep = NULL, *prevacep = NULL; 1610da6c28aaSamw uint64_t who; 1611fa9e4066Sahrens int i; 1612fa9e4066Sahrens int entry_type; 1613fa9e4066Sahrens int reuse_deny; 1614fa9e4066Sahrens int need_canonical_six = 1; 1615da6c28aaSamw uint16_t iflags, type; 1616da6c28aaSamw uint32_t access_mask; 1617fa9e4066Sahrens 16182459a9eaSmarks /* 16192459a9eaSmarks * If discard then just discard all ACL nodes which 16202459a9eaSmarks * represent the ACEs. 16212459a9eaSmarks * 16222459a9eaSmarks * New owner@/group@/everone@ ACEs will be added 16232459a9eaSmarks * later. 16242459a9eaSmarks */ 16252459a9eaSmarks if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) 16262459a9eaSmarks zfs_acl_release_nodes(aclp); 16272459a9eaSmarks 1628da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 1629da6c28aaSamw &iflags, &type)) { 1630fa9e4066Sahrens 1631da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 1632da6c28aaSamw iflags = (iflags & ALL_INHERIT); 1633da6c28aaSamw 1634da6c28aaSamw if ((type != ALLOW && type != DENY) || 1635de122929Smarks (iflags & ACE_INHERIT_ONLY_ACE)) { 1636de122929Smarks if (iflags) 1637da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1638da6c28aaSamw switch (type) { 1639da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 1640da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 1641da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 1642da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 1643da6c28aaSamw aclp->z_hints |= ZFS_ACL_OBJ_ACE; 1644da6c28aaSamw break; 1645fa9e4066Sahrens } 1646da6c28aaSamw goto nextace; 1647da6c28aaSamw } 1648fa9e4066Sahrens 1649fa9e4066Sahrens /* 1650fa9e4066Sahrens * Need to split ace into two? 1651fa9e4066Sahrens */ 1652de122929Smarks if ((iflags & (ACE_FILE_INHERIT_ACE| 1653fa9e4066Sahrens ACE_DIRECTORY_INHERIT_ACE)) && 1654de122929Smarks (!(iflags & ACE_INHERIT_ONLY_ACE))) { 1655da6c28aaSamw zfs_acl_split_ace(aclp, acep); 1656da6c28aaSamw aclp->z_hints |= ZFS_INHERIT_ACE; 1657da6c28aaSamw goto nextace; 1658fa9e4066Sahrens } 1659fa9e4066Sahrens 1660fa9e4066Sahrens if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE || 1661fa9e4066Sahrens (entry_type == OWNING_GROUP)) { 1662da6c28aaSamw access_mask &= ~OGE_CLEAR; 1663da6c28aaSamw aclp->z_ops.ace_mask_set(acep, access_mask); 1664da6c28aaSamw goto nextace; 1665fa9e4066Sahrens } else { 1666da6c28aaSamw reuse_deny = B_TRUE; 1667da6c28aaSamw if (type == ALLOW) { 1668fa9e4066Sahrens 1669fa9e4066Sahrens /* 1670fa9e4066Sahrens * Check preceding ACE if any, to see 1671fa9e4066Sahrens * if we need to prepend a DENY ACE. 1672fa9e4066Sahrens * This is only applicable when the acl_mode 1673fa9e4066Sahrens * property == groupmask. 1674fa9e4066Sahrens */ 1675e9dbad6fSeschrock if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) { 1676fa9e4066Sahrens 1677da6c28aaSamw reuse_deny = zfs_reuse_deny(aclp, acep, 1678da6c28aaSamw prevacep); 1679fa9e4066Sahrens 1680e0d35c44Smarks if (!reuse_deny) { 1681da6c28aaSamw prevacep = 168289459e17SMark Shellenbaum zfs_acl_prepend_deny(uid, 1683da6c28aaSamw aclp, acep, mode); 1684fa9e4066Sahrens } else { 1685fa9e4066Sahrens zfs_acl_prepend_fixup( 1686da6c28aaSamw aclp, prevacep, 168789459e17SMark Shellenbaum acep, mode, uid); 1688fa9e4066Sahrens } 1689da6c28aaSamw zfs_fixup_group_entries(aclp, acep, 1690da6c28aaSamw prevacep, mode); 1691fa9e4066Sahrens } 1692fa9e4066Sahrens } 1693fa9e4066Sahrens } 1694da6c28aaSamw nextace: 1695da6c28aaSamw prevacep = acep; 1696fa9e4066Sahrens } 1697fa9e4066Sahrens 1698fa9e4066Sahrens /* 1699fa9e4066Sahrens * Check out last six aces, if we have six. 1700fa9e4066Sahrens */ 1701fa9e4066Sahrens 1702fa9e4066Sahrens if (aclp->z_acl_count >= 6) { 1703da6c28aaSamw if (zfs_have_canonical_six(aclp)) { 1704fa9e4066Sahrens need_canonical_six = 0; 1705fa9e4066Sahrens } 1706fa9e4066Sahrens } 1707fa9e4066Sahrens 1708fa9e4066Sahrens if (need_canonical_six) { 1709da6c28aaSamw size_t abstract_size = aclp->z_ops.ace_abstract_size(); 1710da6c28aaSamw void *zacep; 1711da6c28aaSamw zfs_acl_node_t *aclnode = 1712da6c28aaSamw zfs_acl_node_alloc(abstract_size * 6); 1713fa9e4066Sahrens 1714da6c28aaSamw aclnode->z_size = abstract_size * 6; 1715da6c28aaSamw aclnode->z_ace_count = 6; 1716da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1717da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1718da6c28aaSamw 1719da6c28aaSamw zacep = aclnode->z_acldata; 1720da6c28aaSamw 1721da6c28aaSamw i = 0; 1722da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1723da6c28aaSamw 0, DENY, -1, ACE_OWNER); 1724da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1725da6c28aaSamw OWNER_ALLOW_MASK, ALLOW, -1, ACE_OWNER); 1726da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1727da6c28aaSamw DENY, -1, OWNING_GROUP); 1728da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0, 1729da6c28aaSamw ALLOW, -1, OWNING_GROUP); 1730da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1731da6c28aaSamw EVERYONE_DENY_MASK, DENY, -1, ACE_EVERYONE); 1732da6c28aaSamw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 1733da6c28aaSamw EVERYONE_ALLOW_MASK, ALLOW, -1, ACE_EVERYONE); 1734fa9e4066Sahrens aclp->z_acl_count += 6; 1735fa9e4066Sahrens } 1736fa9e4066Sahrens 1737fa9e4066Sahrens zfs_acl_fixup_canonical_six(aclp, mode); 1738fa9e4066Sahrens } 1739fa9e4066Sahrens 1740fa9e4066Sahrens int 17414c841f60Smarks zfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode) 1742fa9e4066Sahrens { 1743fa9e4066Sahrens int error; 1744fa9e4066Sahrens 17454c841f60Smarks mutex_enter(&zp->z_lock); 1746fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 1747*0a586ceaSMark Shellenbaum 17484c841f60Smarks *aclp = NULL; 17494c841f60Smarks error = zfs_acl_node_read(zp, aclp, B_TRUE); 175089459e17SMark Shellenbaum if (error == 0) { 1751*0a586ceaSMark Shellenbaum uint64_t owner; 1752*0a586ceaSMark Shellenbaum if (IS_EPHEMERAL(zp->z_uid)) 1753*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 1754*0a586ceaSMark Shellenbaum SA_ZPL_UID(zp->z_zfsvfs), 1755*0a586ceaSMark Shellenbaum &owner, sizeof (owner))) != 0) 1756*0a586ceaSMark Shellenbaum return (error); 1757*0a586ceaSMark Shellenbaum else 1758*0a586ceaSMark Shellenbaum owner = (uint64_t)zp->z_uid; 1759*0a586ceaSMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS; 1760*0a586ceaSMark Shellenbaum zfs_acl_chmod(zp->z_zfsvfs, owner, mode, *aclp); 176189459e17SMark Shellenbaum } 1762fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 17634c841f60Smarks mutex_exit(&zp->z_lock); 1764fa9e4066Sahrens return (error); 1765fa9e4066Sahrens } 1766fa9e4066Sahrens 1767fa9e4066Sahrens /* 1768fa9e4066Sahrens * strip off write_owner and write_acl 1769fa9e4066Sahrens */ 1770fa9e4066Sahrens static void 1771b3d141f8Smarks zfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep) 1772fa9e4066Sahrens { 1773da6c28aaSamw uint32_t mask = aclp->z_ops.ace_mask_get(acep); 1774da6c28aaSamw 1775b3d141f8Smarks if ((zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) && 1776da6c28aaSamw (aclp->z_ops.ace_type_get(acep) == ALLOW)) { 1777b3d141f8Smarks mask &= ~RESTRICTED_CLEAR; 1778da6c28aaSamw aclp->z_ops.ace_mask_set(acep, mask); 1779da6c28aaSamw } 1780da6c28aaSamw } 1781da6c28aaSamw 1782da6c28aaSamw /* 1783da6c28aaSamw * Should ACE be inherited? 1784da6c28aaSamw */ 1785da6c28aaSamw static int 178689459e17SMark Shellenbaum zfs_ace_can_use(vtype_t vtype, uint16_t acep_flags) 1787da6c28aaSamw { 1788da6c28aaSamw int iflags = (acep_flags & 0xf); 1789da6c28aaSamw 1790da6c28aaSamw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE)) 1791da6c28aaSamw return (1); 1792da6c28aaSamw else if (iflags & ACE_FILE_INHERIT_ACE) 1793da6c28aaSamw return (!((vtype == VDIR) && 1794da6c28aaSamw (iflags & ACE_NO_PROPAGATE_INHERIT_ACE))); 1795da6c28aaSamw return (0); 1796fa9e4066Sahrens } 1797fa9e4066Sahrens 1798fa9e4066Sahrens /* 1799fa9e4066Sahrens * inherit inheritable ACEs from parent 1800fa9e4066Sahrens */ 1801fa9e4066Sahrens static zfs_acl_t * 180289459e17SMark Shellenbaum zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, 180389459e17SMark Shellenbaum uint64_t mode, boolean_t *need_chmod) 1804fa9e4066Sahrens { 1805da6c28aaSamw void *pacep; 1806da6c28aaSamw void *acep, *acep2; 1807da6c28aaSamw zfs_acl_node_t *aclnode, *aclnode2; 1808fa9e4066Sahrens zfs_acl_t *aclp = NULL; 1809da6c28aaSamw uint64_t who; 1810da6c28aaSamw uint32_t access_mask; 1811da6c28aaSamw uint16_t iflags, newflags, type; 1812da6c28aaSamw size_t ace_size; 1813da6c28aaSamw void *data1, *data2; 1814da6c28aaSamw size_t data1sz, data2sz; 181589459e17SMark Shellenbaum boolean_t vdir = vtype == VDIR; 181689459e17SMark Shellenbaum boolean_t vreg = vtype == VREG; 1817d0f3f37eSMark Shellenbaum boolean_t passthrough, passthrough_x, noallow; 1818d0f3f37eSMark Shellenbaum 1819d0f3f37eSMark Shellenbaum passthrough_x = 1820d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X; 1821d0f3f37eSMark Shellenbaum passthrough = passthrough_x || 1822d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH; 1823d0f3f37eSMark Shellenbaum noallow = 1824d0f3f37eSMark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW; 1825fa9e4066Sahrens 1826b3d141f8Smarks *need_chmod = B_TRUE; 1827da6c28aaSamw pacep = NULL; 1828003c2582SMark Shellenbaum aclp = zfs_acl_alloc(paclp->z_version); 1829*0a586ceaSMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK) 1830d0f3f37eSMark Shellenbaum return (aclp); 1831da6c28aaSamw while (pacep = zfs_acl_next_ace(paclp, pacep, &who, 1832da6c28aaSamw &access_mask, &iflags, &type)) { 1833fa9e4066Sahrens 1834003c2582SMark Shellenbaum /* 1835003c2582SMark Shellenbaum * don't inherit bogus ACEs 1836003c2582SMark Shellenbaum */ 1837003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 1838003c2582SMark Shellenbaum continue; 1839003c2582SMark Shellenbaum 1840d0f3f37eSMark Shellenbaum if (noallow && type == ALLOW) 1841fa9e4066Sahrens continue; 1842fa9e4066Sahrens 1843da6c28aaSamw ace_size = aclp->z_ops.ace_size(pacep); 1844fa9e4066Sahrens 184589459e17SMark Shellenbaum if (!zfs_ace_can_use(vtype, iflags)) 1846b3d141f8Smarks continue; 1847fa9e4066Sahrens 1848b3d141f8Smarks /* 1849b3d141f8Smarks * If owner@, group@, or everyone@ inheritable 1850b3d141f8Smarks * then zfs_acl_chmod() isn't needed. 1851b3d141f8Smarks */ 1852d0f3f37eSMark Shellenbaum if (passthrough && 1853b3d141f8Smarks ((iflags & (ACE_OWNER|ACE_EVERYONE)) || 1854b3d141f8Smarks ((iflags & OWNING_GROUP) == 1855d0f3f37eSMark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags & 1856d0f3f37eSMark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)))) { 1857b3d141f8Smarks *need_chmod = B_FALSE; 1858b3d141f8Smarks 1859d0f3f37eSMark Shellenbaum if (!vdir && passthrough_x && 1860d0f3f37eSMark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) { 1861d0f3f37eSMark Shellenbaum access_mask &= ~ACE_EXECUTE; 1862d0f3f37eSMark Shellenbaum } 1863d0f3f37eSMark Shellenbaum } 1864d0f3f37eSMark Shellenbaum 1865b3d141f8Smarks aclnode = zfs_acl_node_alloc(ace_size); 1866da6c28aaSamw list_insert_tail(&aclp->z_acl, aclnode); 1867da6c28aaSamw acep = aclnode->z_acldata; 1868d0f3f37eSMark Shellenbaum 1869da6c28aaSamw zfs_set_ace(aclp, acep, access_mask, type, 1870da6c28aaSamw who, iflags|ACE_INHERITED_ACE); 1871169cdae2Smarks 1872fa9e4066Sahrens /* 1873da6c28aaSamw * Copy special opaque data if any 1874fa9e4066Sahrens */ 1875d0f3f37eSMark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) { 1876b3d141f8Smarks VERIFY((data2sz = aclp->z_ops.ace_data(acep, 1877da6c28aaSamw &data2)) == data1sz); 1878da6c28aaSamw bcopy(data1, data2, data2sz); 1879da6c28aaSamw } 1880da6c28aaSamw aclp->z_acl_count++; 1881da6c28aaSamw aclnode->z_ace_count++; 1882da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1883da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1884b3d141f8Smarks 1885d0f3f37eSMark Shellenbaum if (vdir) 1886b3d141f8Smarks aclp->z_hints |= ZFS_INHERIT_ACE; 1887b3d141f8Smarks 1888d0f3f37eSMark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) { 1889da6c28aaSamw newflags &= ~ALL_INHERIT; 1890da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1891da6c28aaSamw newflags|ACE_INHERITED_ACE); 1892b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep); 1893fa9e4066Sahrens continue; 1894fa9e4066Sahrens } 1895fa9e4066Sahrens 1896d0f3f37eSMark Shellenbaum ASSERT(vdir); 1897fa9e4066Sahrens 1898da6c28aaSamw newflags = aclp->z_ops.ace_flags_get(acep); 1899da6c28aaSamw if ((iflags & (ACE_FILE_INHERIT_ACE | 1900169cdae2Smarks ACE_DIRECTORY_INHERIT_ACE)) != 190155601ddbSmarks ACE_FILE_INHERIT_ACE) { 1902da6c28aaSamw aclnode2 = zfs_acl_node_alloc(ace_size); 1903b3d141f8Smarks list_insert_tail(&aclp->z_acl, aclnode2); 1904da6c28aaSamw acep2 = aclnode2->z_acldata; 1905da6c28aaSamw zfs_set_ace(aclp, acep2, 1906da6c28aaSamw access_mask, type, who, 1907da6c28aaSamw iflags|ACE_INHERITED_ACE); 1908da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1909b3d141f8Smarks aclp->z_ops.ace_flags_set(acep, newflags); 1910da6c28aaSamw newflags &= ~ALL_INHERIT; 1911da6c28aaSamw aclp->z_ops.ace_flags_set(acep2, 1912da6c28aaSamw newflags|ACE_INHERITED_ACE); 1913fa9e4066Sahrens 1914da6c28aaSamw /* 1915da6c28aaSamw * Copy special opaque data if any 1916da6c28aaSamw */ 1917b3d141f8Smarks if ((data1sz = aclp->z_ops.ace_data(acep, 1918da6c28aaSamw &data1)) != 0) { 1919da6c28aaSamw VERIFY((data2sz = 1920da6c28aaSamw aclp->z_ops.ace_data(acep2, 1921da6c28aaSamw &data2)) == data1sz); 1922da6c28aaSamw bcopy(data1, data2, data1sz); 1923da6c28aaSamw } 1924da6c28aaSamw aclp->z_acl_count++; 1925da6c28aaSamw aclnode2->z_ace_count++; 1926da6c28aaSamw aclp->z_acl_bytes += aclnode->z_size; 1927b3d141f8Smarks zfs_restricted_update(zfsvfs, aclp, acep2); 1928da6c28aaSamw } else { 1929da6c28aaSamw newflags |= ACE_INHERIT_ONLY_ACE; 1930da6c28aaSamw aclp->z_ops.ace_flags_set(acep, 1931da6c28aaSamw newflags|ACE_INHERITED_ACE); 1932da6c28aaSamw } 1933da6c28aaSamw } 1934fa9e4066Sahrens return (aclp); 1935fa9e4066Sahrens } 1936fa9e4066Sahrens 1937fa9e4066Sahrens /* 1938fa9e4066Sahrens * Create file system object initial permissions 1939fa9e4066Sahrens * including inheritable ACEs. 1940fa9e4066Sahrens */ 194189459e17SMark Shellenbaum int 194289459e17SMark Shellenbaum zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, 194389459e17SMark Shellenbaum vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) 1944fa9e4066Sahrens { 1945fa9e4066Sahrens int error; 194689459e17SMark Shellenbaum zfsvfs_t *zfsvfs = dzp->z_zfsvfs; 1947da6c28aaSamw zfs_acl_t *paclp; 1948e0d35c44Smarks gid_t gid; 1949b3d141f8Smarks boolean_t need_chmod = B_TRUE; 1950*0a586ceaSMark Shellenbaum boolean_t inherited = B_FALSE; 1951*0a586ceaSMark Shellenbaum uint64_t parentgid; 1952da6c28aaSamw 195389459e17SMark Shellenbaum bzero(acl_ids, sizeof (zfs_acl_ids_t)); 195489459e17SMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1955fa9e4066Sahrens 195689459e17SMark Shellenbaum if (vsecp) 195789459e17SMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr, 195889459e17SMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0) 195989459e17SMark Shellenbaum return (error); 1960fa9e4066Sahrens /* 1961fa9e4066Sahrens * Determine uid and gid. 1962fa9e4066Sahrens */ 19634a1f0cc9SMark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay || 1964fa9e4066Sahrens ((flag & IS_XATTR) && (vap->va_type == VDIR))) { 196589459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create(zfsvfs, 196689459e17SMark Shellenbaum (uint64_t)vap->va_uid, cr, 196789459e17SMark Shellenbaum ZFS_OWNER, &acl_ids->z_fuidp); 196889459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 196989459e17SMark Shellenbaum (uint64_t)vap->va_gid, cr, 197089459e17SMark Shellenbaum ZFS_GROUP, &acl_ids->z_fuidp); 1971e0d35c44Smarks gid = vap->va_gid; 1972fa9e4066Sahrens } else { 1973*0a586ceaSMark Shellenbaum if (IS_EPHEMERAL(dzp->z_gid)) 1974*0a586ceaSMark Shellenbaum VERIFY(0 == sa_lookup(dzp->z_sa_hdl, SA_ZPL_GID(zfsvfs), 1975*0a586ceaSMark Shellenbaum &parentgid, sizeof (parentgid))); 1976*0a586ceaSMark Shellenbaum else 1977*0a586ceaSMark Shellenbaum parentgid = (uint64_t)dzp->z_gid; 1978*0a586ceaSMark Shellenbaum 197989459e17SMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, 198089459e17SMark Shellenbaum cr, &acl_ids->z_fuidp); 198189459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1982e0d35c44Smarks if (vap->va_mask & AT_GID) { 198389459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create(zfsvfs, 198489459e17SMark Shellenbaum (uint64_t)vap->va_gid, 198589459e17SMark Shellenbaum cr, ZFS_GROUP, &acl_ids->z_fuidp); 1986e0d35c44Smarks gid = vap->va_gid; 1987*0a586ceaSMark Shellenbaum if (acl_ids->z_fgid != parentgid && 1988e0d35c44Smarks !groupmember(vap->va_gid, cr) && 1989e0d35c44Smarks secpolicy_vnode_create_gid(cr) != 0) 199089459e17SMark Shellenbaum acl_ids->z_fgid = 0; 1991e0d35c44Smarks } 199289459e17SMark Shellenbaum if (acl_ids->z_fgid == 0) { 1993*0a586ceaSMark Shellenbaum if (dzp->z_mode & S_ISGID) { 1994b3874165SJohn Harres char *domain; 1995b3874165SJohn Harres uint32_t rid; 1996b3874165SJohn Harres 1997*0a586ceaSMark Shellenbaum acl_ids->z_fgid = parentgid; 199889459e17SMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid, 1999e0d35c44Smarks cr, ZFS_GROUP); 2000b3874165SJohn Harres 2001b3874165SJohn Harres if (zfsvfs->z_use_fuids && 2002b3874165SJohn Harres IS_EPHEMERAL(acl_ids->z_fgid)) { 2003b3874165SJohn Harres domain = zfs_fuid_idx_domain( 2004b3874165SJohn Harres &zfsvfs->z_fuid_idx, 2005b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid)); 2006b3874165SJohn Harres rid = FUID_RID(acl_ids->z_fgid); 2007b3874165SJohn Harres zfs_fuid_node_add(&acl_ids->z_fuidp, 2008b3874165SJohn Harres domain, rid, 2009b3874165SJohn Harres FUID_INDEX(acl_ids->z_fgid), 2010b3874165SJohn Harres acl_ids->z_fgid, ZFS_GROUP); 2011b3874165SJohn Harres } 2012da6c28aaSamw } else { 201389459e17SMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs, 201489459e17SMark Shellenbaum ZFS_GROUP, cr, &acl_ids->z_fuidp); 2015e0d35c44Smarks gid = crgetgid(cr); 2016e0d35c44Smarks } 2017da6c28aaSamw } 2018fa9e4066Sahrens } 2019fa9e4066Sahrens 2020fa9e4066Sahrens /* 2021fa9e4066Sahrens * If we're creating a directory, and the parent directory has the 2022fa9e4066Sahrens * set-GID bit set, set in on the new directory. 2023fa9e4066Sahrens * Otherwise, if the user is neither privileged nor a member of the 2024fa9e4066Sahrens * file's new group, clear the file's set-GID bit. 2025fa9e4066Sahrens */ 2026fa9e4066Sahrens 2027*0a586ceaSMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) && 202889459e17SMark Shellenbaum (vap->va_type == VDIR)) { 202989459e17SMark Shellenbaum acl_ids->z_mode |= S_ISGID; 2030e0d35c44Smarks } else { 203189459e17SMark Shellenbaum if ((acl_ids->z_mode & S_ISGID) && 2032fa9e4066Sahrens secpolicy_vnode_setids_setgids(cr, gid) != 0) 203389459e17SMark Shellenbaum acl_ids->z_mode &= ~S_ISGID; 2034fa9e4066Sahrens } 2035fa9e4066Sahrens 203689459e17SMark Shellenbaum if (acl_ids->z_aclp == NULL) { 203789459e17SMark Shellenbaum mutex_enter(&dzp->z_lock); 203889459e17SMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR && 2039*0a586ceaSMark Shellenbaum (dzp->z_pflags & ZFS_INHERIT_ACE)) && 2040*0a586ceaSMark Shellenbaum !(dzp->z_pflags & ZFS_XATTR)) { 204189459e17SMark Shellenbaum mutex_enter(&dzp->z_acl_lock); 204289459e17SMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE)); 204389459e17SMark Shellenbaum acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, 204489459e17SMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod); 2045*0a586ceaSMark Shellenbaum mutex_exit(&dzp->z_acl_lock); 2046*0a586ceaSMark Shellenbaum inherited = B_TRUE; 2047fa9e4066Sahrens } else { 204889459e17SMark Shellenbaum acl_ids->z_aclp = 204989459e17SMark Shellenbaum zfs_acl_alloc(zfs_acl_version_zp(dzp)); 2050*0a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 2051fa9e4066Sahrens } 205289459e17SMark Shellenbaum mutex_exit(&dzp->z_lock); 205389459e17SMark Shellenbaum if (need_chmod) { 2054*0a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ? 205589459e17SMark Shellenbaum ZFS_ACL_AUTO_INHERIT : 0; 205689459e17SMark Shellenbaum zfs_acl_chmod(zfsvfs, acl_ids->z_fuid, 205789459e17SMark Shellenbaum acl_ids->z_mode, acl_ids->z_aclp); 205889459e17SMark Shellenbaum } 2059da6c28aaSamw } 2060da6c28aaSamw 2061*0a586ceaSMark Shellenbaum if (inherited || vsecp) { 2062*0a586ceaSMark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode, 2063*0a586ceaSMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints); 2064*0a586ceaSMark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0) 2065*0a586ceaSMark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL; 2066*0a586ceaSMark Shellenbaum } 2067*0a586ceaSMark Shellenbaum 206889459e17SMark Shellenbaum return (0); 2069fa9e4066Sahrens } 2070fa9e4066Sahrens 2071fa9e4066Sahrens /* 207289459e17SMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure 207389459e17SMark Shellenbaum */ 207489459e17SMark Shellenbaum void 207589459e17SMark Shellenbaum zfs_acl_ids_free(zfs_acl_ids_t *acl_ids) 207689459e17SMark Shellenbaum { 207789459e17SMark Shellenbaum if (acl_ids->z_aclp) 207889459e17SMark Shellenbaum zfs_acl_free(acl_ids->z_aclp); 207989459e17SMark Shellenbaum if (acl_ids->z_fuidp) 208089459e17SMark Shellenbaum zfs_fuid_info_free(acl_ids->z_fuidp); 208189459e17SMark Shellenbaum acl_ids->z_aclp = NULL; 208289459e17SMark Shellenbaum acl_ids->z_fuidp = NULL; 208389459e17SMark Shellenbaum } 208489459e17SMark Shellenbaum 208514843421SMatthew Ahrens boolean_t 208614843421SMatthew Ahrens zfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids) 208714843421SMatthew Ahrens { 2088*0a586ceaSMark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) || 2089*0a586ceaSMark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid)); 209014843421SMatthew Ahrens } 209189459e17SMark Shellenbaum 209289459e17SMark Shellenbaum /* 2093fa9e4066Sahrens * Retrieve a files ACL 2094fa9e4066Sahrens */ 2095fa9e4066Sahrens int 2096da6c28aaSamw zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 2097fa9e4066Sahrens { 2098fa9e4066Sahrens zfs_acl_t *aclp; 2099da6c28aaSamw ulong_t mask; 2100fa9e4066Sahrens int error; 2101da6c28aaSamw int count = 0; 2102da6c28aaSamw int largeace = 0; 2103fa9e4066Sahrens 2104da6c28aaSamw mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT | 2105da6c28aaSamw VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 2106da6c28aaSamw 2107fa9e4066Sahrens if (mask == 0) 2108fa9e4066Sahrens return (ENOSYS); 2109fa9e4066Sahrens 2110*0a586ceaSMark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)) 2111*0a586ceaSMark Shellenbaum return (error); 2112*0a586ceaSMark Shellenbaum 2113fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2114fa9e4066Sahrens 2115da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 2116ea8dc4b6Seschrock if (error != 0) { 2117ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2118ea8dc4b6Seschrock return (error); 2119ea8dc4b6Seschrock } 2120ea8dc4b6Seschrock 2121da6c28aaSamw /* 2122da6c28aaSamw * Scan ACL to determine number of ACEs 2123da6c28aaSamw */ 2124*0a586ceaSMark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) { 2125da6c28aaSamw void *zacep = NULL; 2126da6c28aaSamw uint64_t who; 2127da6c28aaSamw uint32_t access_mask; 2128da6c28aaSamw uint16_t type, iflags; 2129da6c28aaSamw 2130da6c28aaSamw while (zacep = zfs_acl_next_ace(aclp, zacep, 2131da6c28aaSamw &who, &access_mask, &iflags, &type)) { 2132da6c28aaSamw switch (type) { 2133da6c28aaSamw case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 2134da6c28aaSamw case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 2135da6c28aaSamw case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 2136da6c28aaSamw case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 2137da6c28aaSamw largeace++; 2138da6c28aaSamw continue; 2139da6c28aaSamw default: 2140da6c28aaSamw count++; 2141da6c28aaSamw } 2142da6c28aaSamw } 2143da6c28aaSamw vsecp->vsa_aclcnt = count; 2144da6c28aaSamw } else 2145*0a586ceaSMark Shellenbaum count = (int)aclp->z_acl_count; 2146fa9e4066Sahrens 2147fa9e4066Sahrens if (mask & VSA_ACECNT) { 2148da6c28aaSamw vsecp->vsa_aclcnt = count; 2149fa9e4066Sahrens } 2150fa9e4066Sahrens 2151fa9e4066Sahrens if (mask & VSA_ACE) { 2152da6c28aaSamw size_t aclsz; 2153da6c28aaSamw 2154da6c28aaSamw aclsz = count * sizeof (ace_t) + 2155da6c28aaSamw sizeof (ace_object_t) * largeace; 2156da6c28aaSamw 2157da6c28aaSamw vsecp->vsa_aclentp = kmem_alloc(aclsz, KM_SLEEP); 2158da6c28aaSamw vsecp->vsa_aclentsz = aclsz; 2159da6c28aaSamw 2160da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_FUID) 2161bda89588Sjp151216 zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, 2162da6c28aaSamw vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); 2163da6c28aaSamw else { 21642e7d9b42SMark Shellenbaum zfs_acl_node_t *aclnode; 21652e7d9b42SMark Shellenbaum void *start = vsecp->vsa_aclentp; 21662e7d9b42SMark Shellenbaum 21672e7d9b42SMark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode; 21682e7d9b42SMark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) { 21692e7d9b42SMark Shellenbaum bcopy(aclnode->z_acldata, start, 21702e7d9b42SMark Shellenbaum aclnode->z_size); 21712e7d9b42SMark Shellenbaum start = (caddr_t)start + aclnode->z_size; 21722e7d9b42SMark Shellenbaum } 21732e7d9b42SMark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == 21742e7d9b42SMark Shellenbaum aclp->z_acl_bytes); 2175da6c28aaSamw } 2176da6c28aaSamw } 2177da6c28aaSamw if (mask & VSA_ACE_ACLFLAGS) { 2178da6c28aaSamw vsecp->vsa_aclflags = 0; 2179*0a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_DEFAULTED) 2180da6c28aaSamw vsecp->vsa_aclflags |= ACL_DEFAULTED; 2181*0a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_PROTECTED) 2182da6c28aaSamw vsecp->vsa_aclflags |= ACL_PROTECTED; 2183*0a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_ACL_AUTO_INHERIT) 2184da6c28aaSamw vsecp->vsa_aclflags |= ACL_AUTO_INHERIT; 2185fa9e4066Sahrens } 2186fa9e4066Sahrens 2187fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2188fa9e4066Sahrens 2189fa9e4066Sahrens return (0); 2190fa9e4066Sahrens } 2191fa9e4066Sahrens 2192da6c28aaSamw int 2193da6c28aaSamw zfs_vsec_2_aclp(zfsvfs_t *zfsvfs, vtype_t obj_type, 219489459e17SMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp) 2195da6c28aaSamw { 2196da6c28aaSamw zfs_acl_t *aclp; 2197da6c28aaSamw zfs_acl_node_t *aclnode; 2198da6c28aaSamw int aclcnt = vsecp->vsa_aclcnt; 2199da6c28aaSamw int error; 2200da6c28aaSamw 2201da6c28aaSamw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0) 2202da6c28aaSamw return (EINVAL); 2203da6c28aaSamw 2204da6c28aaSamw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version)); 2205da6c28aaSamw 2206da6c28aaSamw aclp->z_hints = 0; 2207da6c28aaSamw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t)); 2208da6c28aaSamw if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) { 2209da6c28aaSamw if ((error = zfs_copy_ace_2_oldace(obj_type, aclp, 2210da6c28aaSamw (ace_t *)vsecp->vsa_aclentp, aclnode->z_acldata, 2211da6c28aaSamw aclcnt, &aclnode->z_size)) != 0) { 2212da6c28aaSamw zfs_acl_free(aclp); 2213da6c28aaSamw zfs_acl_node_free(aclnode); 2214da6c28aaSamw return (error); 2215da6c28aaSamw } 2216da6c28aaSamw } else { 221789459e17SMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp, 2218da6c28aaSamw vsecp->vsa_aclentp, aclnode->z_acldata, aclcnt, 221989459e17SMark Shellenbaum &aclnode->z_size, fuidp, cr)) != 0) { 2220da6c28aaSamw zfs_acl_free(aclp); 2221da6c28aaSamw zfs_acl_node_free(aclnode); 2222da6c28aaSamw return (error); 2223da6c28aaSamw } 2224da6c28aaSamw } 2225da6c28aaSamw aclp->z_acl_bytes = aclnode->z_size; 2226da6c28aaSamw aclnode->z_ace_count = aclcnt; 2227da6c28aaSamw aclp->z_acl_count = aclcnt; 2228da6c28aaSamw list_insert_head(&aclp->z_acl, aclnode); 2229da6c28aaSamw 2230da6c28aaSamw /* 2231da6c28aaSamw * If flags are being set then add them to z_hints 2232da6c28aaSamw */ 2233da6c28aaSamw if (vsecp->vsa_mask & VSA_ACE_ACLFLAGS) { 2234da6c28aaSamw if (vsecp->vsa_aclflags & ACL_PROTECTED) 2235da6c28aaSamw aclp->z_hints |= ZFS_ACL_PROTECTED; 2236da6c28aaSamw if (vsecp->vsa_aclflags & ACL_DEFAULTED) 2237da6c28aaSamw aclp->z_hints |= ZFS_ACL_DEFAULTED; 2238da6c28aaSamw if (vsecp->vsa_aclflags & ACL_AUTO_INHERIT) 2239da6c28aaSamw aclp->z_hints |= ZFS_ACL_AUTO_INHERIT; 2240da6c28aaSamw } 2241da6c28aaSamw 2242da6c28aaSamw *zaclp = aclp; 2243da6c28aaSamw 2244da6c28aaSamw return (0); 2245da6c28aaSamw } 2246da6c28aaSamw 2247fa9e4066Sahrens /* 2248fa9e4066Sahrens * Set a files ACL 2249fa9e4066Sahrens */ 2250fa9e4066Sahrens int 2251da6c28aaSamw zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) 2252fa9e4066Sahrens { 2253fa9e4066Sahrens zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2254fa9e4066Sahrens zilog_t *zilog = zfsvfs->z_log; 2255fa9e4066Sahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT); 2256fa9e4066Sahrens dmu_tx_t *tx; 2257fa9e4066Sahrens int error; 2258fa9e4066Sahrens zfs_acl_t *aclp; 2259da6c28aaSamw zfs_fuid_info_t *fuidp = NULL; 226089459e17SMark Shellenbaum boolean_t fuid_dirtied; 2261fa9e4066Sahrens 2262fa9e4066Sahrens if (mask == 0) 22637106075aSmarks return (ENOSYS); 2264fa9e4066Sahrens 2265*0a586ceaSMark Shellenbaum if (zp->z_pflags & ZFS_IMMUTABLE) 2266da6c28aaSamw return (EPERM); 2267da6c28aaSamw 2268da6c28aaSamw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) 2269fa9e4066Sahrens return (error); 2270da6c28aaSamw 227189459e17SMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, 227289459e17SMark Shellenbaum &aclp); 2273da6c28aaSamw if (error) 2274da6c28aaSamw return (error); 2275da6c28aaSamw 2276da6c28aaSamw /* 2277da6c28aaSamw * If ACL wide flags aren't being set then preserve any 2278da6c28aaSamw * existing flags. 2279da6c28aaSamw */ 2280da6c28aaSamw if (!(vsecp->vsa_mask & VSA_ACE_ACLFLAGS)) { 2281*0a586ceaSMark Shellenbaum aclp->z_hints |= 2282*0a586ceaSMark Shellenbaum (zp->z_pflags & V4_ACL_WIDE_FLAGS); 2283fa9e4066Sahrens } 2284da6c28aaSamw top: 2285fa9e4066Sahrens mutex_enter(&zp->z_lock); 2286fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2287fa9e4066Sahrens 2288fa9e4066Sahrens tx = dmu_tx_create(zfsvfs->z_os); 2289fa9e4066Sahrens 2290*0a586ceaSMark Shellenbaum dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE); 2291*0a586ceaSMark Shellenbaum 229289459e17SMark Shellenbaum fuid_dirtied = zfsvfs->z_fuid_dirty; 229314843421SMatthew Ahrens if (fuid_dirtied) 229414843421SMatthew Ahrens zfs_fuid_txhold(zfsvfs, tx); 2295fa9e4066Sahrens 2296*0a586ceaSMark Shellenbaum /* 2297*0a586ceaSMark Shellenbaum * If old version and ACL won't fit in bonus and we aren't 2298*0a586ceaSMark Shellenbaum * upgrading then take out necessary DMU holds 2299*0a586ceaSMark Shellenbaum */ 2300*0a586ceaSMark Shellenbaum 2301*0a586ceaSMark Shellenbaum if (ZFS_EXTERNAL_ACL(zp)) { 2302*0a586ceaSMark Shellenbaum if (zfsvfs->z_version <= ZPL_VERSION_SA && 2303*0a586ceaSMark Shellenbaum ZNODE_ACL_VERSION(zp) <= ZFS_ACL_VERSION_INITIAL) { 2304*0a586ceaSMark Shellenbaum dmu_tx_hold_free(tx, ZFS_EXTERNAL_ACL(zp), 0, 2305*0a586ceaSMark Shellenbaum DMU_OBJECT_END); 2306*0a586ceaSMark Shellenbaum } else { 2307*0a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, ZFS_EXTERNAL_ACL(zp), 2308*0a586ceaSMark Shellenbaum 0, aclp->z_acl_bytes); 2309*0a586ceaSMark Shellenbaum } 2310*0a586ceaSMark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) { 2311*0a586ceaSMark Shellenbaum dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes); 2312*0a586ceaSMark Shellenbaum } 2313*0a586ceaSMark Shellenbaum 2314*0a586ceaSMark Shellenbaum zfs_sa_upgrade_txholds(tx, zp); 23151209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_NOWAIT); 2316fa9e4066Sahrens if (error) { 2317fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2318fa9e4066Sahrens mutex_exit(&zp->z_lock); 2319fa9e4066Sahrens 23201209a471SNeil Perrin if (error == ERESTART) { 23218a2f1b91Sahrens dmu_tx_wait(tx); 23228a2f1b91Sahrens dmu_tx_abort(tx); 2323fa9e4066Sahrens goto top; 2324fa9e4066Sahrens } 23258a2f1b91Sahrens dmu_tx_abort(tx); 2326da6c28aaSamw zfs_acl_free(aclp); 2327fa9e4066Sahrens return (error); 2328fa9e4066Sahrens } 2329fa9e4066Sahrens 233089459e17SMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx); 2331fa9e4066Sahrens ASSERT(error == 0); 23324929fd5eSTim Haley zp->z_acl_cached = aclp; 2333fa9e4066Sahrens 233489459e17SMark Shellenbaum if (fuid_dirtied) 233589459e17SMark Shellenbaum zfs_fuid_sync(zfsvfs, tx); 233689459e17SMark Shellenbaum 2337da6c28aaSamw zfs_log_acl(zilog, tx, zp, vsecp, fuidp); 2338da6c28aaSamw 2339da6c28aaSamw if (fuidp) 2340da6c28aaSamw zfs_fuid_info_free(fuidp); 2341fa9e4066Sahrens dmu_tx_commit(tx); 2342fa9e4066Sahrens done: 2343fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2344fa9e4066Sahrens mutex_exit(&zp->z_lock); 2345fa9e4066Sahrens 2346fa9e4066Sahrens return (error); 2347fa9e4066Sahrens } 2348fa9e4066Sahrens 2349fa9e4066Sahrens /* 2350e802abbdSTim Haley * Check accesses of interest (AoI) against attributes of the dataset 2351e802abbdSTim Haley * such as read-only. Returns zero if no AoI conflict with dataset 2352e802abbdSTim Haley * attributes, otherwise an appropriate errno is returned. 2353fa9e4066Sahrens */ 2354fa9e4066Sahrens static int 2355e802abbdSTim Haley zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) 2356fa9e4066Sahrens { 2357fa9e4066Sahrens if ((v4_mode & WRITE_MASK) && 2358fa9e4066Sahrens (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && 2359f52e0e2bSMark Shellenbaum (!IS_DEVVP(ZTOV(zp)) || 2360f52e0e2bSMark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { 2361fa9e4066Sahrens return (EROFS); 2362fa9e4066Sahrens } 2363fa9e4066Sahrens 2364da6c28aaSamw /* 2365da6c28aaSamw * Only check for READONLY on non-directories. 2366da6c28aaSamw */ 2367da6c28aaSamw if ((v4_mode & WRITE_MASK_DATA) && 2368da6c28aaSamw (((ZTOV(zp)->v_type != VDIR) && 2369*0a586ceaSMark Shellenbaum (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) || 2370da6c28aaSamw (ZTOV(zp)->v_type == VDIR && 2371*0a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_IMMUTABLE)))) { 2372da6c28aaSamw return (EPERM); 2373da6c28aaSamw } 2374da6c28aaSamw 2375da6c28aaSamw if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && 2376*0a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_NOUNLINK)) { 2377da6c28aaSamw return (EPERM); 2378da6c28aaSamw } 2379da6c28aaSamw 2380da6c28aaSamw if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && 2381*0a586ceaSMark Shellenbaum (zp->z_pflags & ZFS_AV_QUARANTINED))) { 2382da6c28aaSamw return (EACCES); 2383da6c28aaSamw } 2384da6c28aaSamw 2385da6c28aaSamw return (0); 2386da6c28aaSamw } 2387da6c28aaSamw 2388e802abbdSTim Haley /* 2389e802abbdSTim Haley * The primary usage of this function is to loop through all of the 2390e802abbdSTim Haley * ACEs in the znode, determining what accesses of interest (AoI) to 2391e802abbdSTim Haley * the caller are allowed or denied. The AoI are expressed as bits in 2392e802abbdSTim Haley * the working_mode parameter. As each ACE is processed, bits covered 2393e802abbdSTim Haley * by that ACE are removed from the working_mode. This removal 2394e802abbdSTim Haley * facilitates two things. The first is that when the working mode is 2395e802abbdSTim Haley * empty (= 0), we know we've looked at all the AoI. The second is 2396e802abbdSTim Haley * that the ACE interpretation rules don't allow a later ACE to undo 2397e802abbdSTim Haley * something granted or denied by an earlier ACE. Removing the 2398e802abbdSTim Haley * discovered access or denial enforces this rule. At the end of 2399e802abbdSTim Haley * processing the ACEs, all AoI that were found to be denied are 2400e802abbdSTim Haley * placed into the working_mode, giving the caller a mask of denied 2401e802abbdSTim Haley * accesses. Returns: 2402e802abbdSTim Haley * 0 if all AoI granted 2403e802abbdSTim Haley * EACCESS if the denied mask is non-zero 2404e802abbdSTim Haley * other error if abnormal failure (e.g., IO error) 2405e802abbdSTim Haley * 2406e802abbdSTim Haley * A secondary usage of the function is to determine if any of the 2407e802abbdSTim Haley * AoI are granted. If an ACE grants any access in 2408e802abbdSTim Haley * the working_mode, we immediately short circuit out of the function. 2409e802abbdSTim Haley * This mode is chosen by setting anyaccess to B_TRUE. The 2410e802abbdSTim Haley * working_mode is not a denied access mask upon exit if the function 2411e802abbdSTim Haley * is used in this manner. 2412e802abbdSTim Haley */ 2413e802abbdSTim Haley static int 2414e802abbdSTim Haley zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, 2415e802abbdSTim Haley boolean_t anyaccess, cred_t *cr) 2416e802abbdSTim Haley { 2417e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2418e802abbdSTim Haley zfs_acl_t *aclp; 2419e802abbdSTim Haley int error; 2420e802abbdSTim Haley uid_t uid = crgetuid(cr); 2421e802abbdSTim Haley uint64_t who; 2422e802abbdSTim Haley uint16_t type, iflags; 2423e802abbdSTim Haley uint16_t entry_type; 2424e802abbdSTim Haley uint32_t access_mask; 2425e802abbdSTim Haley uint32_t deny_mask = 0; 2426e802abbdSTim Haley zfs_ace_hdr_t *acep = NULL; 2427e802abbdSTim Haley boolean_t checkit; 2428*0a586ceaSMark Shellenbaum uint64_t gowner; 2429da6c28aaSamw 2430fa9e4066Sahrens mutex_enter(&zp->z_acl_lock); 2431fa9e4066Sahrens 2432da6c28aaSamw error = zfs_acl_node_read(zp, &aclp, B_FALSE); 2433ea8dc4b6Seschrock if (error != 0) { 2434ea8dc4b6Seschrock mutex_exit(&zp->z_acl_lock); 2435ea8dc4b6Seschrock return (error); 2436ea8dc4b6Seschrock } 2437ea8dc4b6Seschrock 2438*0a586ceaSMark Shellenbaum ASSERT(zp->z_acl_cached); 2439*0a586ceaSMark Shellenbaum 2440*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs), 2441*0a586ceaSMark Shellenbaum &gowner, sizeof (gowner))) != 0) 2442*0a586ceaSMark Shellenbaum return (error); 2443*0a586ceaSMark Shellenbaum 2444da6c28aaSamw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, 2445da6c28aaSamw &iflags, &type)) { 2446e802abbdSTim Haley uint32_t mask_matched; 2447fa9e4066Sahrens 2448003c2582SMark Shellenbaum if (!zfs_acl_valid_ace_type(type, iflags)) 2449003c2582SMark Shellenbaum continue; 2450003c2582SMark Shellenbaum 2451b249c65cSmarks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) 2452fa9e4066Sahrens continue; 2453fa9e4066Sahrens 2454e802abbdSTim Haley /* Skip ACE if it does not affect any AoI */ 2455e802abbdSTim Haley mask_matched = (access_mask & *working_mode); 2456e802abbdSTim Haley if (!mask_matched) 2457e802abbdSTim Haley continue; 2458e802abbdSTim Haley 2459da6c28aaSamw entry_type = (iflags & ACE_TYPE_FLAGS); 2460da6c28aaSamw 2461da6c28aaSamw checkit = B_FALSE; 2462da6c28aaSamw 2463fa9e4066Sahrens switch (entry_type) { 2464fa9e4066Sahrens case ACE_OWNER: 2465*0a586ceaSMark Shellenbaum if (uid == zp->z_uid) 2466da6c28aaSamw checkit = B_TRUE; 2467fa9e4066Sahrens break; 2468da6c28aaSamw case OWNING_GROUP: 2469da6c28aaSamw who = gowner; 2470da6c28aaSamw /*FALLTHROUGH*/ 2471fa9e4066Sahrens case ACE_IDENTIFIER_GROUP: 2472da6c28aaSamw checkit = zfs_groupmember(zfsvfs, who, cr); 2473fa9e4066Sahrens break; 2474fa9e4066Sahrens case ACE_EVERYONE: 2475da6c28aaSamw checkit = B_TRUE; 2476fa9e4066Sahrens break; 2477fa9e4066Sahrens 2478fa9e4066Sahrens /* USER Entry */ 2479fa9e4066Sahrens default: 2480fa9e4066Sahrens if (entry_type == 0) { 2481da6c28aaSamw uid_t newid; 2482da6c28aaSamw 2483e0d35c44Smarks newid = zfs_fuid_map_id(zfsvfs, who, cr, 2484e0d35c44Smarks ZFS_ACE_USER); 2485da6c28aaSamw if (newid != IDMAP_WK_CREATOR_OWNER_UID && 2486da6c28aaSamw uid == newid) 2487da6c28aaSamw checkit = B_TRUE; 2488fa9e4066Sahrens break; 2489da6c28aaSamw } else { 2490fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 2491fa9e4066Sahrens return (EIO); 2492fa9e4066Sahrens } 2493da6c28aaSamw } 2494da6c28aaSamw 2495da6c28aaSamw if (checkit) { 2496e802abbdSTim Haley if (type == DENY) { 2497e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__denies, 2498e802abbdSTim Haley znode_t *, zp, 2499e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2500e802abbdSTim Haley uint32_t, mask_matched); 250190fafcf0Smarks deny_mask |= mask_matched; 2502e802abbdSTim Haley } else { 2503e802abbdSTim Haley DTRACE_PROBE3(zfs__ace__allows, 2504e802abbdSTim Haley znode_t *, zp, 2505e802abbdSTim Haley zfs_ace_hdr_t *, acep, 2506e802abbdSTim Haley uint32_t, mask_matched); 2507e802abbdSTim Haley if (anyaccess) { 2508e802abbdSTim Haley mutex_exit(&zp->z_acl_lock); 2509e802abbdSTim Haley return (0); 2510da6c28aaSamw } 2511da6c28aaSamw } 2512e802abbdSTim Haley *working_mode &= ~mask_matched; 2513e802abbdSTim Haley } 2514fa9e4066Sahrens 251590fafcf0Smarks /* Are we done? */ 251690fafcf0Smarks if (*working_mode == 0) 2517fa9e4066Sahrens break; 2518fa9e4066Sahrens } 2519fa9e4066Sahrens 2520fa9e4066Sahrens mutex_exit(&zp->z_acl_lock); 252190fafcf0Smarks 252290fafcf0Smarks /* Put the found 'denies' back on the working mode */ 25237ed7e920Smarks if (deny_mask) { 252490fafcf0Smarks *working_mode |= deny_mask; 252590fafcf0Smarks return (EACCES); 25267ed7e920Smarks } else if (*working_mode) { 25277ed7e920Smarks return (-1); 25287ed7e920Smarks } 252990fafcf0Smarks 253090fafcf0Smarks return (0); 2531fa9e4066Sahrens } 2532fa9e4066Sahrens 2533e802abbdSTim Haley /* 2534e802abbdSTim Haley * Return true if any access whatsoever granted, we don't actually 2535e802abbdSTim Haley * care what access is granted. 2536e802abbdSTim Haley */ 2537e802abbdSTim Haley boolean_t 2538e802abbdSTim Haley zfs_has_access(znode_t *zp, cred_t *cr) 2539e802abbdSTim Haley { 2540e802abbdSTim Haley uint32_t have = ACE_ALL_PERMS; 2541e802abbdSTim Haley 2542e802abbdSTim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { 2543e802abbdSTim Haley return ( 2544*0a586ceaSMark Shellenbaum secpolicy_vnode_access(cr, ZTOV(zp), 2545*0a586ceaSMark Shellenbaum zp->z_uid, VREAD) == 0 || secpolicy_vnode_access(cr, 2546*0a586ceaSMark Shellenbaum ZTOV(zp), zp->z_uid, VWRITE) == 0 || 2547*0a586ceaSMark Shellenbaum secpolicy_vnode_access(cr, ZTOV(zp), 2548*0a586ceaSMark Shellenbaum zp->z_uid, VEXEC) == 0 || 2549*0a586ceaSMark Shellenbaum secpolicy_vnode_chown(cr, zp->z_uid) == 0 || 2550*0a586ceaSMark Shellenbaum secpolicy_vnode_setdac(cr, zp->z_uid) == 0 || 2551e802abbdSTim Haley secpolicy_vnode_remove(cr) == 0); 2552e802abbdSTim Haley } 2553e802abbdSTim Haley return (B_TRUE); 2554e802abbdSTim Haley } 2555e802abbdSTim Haley 2556e802abbdSTim Haley static int 2557e802abbdSTim Haley zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, 2558e802abbdSTim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) 2559e802abbdSTim Haley { 2560e802abbdSTim Haley zfsvfs_t *zfsvfs = zp->z_zfsvfs; 2561e802abbdSTim Haley int err; 2562e802abbdSTim Haley 2563e802abbdSTim Haley *working_mode = v4_mode; 2564e802abbdSTim Haley *check_privs = B_TRUE; 2565e802abbdSTim Haley 2566e802abbdSTim Haley /* 2567e802abbdSTim Haley * Short circuit empty requests 2568e802abbdSTim Haley */ 2569e802abbdSTim Haley if (v4_mode == 0 || zfsvfs->z_replay) { 2570e802abbdSTim Haley *working_mode = 0; 2571e802abbdSTim Haley return (0); 2572e802abbdSTim Haley } 2573e802abbdSTim Haley 2574e802abbdSTim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { 2575e802abbdSTim Haley *check_privs = B_FALSE; 2576e802abbdSTim Haley return (err); 2577e802abbdSTim Haley } 2578e802abbdSTim Haley 2579e802abbdSTim Haley /* 2580e802abbdSTim Haley * The caller requested that the ACL check be skipped. This 2581e802abbdSTim Haley * would only happen if the caller checked VOP_ACCESS() with a 2582e802abbdSTim Haley * 32 bit ACE mask and already had the appropriate permissions. 2583e802abbdSTim Haley */ 2584e802abbdSTim Haley if (skipaclchk) { 2585e802abbdSTim Haley *working_mode = 0; 2586e802abbdSTim Haley return (0); 2587e802abbdSTim Haley } 2588e802abbdSTim Haley 2589e802abbdSTim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); 2590e802abbdSTim Haley } 2591e802abbdSTim Haley 2592da6c28aaSamw static int 2593da6c28aaSamw zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, 2594da6c28aaSamw cred_t *cr) 2595da6c28aaSamw { 2596da6c28aaSamw if (*working_mode != ACE_WRITE_DATA) 2597da6c28aaSamw return (EACCES); 2598da6c28aaSamw 2599da6c28aaSamw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, 2600da6c28aaSamw check_privs, B_FALSE, cr)); 2601da6c28aaSamw } 2602fa9e4066Sahrens 2603d47621a4STim Haley int 2604d47621a4STim Haley zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) 2605d47621a4STim Haley { 2606d47621a4STim Haley boolean_t owner = B_FALSE; 2607d47621a4STim Haley boolean_t groupmbr = B_FALSE; 2608d47621a4STim Haley boolean_t is_attr; 2609d47621a4STim Haley uid_t uid = crgetuid(cr); 2610d47621a4STim Haley int error; 2611d47621a4STim Haley 2612*0a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_AV_QUARANTINED) 2613d47621a4STim Haley return (EACCES); 2614d47621a4STim Haley 2615*0a586ceaSMark Shellenbaum is_attr = ((zdp->z_pflags & ZFS_XATTR) && 2616d47621a4STim Haley (ZTOV(zdp)->v_type == VDIR)); 2617d47621a4STim Haley if (is_attr) 2618d47621a4STim Haley goto slow; 2619d47621a4STim Haley 2620*0a586ceaSMark Shellenbaum 2621d47621a4STim Haley mutex_enter(&zdp->z_acl_lock); 2622d47621a4STim Haley 2623*0a586ceaSMark Shellenbaum if (zdp->z_pflags & ZFS_NO_EXECS_DENIED) { 2624d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2625d47621a4STim Haley return (0); 2626d47621a4STim Haley } 2627d47621a4STim Haley 2628*0a586ceaSMark Shellenbaum if (IS_EPHEMERAL(zdp->z_uid) != 0 || IS_EPHEMERAL(zdp->z_gid) != 0) { 2629d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2630d47621a4STim Haley goto slow; 2631d47621a4STim Haley } 2632d47621a4STim Haley 2633*0a586ceaSMark Shellenbaum if (uid == zdp->z_uid) { 2634d47621a4STim Haley owner = B_TRUE; 2635*0a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXUSR) { 2636d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2637d47621a4STim Haley return (0); 2638e4f96946STim Haley } else { 2639e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2640e4f96946STim Haley goto slow; 2641d47621a4STim Haley } 2642d47621a4STim Haley } 2643*0a586ceaSMark Shellenbaum if (groupmember(zdp->z_gid, cr)) { 2644d47621a4STim Haley groupmbr = B_TRUE; 2645*0a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXGRP) { 2646d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2647d47621a4STim Haley return (0); 2648e4f96946STim Haley } else { 2649e4f96946STim Haley mutex_exit(&zdp->z_acl_lock); 2650e4f96946STim Haley goto slow; 2651d47621a4STim Haley } 2652d47621a4STim Haley } 2653d47621a4STim Haley if (!owner && !groupmbr) { 2654*0a586ceaSMark Shellenbaum if (zdp->z_mode & S_IXOTH) { 2655d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2656d47621a4STim Haley return (0); 2657d47621a4STim Haley } 2658d47621a4STim Haley } 2659d47621a4STim Haley 2660d47621a4STim Haley mutex_exit(&zdp->z_acl_lock); 2661d47621a4STim Haley 2662d47621a4STim Haley slow: 2663d47621a4STim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss); 2664d47621a4STim Haley ZFS_ENTER(zdp->z_zfsvfs); 2665d47621a4STim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); 2666d47621a4STim Haley ZFS_EXIT(zdp->z_zfsvfs); 2667d47621a4STim Haley return (error); 2668d47621a4STim Haley } 2669d47621a4STim Haley 2670fa9e4066Sahrens /* 2671fa9e4066Sahrens * Determine whether Access should be granted/denied, invoking least 2672fa9e4066Sahrens * priv subsytem when a deny is determined. 2673fa9e4066Sahrens */ 2674fa9e4066Sahrens int 2675da6c28aaSamw zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) 2676fa9e4066Sahrens { 2677da6c28aaSamw uint32_t working_mode; 2678fa9e4066Sahrens int error; 2679fa9e4066Sahrens int is_attr; 2680da6c28aaSamw boolean_t check_privs; 2681fa9e4066Sahrens znode_t *xzp; 2682fa9e4066Sahrens znode_t *check_zp = zp; 2683fa9e4066Sahrens 2684*0a586ceaSMark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); 2685fa9e4066Sahrens 2686fa9e4066Sahrens /* 2687fa9e4066Sahrens * If attribute then validate against base file 2688fa9e4066Sahrens */ 2689fa9e4066Sahrens if (is_attr) { 2690*0a586ceaSMark Shellenbaum uint64_t parent; 2691*0a586ceaSMark Shellenbaum 2692*0a586ceaSMark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, 2693*0a586ceaSMark Shellenbaum SA_ZPL_PARENT(zp->z_zfsvfs), &parent, 2694*0a586ceaSMark Shellenbaum sizeof (parent))) != 0) 2695*0a586ceaSMark Shellenbaum return (error); 2696*0a586ceaSMark Shellenbaum 2697fa9e4066Sahrens if ((error = zfs_zget(zp->z_zfsvfs, 2698*0a586ceaSMark Shellenbaum parent, &xzp)) != 0) { 2699fa9e4066Sahrens return (error); 2700fa9e4066Sahrens } 2701da6c28aaSamw 2702fa9e4066Sahrens check_zp = xzp; 2703da6c28aaSamw 2704fa9e4066Sahrens /* 2705fa9e4066Sahrens * fixup mode to map to xattr perms 2706fa9e4066Sahrens */ 2707fa9e4066Sahrens 2708fa9e4066Sahrens if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) { 2709fa9e4066Sahrens mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA); 2710fa9e4066Sahrens mode |= ACE_WRITE_NAMED_ATTRS; 2711fa9e4066Sahrens } 2712fa9e4066Sahrens 2713fa9e4066Sahrens if (mode & (ACE_READ_DATA|ACE_EXECUTE)) { 2714fa9e4066Sahrens mode &= ~(ACE_READ_DATA|ACE_EXECUTE); 2715fa9e4066Sahrens mode |= ACE_READ_NAMED_ATTRS; 2716fa9e4066Sahrens } 2717fa9e4066Sahrens } 2718fa9e4066Sahrens 2719da6c28aaSamw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, 2720da6c28aaSamw &check_privs, skipaclchk, cr)) == 0) { 2721da6c28aaSamw if (is_attr) 2722da6c28aaSamw VN_RELE(ZTOV(xzp)); 2723da6c28aaSamw return (0); 2724da6c28aaSamw } 2725fa9e4066Sahrens 2726e0d35c44Smarks if (error && !check_privs) { 2727fa9e4066Sahrens if (is_attr) 2728fa9e4066Sahrens VN_RELE(ZTOV(xzp)); 2729fa9e4066Sahrens return (error); 2730fa9e4066Sahrens } 2731fa9e4066Sahrens 2732da6c28aaSamw if (error && (flags & V_APPEND)) { 2733da6c28aaSamw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); 2734fa9e4066Sahrens } 2735fa9e4066Sahrens 2736da6c28aaSamw if (error && check_privs) { 2737da6c28aaSamw mode_t checkmode = 0; 2738fa9e4066Sahrens 2739fa9e4066Sahrens /* 2740da6c28aaSamw * First check for implicit owner permission on 2741da6c28aaSamw * read_acl/read_attributes 2742fa9e4066Sahrens */ 2743fa9e4066Sahrens 2744da6c28aaSamw error = 0; 2745da6c28aaSamw ASSERT(working_mode != 0); 2746da6c28aaSamw 2747da6c28aaSamw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) && 2748*0a586ceaSMark Shellenbaum zp->z_uid == crgetuid(cr))) 2749da6c28aaSamw working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); 2750da6c28aaSamw 2751da6c28aaSamw if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| 275247def0dcSMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) 2753da6c28aaSamw checkmode |= VREAD; 2754da6c28aaSamw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| 275547def0dcSMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) 2756da6c28aaSamw checkmode |= VWRITE; 2757da6c28aaSamw if (working_mode & ACE_EXECUTE) 2758da6c28aaSamw checkmode |= VEXEC; 2759da6c28aaSamw 2760da6c28aaSamw if (checkmode) 2761da6c28aaSamw error = secpolicy_vnode_access(cr, ZTOV(check_zp), 2762*0a586ceaSMark Shellenbaum zp->z_uid, checkmode); 2763da6c28aaSamw 2764da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_OWNER)) 2765*0a586ceaSMark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid); 2766da6c28aaSamw if (error == 0 && (working_mode & ACE_WRITE_ACL)) 2767*0a586ceaSMark Shellenbaum error = secpolicy_vnode_setdac(cr, zp->z_uid); 2768da6c28aaSamw 2769da6c28aaSamw if (error == 0 && (working_mode & 2770da6c28aaSamw (ACE_DELETE|ACE_DELETE_CHILD))) 2771da6c28aaSamw error = secpolicy_vnode_remove(cr); 2772da6c28aaSamw 277347def0dcSMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { 2774*0a586ceaSMark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid); 277547def0dcSMark Shellenbaum } 2776da6c28aaSamw if (error == 0) { 2777da6c28aaSamw /* 2778da6c28aaSamw * See if any bits other than those already checked 2779da6c28aaSamw * for are still present. If so then return EACCES 2780da6c28aaSamw */ 2781da6c28aaSamw if (working_mode & ~(ZFS_CHECKED_MASKS)) { 2782da6c28aaSamw error = EACCES; 2783da6c28aaSamw } 2784da6c28aaSamw } 2785da6c28aaSamw } 2786da6c28aaSamw 2787da6c28aaSamw if (is_attr) 2788da6c28aaSamw VN_RELE(ZTOV(xzp)); 2789da6c28aaSamw 2790da6c28aaSamw return (error); 2791fa9e4066Sahrens } 2792fa9e4066Sahrens 2793fa9e4066Sahrens /* 2794da6c28aaSamw * Translate traditional unix VREAD/VWRITE/VEXEC mode into 2795fa9e4066Sahrens * native ACL format and call zfs_zaccess() 2796fa9e4066Sahrens */ 2797fa9e4066Sahrens int 2798da6c28aaSamw zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) 2799da6c28aaSamw { 2800da6c28aaSamw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); 2801da6c28aaSamw } 2802da6c28aaSamw 2803da6c28aaSamw /* 2804da6c28aaSamw * Access function for secpolicy_vnode_setattr 2805da6c28aaSamw */ 2806da6c28aaSamw int 2807da6c28aaSamw zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) 2808fa9e4066Sahrens { 2809fa9e4066Sahrens int v4_mode = zfs_unix_to_v4(mode >> 6); 2810fa9e4066Sahrens 2811da6c28aaSamw return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); 2812fa9e4066Sahrens } 2813fa9e4066Sahrens 281447db7e74Smarks static int 281523d5bb1fSmarks zfs_delete_final_check(znode_t *zp, znode_t *dzp, 281623d5bb1fSmarks mode_t missing_perms, cred_t *cr) 281747db7e74Smarks { 281847db7e74Smarks int error; 281947db7e74Smarks 2820*0a586ceaSMark Shellenbaum error = secpolicy_vnode_access(cr, ZTOV(dzp), 2821*0a586ceaSMark Shellenbaum dzp->z_uid, missing_perms); 282247db7e74Smarks 282347db7e74Smarks if (error == 0) 282447db7e74Smarks error = zfs_sticky_remove_access(dzp, zp, cr); 282547db7e74Smarks 282647db7e74Smarks return (error); 282747db7e74Smarks } 282847db7e74Smarks 2829fa9e4066Sahrens /* 2830fa9e4066Sahrens * Determine whether Access should be granted/deny, without 2831fa9e4066Sahrens * consulting least priv subsystem. 2832fa9e4066Sahrens * 2833fa9e4066Sahrens * 2834fa9e4066Sahrens * The following chart is the recommended NFSv4 enforcement for 2835fa9e4066Sahrens * ability to delete an object. 2836fa9e4066Sahrens * 2837fa9e4066Sahrens * ------------------------------------------------------- 2838fa9e4066Sahrens * | Parent Dir | Target Object Permissions | 2839fa9e4066Sahrens * | permissions | | 2840fa9e4066Sahrens * ------------------------------------------------------- 2841fa9e4066Sahrens * | | ACL Allows | ACL Denies| Delete | 2842fa9e4066Sahrens * | | Delete | Delete | unspecified| 2843fa9e4066Sahrens * ------------------------------------------------------- 2844fa9e4066Sahrens * | ACL Allows | Permit | Permit | Permit | 2845fa9e4066Sahrens * | DELETE_CHILD | | 2846fa9e4066Sahrens * ------------------------------------------------------- 2847fa9e4066Sahrens * | ACL Denies | Permit | Deny | Deny | 2848fa9e4066Sahrens * | DELETE_CHILD | | | | 2849fa9e4066Sahrens * ------------------------------------------------------- 2850fa9e4066Sahrens * | ACL specifies | | | | 2851fa9e4066Sahrens * | only allow | Permit | Permit | Permit | 2852fa9e4066Sahrens * | write and | | | | 2853fa9e4066Sahrens * | execute | | | | 2854fa9e4066Sahrens * ------------------------------------------------------- 2855fa9e4066Sahrens * | ACL denies | | | | 2856fa9e4066Sahrens * | write and | Permit | Deny | Deny | 2857fa9e4066Sahrens * | execute | | | | 2858fa9e4066Sahrens * ------------------------------------------------------- 2859fa9e4066Sahrens * ^ 2860fa9e4066Sahrens * | 2861fa9e4066Sahrens * No search privilege, can't even look up file? 2862fa9e4066Sahrens * 2863fa9e4066Sahrens */ 2864fa9e4066Sahrens int 2865fa9e4066Sahrens zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) 2866fa9e4066Sahrens { 2867da6c28aaSamw uint32_t dzp_working_mode = 0; 2868da6c28aaSamw uint32_t zp_working_mode = 0; 2869fa9e4066Sahrens int dzp_error, zp_error; 287023d5bb1fSmarks mode_t missing_perms; 2871da6c28aaSamw boolean_t dzpcheck_privs = B_TRUE; 2872da6c28aaSamw boolean_t zpcheck_privs = B_TRUE; 2873fa9e4066Sahrens 2874fa9e4066Sahrens /* 287523d5bb1fSmarks * We want specific DELETE permissions to 2876fa9e4066Sahrens * take precedence over WRITE/EXECUTE. We don't 2877fa9e4066Sahrens * want an ACL such as this to mess us up. 287847db7e74Smarks * user:joe:write_data:deny,user:joe:delete:allow 2879fa9e4066Sahrens * 2880fa9e4066Sahrens * However, deny permissions may ultimately be overridden 2881fa9e4066Sahrens * by secpolicy_vnode_access(). 288223d5bb1fSmarks * 288323d5bb1fSmarks * We will ask for all of the necessary permissions and then 288423d5bb1fSmarks * look at the working modes from the directory and target object 288523d5bb1fSmarks * to determine what was found. 2886fa9e4066Sahrens */ 2887fa9e4066Sahrens 2888*0a586ceaSMark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK)) 2889da6c28aaSamw return (EPERM); 2890fa9e4066Sahrens 289123d5bb1fSmarks /* 28927ed7e920Smarks * First row 289323d5bb1fSmarks * If the directory permissions allow the delete, we are done. 289423d5bb1fSmarks */ 28957ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD, 289623d5bb1fSmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 289723d5bb1fSmarks return (0); 2898da6c28aaSamw 289923d5bb1fSmarks /* 290023d5bb1fSmarks * If target object has delete permission then we are done 290123d5bb1fSmarks */ 290223d5bb1fSmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, 290323d5bb1fSmarks &zpcheck_privs, B_FALSE, cr)) == 0) 290423d5bb1fSmarks return (0); 290523d5bb1fSmarks 29067ed7e920Smarks ASSERT(dzp_error && zp_error); 29077ed7e920Smarks 290823d5bb1fSmarks if (!dzpcheck_privs) 2909fa9e4066Sahrens return (dzp_error); 29107ed7e920Smarks if (!zpcheck_privs) 291123d5bb1fSmarks return (zp_error); 2912fa9e4066Sahrens 2913fa9e4066Sahrens /* 2914fa9e4066Sahrens * Second row 29157ed7e920Smarks * 29167ed7e920Smarks * If directory returns EACCES then delete_child was denied 29177ed7e920Smarks * due to deny delete_child. In this case send the request through 29187ed7e920Smarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check() 29197ed7e920Smarks * since that *could* allow the delete based on write/execute permission 29207ed7e920Smarks * and we want delete permissions to override write/execute. 2921fa9e4066Sahrens */ 2922fa9e4066Sahrens 292347db7e74Smarks if (dzp_error == EACCES) 29247ed7e920Smarks return (secpolicy_vnode_remove(cr)); 292547db7e74Smarks 292647db7e74Smarks /* 2927fa9e4066Sahrens * Third Row 292823d5bb1fSmarks * only need to see if we have write/execute on directory. 2929fa9e4066Sahrens */ 2930fa9e4066Sahrens 29317ed7e920Smarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, 29327ed7e920Smarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) 293347db7e74Smarks return (zfs_sticky_remove_access(dzp, zp, cr)); 2934fa9e4066Sahrens 29357ed7e920Smarks if (!dzpcheck_privs) 29367ed7e920Smarks return (dzp_error); 29377ed7e920Smarks 2938fa9e4066Sahrens /* 29397ed7e920Smarks * Fourth row 2940fa9e4066Sahrens */ 2941fa9e4066Sahrens 29427ed7e920Smarks missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0; 29437ed7e920Smarks missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0; 29447ed7e920Smarks 29457ed7e920Smarks ASSERT(missing_perms); 2946fa9e4066Sahrens 294723d5bb1fSmarks return (zfs_delete_final_check(zp, dzp, missing_perms, cr)); 29487ed7e920Smarks 2949fa9e4066Sahrens } 2950fa9e4066Sahrens 2951fa9e4066Sahrens int 2952fa9e4066Sahrens zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, 2953fa9e4066Sahrens znode_t *tzp, cred_t *cr) 2954fa9e4066Sahrens { 2955fa9e4066Sahrens int add_perm; 2956fa9e4066Sahrens int error; 2957fa9e4066Sahrens 2958*0a586ceaSMark Shellenbaum if (szp->z_pflags & ZFS_AV_QUARANTINED) 2959da6c28aaSamw return (EACCES); 2960da6c28aaSamw 2961fa9e4066Sahrens add_perm = (ZTOV(szp)->v_type == VDIR) ? 2962fa9e4066Sahrens ACE_ADD_SUBDIRECTORY : ACE_ADD_FILE; 2963fa9e4066Sahrens 2964fa9e4066Sahrens /* 2965fa9e4066Sahrens * Rename permissions are combination of delete permission + 2966fa9e4066Sahrens * add file/subdir permission. 2967fa9e4066Sahrens */ 2968fa9e4066Sahrens 2969fa9e4066Sahrens /* 2970fa9e4066Sahrens * first make sure we do the delete portion. 2971fa9e4066Sahrens * 2972fa9e4066Sahrens * If that succeeds then check for add_file/add_subdir permissions 2973fa9e4066Sahrens */ 2974fa9e4066Sahrens 2975fa9e4066Sahrens if (error = zfs_zaccess_delete(sdzp, szp, cr)) 2976fa9e4066Sahrens return (error); 2977fa9e4066Sahrens 2978fa9e4066Sahrens /* 2979fa9e4066Sahrens * If we have a tzp, see if we can delete it? 2980fa9e4066Sahrens */ 2981fa9e4066Sahrens if (tzp) { 2982fa9e4066Sahrens if (error = zfs_zaccess_delete(tdzp, tzp, cr)) 2983fa9e4066Sahrens return (error); 2984fa9e4066Sahrens } 2985fa9e4066Sahrens 2986fa9e4066Sahrens /* 2987fa9e4066Sahrens * Now check for add permissions 2988fa9e4066Sahrens */ 2989da6c28aaSamw error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); 2990fa9e4066Sahrens 2991fa9e4066Sahrens return (error); 2992fa9e4066Sahrens } 2993