Add trivial acl helpers
[zfs.git] / module / zfs / zfs_acl.c
index f1ba9af..ea209ba 100644 (file)
@@ -53,7 +53,6 @@
 #include <sys/zap.h>
 #include <sys/sa.h>
 #include "fs/fs_subr.h"
-#include <acl/acl_common.h>
 
 #define        ALLOW   ACE_ACCESS_ALLOWED_ACE_TYPE
 #define        DENY    ACE_ACCESS_DENIED_ACE_TYPE
@@ -494,7 +493,7 @@ zfs_acl_release_nodes(zfs_acl_t *aclp)
 {
        zfs_acl_node_t *aclnode;
 
-       while (aclnode = list_head(&aclp->z_acl)) {
+       while ((aclnode = list_head(&aclp->z_acl))) {
                list_remove(&aclp->z_acl, aclnode);
                zfs_acl_node_free(aclnode);
        }
@@ -644,13 +643,6 @@ zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt,
        return ((uint64_t)(uintptr_t)acep);
 }
 
-static zfs_acl_node_t *
-zfs_acl_curr_node(zfs_acl_t *aclp)
-{
-       ASSERT(aclp->z_curr_node);
-       return (aclp->z_curr_node);
-}
-
 /*
  * Copy ACE to internal ZFS format.
  * While processing the ACL each ACE will be validated for correctness.
@@ -732,8 +724,8 @@ zfs_copy_fuid_2_ace(zfsvfs_t *zfsvfs, zfs_acl_t *aclp, cred_t *cr,
        size_t ace_size;
        uint16_t entry_type;
 
-       while (zacep = zfs_acl_next_ace(aclp, zacep,
-           &who, &access_mask, &iflags, &type)) {
+       while ((zacep = zfs_acl_next_ace(aclp, zacep,
+           &who, &access_mask, &iflags, &type))) {
 
                switch (type) {
                case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
@@ -823,8 +815,8 @@ zfs_acl_xform(znode_t *zp, zfs_acl_t *aclp, cred_t *cr)
        oldaclp = kmem_alloc(sizeof (zfs_oldace_t) * aclp->z_acl_count,
            KM_SLEEP);
        i = 0;
-       while (cookie = zfs_acl_next_ace(aclp, cookie, &who,
-           &access_mask, &iflags, &type)) {
+       while ((cookie = zfs_acl_next_ace(aclp, cookie, &who,
+           &access_mask, &iflags, &type))) {
                oldaclp[i].z_flags = iflags;
                oldaclp[i].z_type = type;
                oldaclp[i].z_fuid = who;
@@ -904,8 +896,8 @@ zfs_mode_compute(uint64_t fmode, zfs_acl_t *aclp,
 
        mode = (fmode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX));
 
-       while (acep = zfs_acl_next_ace(aclp, acep, &who,
-           &access_mask, &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who,
+           &access_mask, &iflags, &type))) {
 
                if (!zfs_acl_valid_ace_type(type, iflags))
                        continue;
@@ -1173,6 +1165,126 @@ zfs_acl_chown_setattr(znode_t *zp)
        return (error);
 }
 
+static void
+acl_trivial_access_masks(mode_t mode, uint32_t *allow0, uint32_t *deny1,
+    uint32_t *deny2, uint32_t *owner, uint32_t *group, uint32_t *everyone)
+{
+       *deny1 = *deny2 = *allow0 = *group = 0;
+
+       if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
+               *deny1 |= ACE_READ_DATA;
+       if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
+               *deny1 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
+               *deny1 |= ACE_EXECUTE;
+
+       if (!(mode & S_IRGRP) && (mode & S_IROTH))
+               *deny2 = ACE_READ_DATA;
+       if (!(mode & S_IWGRP) && (mode & S_IWOTH))
+               *deny2 |= ACE_WRITE_DATA;
+       if (!(mode & S_IXGRP) && (mode & S_IXOTH))
+               *deny2 |= ACE_EXECUTE;
+
+       if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
+               *allow0 |= ACE_READ_DATA;
+       if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
+               *allow0 |= ACE_WRITE_DATA;
+       if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
+               *allow0 |= ACE_EXECUTE;
+
+       *owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
+           ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
+           ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
+       if (mode & S_IRUSR)
+               *owner |= ACE_READ_DATA;
+       if (mode & S_IWUSR)
+               *owner |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXUSR)
+               *owner |= ACE_EXECUTE;
+
+       *group = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IRGRP)
+               *group |= ACE_READ_DATA;
+       if (mode & S_IWGRP)
+               *group |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXGRP)
+               *group |= ACE_EXECUTE;
+
+       *everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES| ACE_READ_NAMED_ATTRS|
+           ACE_SYNCHRONIZE;
+       if (mode & S_IROTH)
+               *everyone |= ACE_READ_DATA;
+       if (mode & S_IWOTH)
+               *everyone |= ACE_WRITE_DATA|ACE_APPEND_DATA;
+       if (mode & S_IXOTH)
+               *everyone |= ACE_EXECUTE;
+}
+
+/*
+ * ace_trivial:
+ * determine whether an ace_t acl is trivial
+ *
+ * Trivialness implies that the acl is composed of only
+ * owner, group, everyone entries.  ACL can't
+ * have read_acl denied, and write_owner/write_acl/write_attributes
+ * can only be owner@ entry.
+ */
+static int
+ace_trivial_common(void *acep, int aclcnt,
+    uint64_t (*walk)(void *, uint64_t, int aclcnt,
+    uint16_t *, uint16_t *, uint32_t *))
+{
+       uint16_t flags;
+       uint32_t mask;
+       uint16_t type;
+       uint64_t cookie = 0;
+
+       while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) {
+               switch (flags & ACE_TYPE_FLAGS) {
+               case ACE_OWNER:
+               case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+               case ACE_EVERYONE:
+                       break;
+               default:
+                       return (1);
+               }
+
+               if (flags & (ACE_FILE_INHERIT_ACE|
+                   ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
+                   ACE_INHERIT_ONLY_ACE))
+                       return (1);
+
+               /*
+                * Special check for some special bits
+                *
+                * Don't allow anybody to deny reading basic
+                * attributes or a files ACL.
+                */
+               if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
+                   (type == ACE_ACCESS_DENIED_ACE_TYPE))
+                       return (1);
+
+               /*
+                * Delete permissions are never set by default
+                */
+               if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
+                       return (1);
+               /*
+                * only allow owner@ to have
+                * write_acl/write_owner/write_attributes/write_xattr/
+                */
+               if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
+                   (!(flags & ACE_OWNER) && (mask &
+                   (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
+                   ACE_WRITE_NAMED_ATTRS))))
+                       return (1);
+
+       }
+
+       return (0);
+}
+
 /*
  * common code for setting ACLs.
  *
@@ -1332,73 +1444,6 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
        return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
 }
 
-/*
- * Update access mask for prepended ACE
- *
- * This applies the "groupmask" value for aclmode property.
- */
-static void
-zfs_acl_prepend_fixup(zfs_acl_t *aclp, void  *acep, void  *origacep,
-    mode_t mode, uint64_t owner)
-{
-       int     rmask, wmask, xmask;
-       int     user_ace;
-       uint16_t aceflags;
-       uint32_t origmask, acepmask;
-       uint64_t fuid;
-
-       aceflags = aclp->z_ops.ace_flags_get(acep);
-       fuid = aclp->z_ops.ace_who_get(acep);
-       origmask = aclp->z_ops.ace_mask_get(origacep);
-       acepmask = aclp->z_ops.ace_mask_get(acep);
-
-       user_ace = (!(aceflags &
-           (ACE_OWNER|ACE_GROUP|ACE_IDENTIFIER_GROUP)));
-
-       if (user_ace && (fuid == owner)) {
-               rmask = S_IRUSR;
-               wmask = S_IWUSR;
-               xmask = S_IXUSR;
-       } else {
-               rmask = S_IRGRP;
-               wmask = S_IWGRP;
-               xmask = S_IXGRP;
-       }
-
-       if (origmask & ACE_READ_DATA) {
-               if (mode & rmask) {
-                       acepmask &= ~ACE_READ_DATA;
-               } else {
-                       acepmask |= ACE_READ_DATA;
-               }
-       }
-
-       if (origmask & ACE_WRITE_DATA) {
-               if (mode & wmask) {
-                       acepmask &= ~ACE_WRITE_DATA;
-               } else {
-                       acepmask |= ACE_WRITE_DATA;
-               }
-       }
-
-       if (origmask & ACE_APPEND_DATA) {
-               if (mode & wmask) {
-                       acepmask &= ~ACE_APPEND_DATA;
-               } else {
-                       acepmask |= ACE_APPEND_DATA;
-               }
-       }
-
-       if (origmask & ACE_EXECUTE) {
-               if (mode & xmask) {
-                       acepmask &= ~ACE_EXECUTE;
-               } else {
-                       acepmask |= ACE_EXECUTE;
-               }
-       }
-       aclp->z_ops.ace_mask_set(acep, acepmask);
-}
-
 static void
 zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
 {
@@ -1441,8 +1486,8 @@ zfs_acl_chmod(zfsvfs_t *zfsvfs, uint64_t mode, zfs_acl_t *aclp)
                new_bytes += abstract_size;
        }
 
