fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER START
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file are subject to the terms of the
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Common Development and Distribution License (the "License").
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * You may not use this file except in compliance with the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * See the License for the specific language governing permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and limitations under the License.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * When distributing Covered Code, include this CDDL HEADER in each
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If applicable, add the following below this CDDL HEADER, with the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fields enclosed by brackets "[]" replaced with your own identifying
fa9e4066f08beec538e775443c5be79dd423fcabahrens * information: Portions Copyright [yyyy] [name of copyright owner]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL HEADER END
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
be6fd75a69ae679453d9cda5bff3326111e6d1caMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#define MAX_ACE_TYPE ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define EVERYONE_ALLOW_MASK (ACE_READ_ACL|ACE_READ_ATTRIBUTES | \
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define EVERYONE_DENY_MASK (ACE_WRITE_ACL|ACE_WRITE_OWNER | \
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define OWNER_ALLOW_MASK (ACE_WRITE_ACL | ACE_WRITE_OWNER | \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#define ZFS_CHECKED_MASKS (ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_DATA| \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_READ_NAMED_ATTRS|ACE_WRITE_DATA|ACE_WRITE_ATTRIBUTES| \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_WRITE_NAMED_ATTRS|ACE_APPEND_DATA|ACE_EXECUTE|ACE_WRITE_OWNER| \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_WRITE_ACL|ACE_DELETE|ACE_DELETE_CHILD|ACE_SYNCHRONIZE)
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum#define WRITE_MASK_DATA (ACE_WRITE_DATA|ACE_APPEND_DATA|ACE_WRITE_NAMED_ATTRS)
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum#define WRITE_MASK_ATTRS (ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES| \
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum#define WRITE_MASK (WRITE_MASK_DATA|WRITE_MASK_ATTRS)
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define OGE_CLEAR (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
fa9e4066f08beec538e775443c5be79dd423fcabahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define OKAY_MASK_BITS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
fa9e4066f08beec538e775443c5be79dd423fcabahrens ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_EXECUTE)
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define ALL_INHERIT (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE | \
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE|ACE_INHERITED_ACE)
b3d141f8c7a5335d670721a81f797b1834ee327bmarks#define RESTRICTED_CLEAR (ACE_WRITE_ACL|ACE_WRITE_OWNER)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#define V4_ACL_WIDE_FLAGS (ZFS_ACL_AUTO_INHERIT|ZFS_ACL_DEFAULTED|\
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley#define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_oldace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_oldace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (-1);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t entry_type = acep->z_hdr.z_flags & ACE_TYPE_FLAGS;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (entry_type == ACE_OWNER || entry_type == OWNING_GROUP ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_object_ace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_ace_hdr_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*FALLTHROUGH*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_ace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_ace_hdr_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (sizeof (zfs_object_ace_t) - sizeof (zfs_ace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * The following three functions are provided for compatibility with
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * older ZPL version in order to determine if the file use to have
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * an external ACL and what version of ACL previously existed on the
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * file. Would really be nice to not need this, sigh.
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * Need to deal with a potential
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * race where zfs_sa_upgrade could cause
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * z_isa_sa to change.
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * If the lookup fails then the state of z_is_sa should have
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * after upgrade the SA_ZPL_ZNODE_ACL should have been
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * Determine size of ACL in bytes
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * This is more complicated than it should be since we have to deal
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * with old external ACLs.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaumzfs_acl_znode_info(znode_t *zp, int *aclsize, int *aclcount,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = sa_size(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_COUNT(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (aclphys->z_acl_version == ZFS_ACL_VERSION_INITIAL) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum *aclsize = ZFS_ACL_SIZE(aclphys->z_acl_size);
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * Need to deal with a potential
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * race where zfs_sa_upgrade could cause
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * z_isa_sa to change.
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * If the lookup fails then the state of z_is_sa should have
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * After upgrade SA_ZPL_ZNODE_ACL should have
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * been removed.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclnode = kmem_zalloc(sizeof (zfs_acl_node_t), KM_SLEEP);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaumzfs_acl_valid_ace_type(uint_t type, uint_t flags)
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum entry_type == ACE_EVERYONE || entry_type == 0 ||
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum if (type >= MIN_ACE_TYPE && type <= MAX_ACE_TYPE)
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaumzfs_ace_valid(vtype_t obj_type, zfs_acl_t *aclp, uint16_t type, uint16_t iflags)
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum * first check type of entry
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum * next check inheritance level flags
b249c65cf0a7400e86a36ddab5c3fce085809859marks (iflags & (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (iflags & (ACE_INHERIT_ONLY_ACE|ACE_NO_PROPAGATE_INHERIT_ACE)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t *access_mask, uint16_t *iflags, uint16_t *type)
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum * Make sure we don't overstep our bounds
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum ((caddr_t)aclnode->z_acldata + aclnode->z_size)) {
003c2582df5b8a57cb0e6f04227f93ccd982f0e5Mark Shellenbaum aclp->z_next_ace = (caddr_t)aclp->z_next_ace + ace_size;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return ((void *)acep);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Copy ACE to internal ZFS format.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * While processing the ACL each ACE will be validated for correctness.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ACE FUIDs will be created later.
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_copy_ace_2_fuid(zfsvfs_t *zfsvfs, vtype_t obj_type, zfs_acl_t *aclp,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum void *datap, zfs_ace_t *z_acl, uint64_t aclcnt, size_t *size,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = 0; i != aclcnt; i++) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (entry_type != ACE_OWNER && entry_type != OWNING_GROUP &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum aceptr->z_fuid = zfs_fuid_create(zfsvfs, acep->a_who,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Make sure ACE is valid
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw acep = (ace_t *)((caddr_t)acep + sizeof (ace_object_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Copy ZFS ACEs to fixed size ace_t layout
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
bda89588bd7667394a834e8a9a34612cce2ae9c3jpzfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_copy_ace_2_oldace(vtype_t obj_type, zfs_acl_t *aclp, ace_t *acep,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Make sure ACE is valid
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * convert old ACL format to new
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * First create the ACE in a contiguous piece of memory
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * for zfs_copy_ace_2_fuid().
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We only convert an ACL once, so this won't happen
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * everytime.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum VERIFY(zfs_copy_ace_2_fuid(zp->z_zfsvfs, ZTOV(zp)->v_type, aclp,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum oldaclp, newaclnode->z_acldata, aclp->z_acl_count,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw kmem_free(oldaclp, aclp->z_acl_count * sizeof (zfs_oldace_t));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Release all previous ACL nodes
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Convert unix access mask to v4 access mask
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_set_ace(zfs_acl_t *aclp, void *acep, uint32_t access_mask,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t access_type, uint64_t fuid, uint16_t entry_type)
1ab996781aab376b5ee79af025ab24ff42a0a3f0Mark Shellenbaum if ((type != ACE_OWNER && type != OWNING_GROUP &&
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Determine mode of file based on ACL.
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaumzfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum uint64_t *pflags, uint64_t fuid, uint64_t fgid)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Skip over any inherit_only ACEs
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (entry_type == ACE_OWNER || (entry_type == 0 &&
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum (entry_type == ACE_IDENTIFIER_GROUP && who == fgid)) {
d47621a49c68c359358f6630aa45cc320762f51fTim Haley * Only care if this IDENTIFIER_GROUP or
d47621a49c68c359358f6630aa45cc320762f51fTim Haley * USER ACE denies execute access to someone,
d47621a49c68c359358f6630aa45cc320762f51fTim Haley * mode is not affected
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley * Failure to allow is effectively a deny, so execute permission
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley * is denied if it was never mentioned or if we explicitly
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley * weren't allowed it.
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley * Read an external acl object. If the intent is to modify, always
4929fd5ef3f018b490359eb4a2d95d22152325fbTim Haley * create a new acl and leave any cached acl in place.
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaumzfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp,
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * close race where znode could be upgrade while trying to
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * read the znode attributes.
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum * But this could only happen if the file isn't already an SA
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = zfs_acl_znode_info(zp, &aclsize,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum znode_acl.z_acl_extern_obj, 0, aclnode->z_size,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum bcopy(znode_acl.z_ace_data, aclnode->z_acldata,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum error = sa_lookup(zp->z_sa_hdl, SA_ZPL_DACL_ACES(zp->z_zfsvfs),
b87f3af36bb994656da117319f5129ddfd05ed21perrin /* convert checksum errors into IO errors */
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaumzfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum zfs_acl_locator_cb_t *cb = (zfs_acl_locator_cb_t *)userdata;
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum cb->cb_acl_node = list_head(&cb->cb_aclp->z_acl);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl,
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum if ((error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE)) == 0)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * common code for setting ACLs.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This function is called from zfs_mode_update, zfs_perm_init, and zfs_setacl.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * zfs_setacl passes a non-NULL inherit pointer (ihp) to indicate that it's
fa9e4066f08beec538e775443c5be79dd423fcabahrens * already checked the acl and knows whether to inherit.
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zfsvfs), NULL,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * Upgrade needed?
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * Arrgh, we have to handle old on disk format
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * as well as newer (preferred) SA format.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (zp->z_is_sa) { /* the easy case, just update the ACL attribute */
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_ACES(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum zfs_acl_data_locator, &locate, aclp->z_acl_bytes);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_DACL_COUNT(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum NULL, &aclp->z_acl_count, sizeof (uint64_t));
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum } else { /* Painful legacy way */
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zfsvfs),
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * If ACL was previously external and we are now
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * converting to new ACL format then release old
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * ACL object and create a new one.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum aclp->z_version != acl_phys.z_acl_version) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum error = dmu_object_free(zfsvfs->z_os, aoid, tx);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum (void) dmu_object_set_blocksize(zfsvfs->z_os,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * Migrating back embedded?
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * If Old version then swap count/bytes to match old
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * layout of znode_acl_phys_t.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (aclp->z_version == ZFS_ACL_VERSION_INITIAL) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zfsvfs), NULL,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Replace ACL wide bits, but first clear them.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Leezfs_acl_chmod(vtype_t vtype, uint64_t mode, boolean_t split, boolean_t trim,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size();
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee acl_trivial_access_masks((mode_t)mode, isdir, &masks);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee zfs_set_ace(aclp, zacep, masks.allow0, ALLOW, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee zfs_set_ace(aclp, zacep, masks.deny1, DENY, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee zfs_set_ace(aclp, zacep, masks.deny2, DENY, -1, OWNING_GROUP);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * ACEs used to represent the file mode may be divided
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * into an equivalent pair of inherit-only and regular
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * ACEs, if they are inheritable.
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Skip regular ACEs, which are replaced by the new mode.
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * We preserve owner@, group@, or @everyone
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * permissions, if they are inheritable, by
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * copying them to inherit_only ACEs. This
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * prevents inheritable permissions from being
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * altered along with the file mode.
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee * If this ACL has any inheritable ACEs, mark that in
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee * the hints (which are later masked into the pflags)
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee * so create knows to do inheritance.
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
851632d6a88d512574719953cc01ae7c2ed66b88Albert Lee * Limit permissions granted by ACEs to be no greater
851632d6a88d512574719953cc01ae7c2ed66b88Albert Lee * than permissions of the requested group mode.
851632d6a88d512574719953cc01ae7c2ed66b88Albert Lee * Applies when the "aclmode" property is set to
851632d6a88d512574719953cc01ae7c2ed66b88Albert Lee * "groupmask".
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size);
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee zfs_set_ace(aclp, zacep, masks.owner, ALLOW, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee zfs_set_ace(aclp, zacep, masks.group, ALLOW, -1, OWNING_GROUP);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee zfs_set_ace(aclp, zacep, masks.everyone, ALLOW, -1, ACE_EVERYONE);
4c841f6070b4f88f9dc008de526b313bbebd4e32markszfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee error = zfs_acl_node_read(zp, B_TRUE, aclp, B_TRUE);
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
a3c49ce110f325a563c245bedc4d533adddb7211Albert Lee (zp->z_zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK), *aclp);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Should ACE be inherited?
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_ace_can_use(vtype_t vtype, uint16_t acep_flags)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((vtype == VDIR) && (iflags & ACE_DIRECTORY_INHERIT_ACE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (1);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * inherit inheritable ACEs from parent
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee if (aclinherit == ZFS_ACL_DISCARD || vtype == VLNK)
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum * don't inherit bogus ACEs
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Check if ACE is inheritable by this vnode
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee if ((aclinherit == ZFS_ACL_NOALLOW && type == ALLOW) ||
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Strip inherited execute permission from file if
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * not in mode
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee if (aclinherit == ZFS_ACL_PASSTHROUGH_X && type == ALLOW &&
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee !isdir && ((mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)) {
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Strip write_acl and write_owner from permissions
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * when inheriting an ACE
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee if (aclinherit == ZFS_ACL_RESTRICTED && type == ALLOW) {
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum * Copy special opaque data if any
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum if ((data1sz = paclp->z_ops.ace_data(pacep, &data1)) != 0) {
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum VERIFY((data2sz = aclp->z_ops.ace_data(acep,
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum newflags = aclp->z_ops.ace_flags_get(acep);
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * If ACE is not to be inherited further, or if the vnode is
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * not a directory, remove all inheritance flags
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee if (!isdir || (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * This directory has an inheritable ACE
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * If only FILE_INHERIT is set then turn on
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * inherit_only
485adf6194d7a711f1a48d816798e4481c28dae5Mark Shellenbaum ACE_DIRECTORY_INHERIT_ACE)) == ACE_FILE_INHERIT_ACE) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Create file system object initial permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * including inheritable ACEs.
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee * Also, create FUIDs for owner and group.
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum acl_ids->z_mode = MAKEIMODE(vap->va_type, vap->va_mode);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if ((error = zfs_vsec_2_aclp(zfsvfs, vap->va_type, vsecp, cr,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum &acl_ids->z_fuidp, &acl_ids->z_aclp)) != 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine uid and gid.
4a1f0cc97e50e029e40b6055fa68f89c9ae6bb38Mark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum gid = zfs_fuid_map_id(zfsvfs, acl_ids->z_fgid,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum acl_ids->z_fgid = zfs_fuid_create_cred(zfsvfs,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If we're creating a directory, and the parent directory has the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * set-GID bit set, set in on the new directory.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Otherwise, if the user is neither privileged nor a member of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * file's new group, clear the file's set-GID bit.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_mode & S_ISGID) &&
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee acl_ids->z_aclp->z_hints |= ZFS_ACL_AUTO_INHERIT;
de0f1ddb598506a5d9a02946b67e9300b5f2a7cdAlbert Lee zfs_acl_chmod(vap->va_type, acl_ids->z_mode, B_FALSE, trim,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum acl_ids->z_mode = zfs_mode_compute(acl_ids->z_mode,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum acl_ids->z_aclp, &acl_ids->z_aclp->z_hints,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (ace_trivial_common(acl_ids->z_aclp, 0, zfs_ace_walk) == 0)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum * Free ACL and fuid_infop, but not the acl_ids structure
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrenszfs_acl_ids_overquota(zfsvfs_t *zfsvfs, zfs_acl_ids_t *acl_ids)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum return (zfs_fuid_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) ||
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum zfs_fuid_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid));
f7170741490edba9d1d9c697c177c887172bc741Will Andrews * Retrieve a file's ACL
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Scan ACL to determine number of ACEs
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((zp->z_pflags & ZFS_ACL_OBJ_ACE) && !(mask & VSA_ACE_ALLTYPES)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
2e7d9b4283515cc94f4e29f4b76204b1c108c307Mark Shellenbaum for (aclnode = list_head(&aclp->z_acl); aclnode;
2e7d9b4283515cc94f4e29f4b76204b1c108c307Mark Shellenbaum aclnode = list_next(&aclp->z_acl, aclnode)) {
2e7d9b4283515cc94f4e29f4b76204b1c108c307Mark Shellenbaum ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp ==
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum vsecattr_t *vsecp, cred_t *cr, zfs_fuid_info_t **fuidp, zfs_acl_t **zaclp)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (vsecp->vsa_aclcnt > MAX_ACL_ENTRIES || vsecp->vsa_aclcnt <= 0)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclp = zfs_acl_alloc(zfs_acl_version(zfsvfs->z_version));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclnode = zfs_acl_node_alloc(aclcnt * sizeof (zfs_object_ace_t));
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if ((error = zfs_copy_ace_2_fuid(zfsvfs, obj_type, aclp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If flags are being set then add them to z_hints
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
f7170741490edba9d1d9c697c177c887172bc741Will Andrews * Set a file's ACL
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens ulong_t mask = vsecp->vsa_mask & (VSA_ACE | VSA_ACECNT);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If ACL wide flags aren't being set then preserve any
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * existing flags.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * If old version and ACL won't fit in bonus and we aren't
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum * upgrading then take out necessary DMU holds
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum if ((acl_obj = zfs_external_acl(zp)) != 0) {
2bd6c4de2748ab3787a6e1ab244159d738d831e0Mark Shellenbaum if (zfsvfs->z_version >= ZPL_VERSION_FUID &&
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum zfs_znode_acl_version(zp) <= ZFS_ACL_VERSION_INITIAL) {
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum dmu_tx_hold_write(tx, acl_obj, 0, aclp->z_acl_bytes);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum } else if (!zp->z_is_sa && aclp->z_acl_bytes > ZFS_ACE_SPACE) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx);
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * Check accesses of interest (AoI) against attributes of the dataset
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * such as read-only. Returns zero if no AoI conflict with dataset
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * attributes, otherwise an appropriate errno is returned.
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haleyzfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode)
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Only check for READONLY on non-directories.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum (zp->z_pflags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * The primary usage of this function is to loop through all of the
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * ACEs in the znode, determining what accesses of interest (AoI) to
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * the caller are allowed or denied. The AoI are expressed as bits in
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * the working_mode parameter. As each ACE is processed, bits covered
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * by that ACE are removed from the working_mode. This removal
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * facilitates two things. The first is that when the working mode is
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * empty (= 0), we know we've looked at all the AoI. The second is
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * that the ACE interpretation rules don't allow a later ACE to undo
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * something granted or denied by an earlier ACE. Removing the
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * discovered access or denial enforces this rule. At the end of
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * processing the ACEs, all AoI that were found to be denied are
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * placed into the working_mode, giving the caller a mask of denied
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * accesses. Returns:
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * 0 if all AoI granted
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * EACCES if the denied mask is non-zero
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * other error if abnormal failure (e.g., IO error)
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * A secondary usage of the function is to determine if any of the
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * AoI are granted. If an ACE grants any access in
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * the working_mode, we immediately short circuit out of the function.
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * This mode is chosen by setting anyaccess to B_TRUE. The
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * working_mode is not a denied access mask upon exit if the function
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * is used in this manner.
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haleyzfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
1412a1a223b7a94990edf5114c108b0a29c3f881Mark Shellenbaum error = zfs_acl_node_read(zp, B_FALSE, &aclp, B_FALSE);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
b249c65cf0a7400e86a36ddab5c3fce085809859marks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley /* Skip ACE if it does not affect any AoI */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*FALLTHROUGH*/
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* USER Entry */
90fafcf0df314d4b61e54f05ce41f7e1c06a025amarks /* Are we done? */
90fafcf0df314d4b61e54f05ce41f7e1c06a025amarks /* Put the found 'denies' back on the working mode */
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks } else if (*working_mode) {
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks return (-1);
90fafcf0df314d4b61e54f05ce41f7e1c06a025amarks return (0);
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * Return true if any access whatsoever granted, we don't actually
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * care what access is granted.
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum return (secpolicy_vnode_any_access(cr, ZTOV(zp), owner) == 0);
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haleyzfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * Short circuit empty requests
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) {
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * The caller requested that the ACL check be skipped. This
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * would only happen if the caller checked VOP_ACCESS() with a
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * 32 bit ACE mask and already had the appropriate permissions.
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode,
d47621a49c68c359358f6630aa45cc320762f51fTim Haleyzfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
d47621a49c68c359358f6630aa45cc320762f51fTim Haley DTRACE_PROBE(zfs__fastpath__execute__access__miss);
d47621a49c68c359358f6630aa45cc320762f51fTim Haley error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr);
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * Determine whether Access should be granted/denied.
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * The least priv subsytem is always consulted as a basic privilege
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * can define any form of access.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If attribute then validate against base file
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum sizeof (parent))) != 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fixup mode to map to xattr perms
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * in needed_bits. Map the bits mapped by working_mode (currently
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * missing) in missing_bits.
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode),
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik * needed_bits.
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES);
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS|
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum return (secpolicy_vnode_access2(cr, ZTOV(zp), owner,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * First check for implicit owner permission on
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES) &&
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS|
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE))
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(check_zp), owner,
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See if any bits other than those already checked
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * for are still present. If so then return EACCES
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik } else if (error == 0) {
f1696b231bb1209e1cea95b7ff29b8c60493daa0Mark Shellenbaum error = secpolicy_vnode_access2(cr, ZTOV(zp), owner,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Translate traditional unix VREAD/VWRITE/VEXEC mode into
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * native ACL format and call zfs_zaccess()
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Access function for secpolicy_vnode_setattr
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe/* See zfs_zaccess_delete() */
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Determine whether delete access should be granted.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * The following chart outlines how we handle delete permissions which is
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * how recent versions of windows (Windows 2008) handles it. The efficiency
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * comes from not having to check the parent ACL where the object itself grants
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * | Parent Dir | Target Object Permissions |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | permissions | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | | ACL Allows | ACL Denies| Delete |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | | Delete | Delete | unspecified|
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * | ACL Allows | Permit | Deny * | Permit |
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * | DELETE_CHILD | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * | ACL Denies | Permit | Deny | Deny |
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * | DELETE_CHILD | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL specifies | | | |
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * | only allow | Permit | Deny * | Permit |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | write and | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | execute | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL denies | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | write and | Permit | Deny | Deny |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | execute | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Re. execute permission on the directory: if that's missing,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * the vnode lookup of the target will fail before we get here.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * Re [*] in the table above: NFSv4 would normally Permit delete for
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * these two cells of the matrix.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * See acl.h for notes on which ACE_... flags should be checked for which
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * operations. Specifically, the NFSv4 committee recommendation is in
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * conflict with the Windows interpretation of DENY ACEs, where DENY ACEs
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * should take precedence ahead of ALLOW ACEs.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * This implementation always consults the target object's ACL first.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * If a DENY ACE is present on the target object that specifies ACE_DELETE,
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * delete access is denied. If an ALLOW ACE with ACE_DELETE is present on
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * the target object, access is allowed. If and only if no entries with
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * ACE_DELETE are present in the object's ACL, check the container's ACL
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * for entries with ACE_DELETE_CHILD.
da412744bc6f902e4519ae67e92191a2e5d85e2cKevin Crowe * A summary of the logic implemented from the table above is as follows:
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * First check for DENY ACEs that apply.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * If either target or container has a deny, EACCES.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Delete access can then be summarized as follows:
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 1: The object to be deleted grants ACE_DELETE, or
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 2: The containing directory grants ACE_DELETE_CHILD.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * In a Windows system, that would be the end of the story.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * In this system, (2) has some complications...
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 2a: "sticky" bit on a directory adds restrictions, and
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 2b: existing ACEs from previous versions of ZFS may
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * not carry ACE_DELETE_CHILD where they should, so we
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * also allow delete when ACE_WRITE_DATA is granted.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Note: 2b is technically a work-around for a prior bug,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * which hopefully can go away some day. For those who
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * no longer need the work around, and for testing, this
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * work-around is made conditional via the tunable:
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * zfs_write_implies_delete_child
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (zp->z_pflags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * If target object grants ACE_DELETE then we are done. This is
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * indicated by a return value of 0. For this case we don't worry
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * about the sticky bit because sticky only applies to the parent
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * directory and this is the child access result.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * If we encounter a DENY ACE here, we're also done (EACCES).
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Note that if we hit a DENY ACE here (on the target) it should
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * take precedence over a DENY ACE on the container, so that when
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * we have more complete auditing support we will be able to
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * report an access failure against the specific target.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * (This is part of why we're checking the target first.)
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe /* We hit a DENY ACE. */
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks return (0);
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * If the containing directory grants ACE_DELETE_CHILD,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * or we're in backward compatibility mode and the
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * containing directory has ACE_WRITE_DATA, allow.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Case 2b is handled with wanted_dirperms.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe dzp_error = zfs_zaccess_common(dzp, wanted_dirperms,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe /* We hit a DENY ACE. */
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Cases 2a, 2b (continued)
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Note: dzp_working_mode now contains any permissions
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * that were NOT granted. Therefore, if any of the
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * wanted_dirperms WERE granted, we will have:
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * dzp_working_mode != wanted_dirperms
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * We're really asking if ANY of those permissions
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * were granted, and if so, grant delete access.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * dzp_error is 0 if the container granted us permissions to "modify".
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * If we do not have permission via one or more ACEs, our current
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * privileges may still permit us to modify the container.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * dzpcheck_privs is false when i.e. the FS is read-only.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Otherwise, do privilege checks for the container.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * The secpolicy call needs the requested access and
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * the current access mode of the container, but it
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * only knows about Unix-style modes (VEXEC, VWRITE),
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * so this must condense the fine-grained ACE bits into
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Unix modes.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * The VEXEC flag is easy, because we know that has
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * always been checked before we get here (during the
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * lookup of the target vnode). The container has not
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * granted us permissions to "modify", so we do not set
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * the VWRITE flag in the current access mode.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe owner = zfs_fuid_map_id(dzp->z_zfsvfs, dzp->z_uid, cr,
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe dzp_error = secpolicy_vnode_access2(cr, ZTOV(dzp),
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Note: We may have dzp_error = -1 here (from
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * zfs_zacess_common). Don't return that.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * At this point, we know that the directory permissions allow
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * us to modify, but we still need to check for the additional
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * restrictions that apply when the "sticky bit" is set.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * Yes, zfs_sticky_remove_access() also checks this bit, but
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * checking it here and skipping the call below is nice when
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * you're watching all of this with dtrace.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * zfs_sticky_remove_access will succeed if:
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 1. The sticky bit is absent.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 2. We pass the sticky bit restrictions.
1eb4e906ec75b9bde421954ace46ef137b0fc9ebKevin Crowe * 3. We have privileges that always allow file removal.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Rename permissions are combination of delete permission +
fa9e4066f08beec538e775443c5be79dd423fcabahrens * add file/subdir permission.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * first make sure we do the delete portion.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If that succeeds then check for add_file/add_subdir permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If we have a tzp, see if we can delete it?
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Now check for add permissions