zfs_acl.c revision 134a1f4e3289b54e0f980e9cf05352e419a60bee
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.
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.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum VERIFY(0 == sa_lookup(zp->z_sa_hdl, SA_ZPL_ZNODE_ACL(zp->z_zfsvfs),
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);
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.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Also, create FUIDs for any User/Group ACEs
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));
1ab996781aab376b5ee79af025ab24ff42a0a3f0Mark Shellenbaum * Skip over owner@, group@ or everyone@ inherit only ACEs
1ab996781aab376b5ee79af025ab24ff42a0a3f0Mark Shellenbaum (entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
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.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwzfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify)
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 */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock return (0);
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,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaumzfs_acl_get_owner_fuids(znode_t *zp, uint64_t *fuid, uint64_t *fgid)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (IS_EPHEMERAL(zp->z_uid) || IS_EPHEMERAL(zp->z_gid)) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zp->z_zfsvfs), NULL,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zp->z_zfsvfs), NULL,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((error = sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) != 0) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((error = zfs_acl_node_read(zp, &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)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((error = zfs_acl_get_owner_fuids(zp, &fuid, &fgid)) != 0)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum mode = zfs_mode_compute(mode, aclp, &zp->z_pflags, fuid, fgid);
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));
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,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaumzfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum size_t abstract_size = aclp->z_ops.ace_abstract_size();
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum acl_trivial_access_masks((mode_t)mode, &allow0, &deny1, &deny2,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum newnode = zfs_acl_node_alloc((abstract_size * 6) + aclp->z_acl_bytes);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, allow0, ALLOW, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, deny1, DENY, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, 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,
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if ((entry_type == ACE_OWNER || entry_type == ACE_EVERYONE ||
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum ((inherit_flags & ACE_INHERIT_ONLY_ACE) == 0)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * Limit permissions to be no greater than
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * group permissions
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_RESTRICTED) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum ACE_WRITE_ATTRIBUTES|ACE_WRITE_NAMED_ATTRS);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, access_mask, type, who, iflags);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + ace_size);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, owner, 0, -1, ACE_OWNER);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, group, 0, -1, OWNING_GROUP);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zacep = (void *)((uintptr_t)zacep + abstract_size);
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_set_ace(aclp, zacep, everyone, 0, -1, ACE_EVERYONE);
4c841f6070b4f88f9dc008de526b313bbebd4e32markszfs_acl_chmod_setattr(znode_t *zp, zfs_acl_t **aclp, uint64_t mode)
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum *aclp = zfs_acl_alloc(zfs_acl_version_zp(zp));
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum (*aclp)->z_hints = zp->z_pflags & V4_ACL_WIDE_FLAGS;
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;
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK)
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 &
c694df91a1cf9e8c631e696641c4475968652f40Mark 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) {
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * If only FILE_INHERIT is set then turn on
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum * inherit_only
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.
4a1f0cc97e50e029e40b6055fa68f89c9ae6bb38Mark Shellenbaum if ((flag & IS_ROOT_NODE) || zfsvfs->z_replay ||
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum VERIFY(0 == sa_lookup(dzp->z_sa_hdl, SA_ZPL_GID(zfsvfs),
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) &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum if (!(flag & IS_ROOT_NODE) && (ZTOV(dzp)->v_type == VDIR &&
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum VERIFY(0 == zfs_acl_node_read(dzp, &paclp, B_FALSE));
89459e17032b6bb1d59eebd2b7c0d06859d4657cMark Shellenbaum vap->va_type, paclp, acl_ids->z_mode, &need_chmod);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum acl_ids->z_aclp->z_hints |= ZFS_ACL_TRIVIAL;
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum acl_ids->z_aclp->z_hints |= (vap->va_type == VDIR) ?
27dd1e87cd3d939264769dd4af7e6a529cde001fMark Shellenbaum zfs_acl_chmod(zfsvfs, acl_ids->z_mode, acl_ids->z_aclp);
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));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Retrieve a files 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))
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);
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.
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
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum ZNODE_ACL_VERSION(zp) <= ZFS_ACL_VERSION_INITIAL) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum dmu_tx_hold_free(tx, ZFS_EXTERNAL_ACL(zp), 0,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum dmu_tx_hold_write(tx, ZFS_EXTERNAL_ACL(zp),
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
e802abbda8c322f24d47835734f4a793ef15ddc8Tim Haley * EACCESS 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,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if ((error = sa_lookup(zp->z_sa_hdl, SA_ZPL_GID(zfsvfs),
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) {
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik return (secpolicy_vnode_any_access(cr, ZTOV(zp),
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)
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (IS_EPHEMERAL(zdp->z_uid) != 0 || IS_EPHEMERAL(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
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,
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik return (secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid,
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))
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(check_zp), zp->z_uid,
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid);
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum error = secpolicy_vnode_setdac(cr, zp->z_uid);
47def0dc58be41683fc5c0729b1308e689fc9d4aMark Shellenbaum if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) {
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum error = secpolicy_vnode_chown(cr, zp->z_uid);
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) {
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid,
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
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik error = secpolicy_vnode_access2(cr, ZTOV(dzp),
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.
0a586cea3ceec7e5e50e7e54c745082a7a333ac2Mark Shellenbaum if (zp->z_pflags & (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.
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA,
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr);
7ed7e920b3b51c792a1541c93ef3d50f4a07763emarks * Fourth row
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE;
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC;
134a1f4e3289b54e0f980e9cf05352e419a60beeCasper H.S. Dik return (zfs_delete_final_check(zp, dzp, available_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