-       while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
-           &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
                uint16_t inherit_flags;
 
                entry_type = (iflags & ACE_TYPE_FLAGS);
@@ -1584,8 +1629,8 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
        aclp = zfs_acl_alloc(paclp->z_version);
        if (zfsvfs->z_acl_inherit == ZFS_ACL_DISCARD || vtype == VLNK)
                return (aclp);
-       while (pacep = zfs_acl_next_ace(paclp, pacep, &who,
-           &access_mask, &iflags, &type)) {
+       while ((pacep = zfs_acl_next_ace(paclp, pacep, &who,
+           &access_mask, &iflags, &type))) {
 
                /*
                 * don't inherit bogus ACEs
@@ -1837,7 +1882,7 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (mask == 0)
                return (ENOSYS);
 
-       if (error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))
+       if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr)))
                return (error);
 
        mutex_enter(&zp->z_acl_lock);
@@ -1857,8 +1902,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
                uint32_t access_mask;
                uint16_t type, iflags;
 
-               while (zacep = zfs_acl_next_ace(aclp, zacep,
-                   &who, &access_mask, &iflags, &type)) {
+               while ((zacep = zfs_acl_next_ace(aclp, zacep,
+                   &who, &access_mask, &iflags, &type))) {
                        switch (type) {
                        case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
                        case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
@@ -1996,7 +2041,7 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
        if (zp->z_pflags & ZFS_IMMUTABLE)
                return (EPERM);
 
-       if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))
+       if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)))
                return (error);
 
        error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
@@ -2072,7 +2117,7 @@ top:
        if (fuidp)
                zfs_fuid_info_free(fuidp);
        dmu_tx_commit(tx);
-done:
+
        mutex_exit(&zp->z_lock);
        mutex_exit(&zp->z_acl_lock);
 
@@ -2173,8 +2218,8 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
 
        ASSERT(zp->z_acl_cached);
 
-       while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
-           &iflags, &type)) {
+       while ((acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask,
+           &iflags, &type))) {
                uint32_t mask_matched;
 
                if (!zfs_acl_valid_ace_type(type, iflags))
@@ -2730,14 +2775,14 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
         * If that succeeds then check for add_file/add_subdir permissions
         */
 
-       if (error = zfs_zaccess_delete(sdzp, szp, cr))
+       if ((error = zfs_zaccess_delete(sdzp, szp, cr)))
                return (error);
 
        /*
         * If we have a tzp, see if we can delete it?
         */
        if (tzp) {
-               if (error = zfs_zaccess_delete(tdzp, tzp, cr))
+               if ((error = zfs_zaccess_delete(tdzp, tzp, cr)))
                        return (error);
        }