zfs_acl.c revision 148434217c040ea38dc844384f6ba68d9b325906
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
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Use is subject to license terms.
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|\
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);
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,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum void *datap, zfs_ace_t *z_acl, int 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.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Also, create FUIDs for any User/Group ACEs
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_mode_compute(znode_t *zp, zfs_acl_t *aclp)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
1ab996781aab376b5ee79af025ab24ff42a0a3f0Mark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs
1ab996781aab376b5ee79af025ab24ff42a0a3f0Mark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Version 0 to 1 znode_acl_phys has the size/count fields swapped.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Version 0 didn't have a size field, only a count.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclnode = zfs_acl_node_alloc(will_modify ? aclp->z_acl_bytes : 0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw bcopy(zp->z_phys->zp_acl.z_ace_data, aclnode->z_acldata,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Read an external acl object.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
fa9e4066f08beec538e775443c5be79dd423fcabahrens uint64_t extacl = zp->z_phys->zp_acl.z_acl_extern_obj;
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (zp->z_phys->zp_acl.z_acl_version == ZFS_ACL_VERSION_INITIAL) {
b87f3af36bb994656da117319f5129ddfd05ed21perrin /* convert checksum errors into IO errors */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock return (0);
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)
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum zphys->zp_mode = zfs_mode_compute(zp, aclp);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Decide which opbject type to use. If we are forced to
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * use old ACL format than transform ACL into zfs_oldace_t
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If ACL was previously external and we are now
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * converting to new ACL format then release old
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ACL object and create a new one.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (aoid == 0) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Migrating back embedded?
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If Old version then swap count/bytes to match old
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * layout of znode_acl_phys_t.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Replace ACL wide bits, but first clear them.
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Update access mask for prepended ACE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This applies the "groupmask" value for aclmode property.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_prepend_fixup(zfs_acl_t *aclp, void *acep, void *origacep,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Apply mode to canonical six ACEs.
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_acl_fixup_canonical_six(zfs_acl_t *aclp, mode_t mode)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Fixup final ACEs to match the mode
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_ace_match(zfs_acl_t *aclp, void *acep, int allow_deny,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Can prepended ACE be reused?
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_reuse_deny(zfs_acl_t *aclp, void *acep, void *prevacep)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Insert new ACL node into chain of zfs_acl_node_t's
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * This will result in two possible results.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 1. If the ACL is currently just a single zfs_acl_node and
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * we are prepending the entry then current acl node will have
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * a new node inserted above it.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 2. If we are inserting in the middle of current acl node then
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the current node will be split in two and new node will be inserted
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * in between the two split nodes.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw newnode = zfs_acl_node_alloc(aclp->z_ops.ace_size(acep));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw currnode->z_size = (caddr_t)acep - (caddr_t)currnode->z_acldata;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Prepend deny ACE
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void *
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_acl_prepend_deny(uint64_t uid, zfs_acl_t *aclp, void *acep,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, newacep, 0, DENY, fuid, (flags & ACE_TYPE_FLAGS));
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum zfs_acl_prepend_fixup(aclp, newacep, acep, mode, uid);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Split an inherited ACE into inherit_only ACE
fa9e4066f08beec538e775443c5be79dd423fcabahrens * and original ACE with inheritance flags stripped off.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclp->z_ops.ace_flags_set(newacep, flags | ACE_INHERIT_ONLY_ACE);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Are ACES started at index i, the canonical six ACES?
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int i = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclnode->z_size - (aclp->z_ops.ace_abstract_size() * 6));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++), DENY,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw OWNING_GROUP, 0) && zfs_acl_ace_match(aclp, (caddr_t)acep +
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_acl_ace_match(aclp, (caddr_t)acep + (abstract_size * i++),
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (1);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Apply step 1g, to group entries
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Need to deal with corner case where group may have
fa9e4066f08beec538e775443c5be79dd423fcabahrens * greater permissions than owner. If so then limit
fa9e4066f08beec538e775443c5be79dd423fcabahrens * group permissions, based on what extra permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * group has.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_fixup_group_entries(zfs_acl_t *aclp, void *acep, void *prevacep,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t prevflags = aclp->z_ops.ace_flags_get(prevacep);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Apply the chmod algorithm as described
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in PSARC/2002/240
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaumzfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t uid,
2459a9eaca6b6525c76289d22ffe4c96be1956d6marks * If discard then just discard all ACL nodes which
2459a9eaca6b6525c76289d22ffe4c96be1956d6marks * represent the ACEs.
2459a9eaca6b6525c76289d22ffe4c96be1956d6marks * New owner@/group@/everone@ ACEs will be added
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Need to split ace into two?
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check preceding ACE if any, to see
fa9e4066f08beec538e775443c5be79dd423fcabahrens * if we need to prepend a DENY ACE.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This is only applicable when the acl_mode
fa9e4066f08beec538e775443c5be79dd423fcabahrens * property == groupmask.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check out last six aces, if we have six.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++), 0,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw zfs_set_ace(aclp, (caddr_t)zacep + (abstract_size * i++),
4c841f6070b4f88f9dc008de526b313bbebd4e32markszfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum (*aclp)->z_hints = zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS;
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum zfs_acl_chmod(zp->z_zfsvfs, zp->z_phys->zp_uid, mode, *aclp);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * strip off write_owner and write_acl
b3d141f8c7a5335d670721a81f797b1834ee327bmarkszfs_restricted_update(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, void *acep)
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,
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum boolean_t passthrough, passthrough_x, noallow;
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH_X;
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum zfsvfs->z_acl_inherit == ZFS_ACL_PASSTHROUGH;
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD)
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum * don't inherit bogus ACEs
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum * If owner@, group@, or everyone@ inheritable
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum * then zfs_acl_chmod() isn't needed.
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum OWNING_GROUP)) && (vreg || (vdir && (iflags &
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)) {
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);
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum if ((iflags & ACE_NO_PROPAGATE_INHERIT_ACE) || !vdir) {
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum newflags = aclp->z_ops.ace_flags_get(acep);
b3d141f8c7a5335d670721a81f797b1834ee327bmarks * Copy special opaque data if any
d0f3f37e7f24f68fdbd85386c60e576883622762Mark Shellenbaum zfs_restricted_update(zfsvfs, aclp, acep2);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Create file system object initial permissions
fa9e4066f08beec538e775443c5be79dd423fcabahrens * including inheritable ACEs.
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.
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER,
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if (acl_ids->z_fgid != dzp->z_phys->zp_gid &&
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.
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (dzp->z_phys->zp_mode & S_ISGID) &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum (dzp->z_phys->zp_flags & ZFS_INHERIT_ACE)) &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE));
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum acl_ids->z_aclp->z_hints = (vap->va_type == VDIR) ?
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)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return (zfs_usergroup_overquota(zfsvfs, B_FALSE, acl_ids->z_fuid) ||
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens zfs_usergroup_overquota(zfsvfs, B_TRUE, acl_ids->z_fgid));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Retrieve a files ACL
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Scan ACL to determine number of ACEs
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
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);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Set a files 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.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* Are we upgrading ACL? */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, aclp->z_acl_bytes);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum error = zfs_aclset_common(zp, aclp, cr, tx);
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum zfs_time_stamper_locked(zp, STATE_CHANGED, tx);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * working_mode returns the permissions that were not granted
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Short circuit empty requests
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return (0);
f52e0e2bdbf77acd45e060be155f7a484e1bf1f9Mark Shellenbaum (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Only check for READONLY on non-directories.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) ||
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The caller requested that the ACL check be skipped. This
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * would only happen if the caller checked VOP_ACCESS() with a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 32 bit ACE mask and already had the appropriate permissions.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
b249c65cf0a7400e86a36ddab5c3fce085809859marks if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*FALLTHROUGH*/
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* USER Entry */
90fafcf0df314d4b61e54f05ce41f7e1c06a025amarks uint32_t mask_matched = (access_mask & *working_mode);
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);
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,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine whether Access should be granted/denied, invoking least
fa9e4066f08beec538e775443c5be79dd423fcabahrens * priv subsytem when a deny is determined.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * If attribute then validate against base file
fa9e4066f08beec538e775443c5be79dd423fcabahrens * fixup mode to map to xattr perms
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((error = zfs_zaccess_common(check_zp, mode, &working_mode,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr);
e0d35c4478bf9fd4080951b5b9d1f9a38948ba69marks owner = zfs_fuid_map_id(zfsvfs, check_zp->z_phys->zp_uid, 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))
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum error = secpolicy_vnode_chown(cr, B_FALSE);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See if any bits other than those already checked
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * for are still present. If so then return EACCES
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
e0d35c4478bf9fd4080951b5b9d1f9a38948ba69marks downer = zfs_fuid_map_id(zfsvfs, dzp->z_phys->zp_uid, cr, ZFS_OWNER);
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks error = secpolicy_vnode_access(cr, ZTOV(dzp), downer, missing_perms);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Determine whether Access should be granted/deny, without
fa9e4066f08beec538e775443c5be79dd423fcabahrens * consulting least priv subsystem.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The following chart is the recommended NFSv4 enforcement for
fa9e4066f08beec538e775443c5be79dd423fcabahrens * ability to delete an object.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | Parent Dir | Target Object Permissions |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | permissions | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | | ACL Allows | ACL Denies| Delete |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | | Delete | Delete | unspecified|
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL Allows | Permit | Permit | Permit |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | DELETE_CHILD | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL Denies | Permit | Deny | Deny |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | DELETE_CHILD | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL specifies | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | only allow | Permit | Permit | Permit |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | write and | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | execute | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | ACL denies | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | write and | Permit | Deny | Deny |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * | execute | | | |
fa9e4066f08beec538e775443c5be79dd423fcabahrens * -------------------------------------------------------
fa9e4066f08beec538e775443c5be79dd423fcabahrens * No search privilege, can't even look up file?
fa9e4066f08beec538e775443c5be79dd423fcabahrenszfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * We want specific DELETE permissions to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * take precedence over WRITE/EXECUTE. We don't
fa9e4066f08beec538e775443c5be79dd423fcabahrens * want an ACL such as this to mess us up.
47db7e746eb0bef03d3708b9d5b48f4ca49968bamarks * user:joe:write_data:deny,user:joe:delete:allow
fa9e4066f08beec538e775443c5be79dd423fcabahrens * However, deny permissions may ultimately be overridden
fa9e4066f08beec538e775443c5be79dd423fcabahrens * by secpolicy_vnode_access().
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * We will ask for all of the necessary permissions and then
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * look at the working modes from the directory and target object
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * to determine what was found.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (zp->z_phys->zp_flags & (ZFS_IMMUTABLE | ZFS_NOUNLINK))
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * First row
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * If the directory permissions allow the delete, we are done.
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_DELETE_CHILD,
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks return (0);
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * If target object has delete permission then we are done
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks if ((zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode,
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks return (0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Second row
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * If directory returns EACCES then delete_child was denied
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * due to deny delete_child. In this case send the request through
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * secpolicy_vnode_remove(). We don't use zfs_delete_final_check()
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * since that *could* allow the delete based on write/execute permission
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * and we want delete permissions to override write/execute.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Third Row
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks * only need to see if we have write/execute on directory.
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0)
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * Fourth row
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0;
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0;
23d5bb1f2275e3b549733444de8e92fb47d0631bmarks return (zfs_delete_final_check(zp, dzp, missing_perms, cr));
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