summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2010-09-20 17:10:06 +0000
committertrasz <trasz@FreeBSD.org>2010-09-20 17:10:06 +0000
commit3e2d23f909272476403e9cfd83e4f5c8c0110d07 (patch)
treef8114c58aa3c9da5fbe374cab1b67f84701f28fa
parent154966ba66b85cf61d19a97a29e55b603e63a9ec (diff)
downloadFreeBSD-src-3e2d23f909272476403e9cfd83e4f5c8c0110d07.zip
FreeBSD-src-3e2d23f909272476403e9cfd83e4f5c8c0110d07.tar.gz
First step at adopting FreeBSD to support PSARC/2010/029. This makes
acl_is_trivial_np(3) properly recognize the new trivial ACLs. From the user point of view, that means "ls -l" no longer shows plus signs for all the files when running ZFS v28.
-rw-r--r--lib/libc/posix1e/acl_strip.c32
-rw-r--r--sys/kern/subr_acl_nfs4.c77
-rw-r--r--sys/sys/acl.h2
3 files changed, 105 insertions, 6 deletions
diff --git a/lib/libc/posix1e/acl_strip.c b/lib/libc/posix1e/acl_strip.c
index 82eacdc..c4065d6 100644
--- a/lib/libc/posix1e/acl_strip.c
+++ b/lib/libc/posix1e/acl_strip.c
@@ -31,19 +31,21 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <assert.h>
#include <sys/acl.h>
+#include <sys/stat.h>
#include "acl_support.h"
/*
- * These two routines from sys/kern/subr_acl_nfs4.c are used by both kernel
+ * These three routines from sys/kern/subr_acl_nfs4.c are used by both kernel
* and libc.
*/
+void acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode);
void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode,
int file_owner_id);
void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
static acl_t
-_nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask)
+_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
{
acl_t newacl;
mode_t mode = 0;
@@ -57,7 +59,10 @@ _nfs4_acl_strip_np(const acl_t aclp, int recalculate_mask)
_acl_brand_as(newacl, ACL_BRAND_NFS4);
acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
- acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1);
+ if (canonical_six)
+ acl_nfs4_sync_acl_from_mode(&(newacl->ats_acl), mode, -1);
+ else
+ acl_nfs4_trivial_from_mode(&(newacl->ats_acl), mode);
return (newacl);
}
@@ -136,7 +141,7 @@ acl_strip_np(const acl_t aclp, int recalculate_mask)
{
switch (_acl_brand(aclp)) {
case ACL_BRAND_NFS4:
- return (_nfs4_acl_strip_np(aclp, recalculate_mask));
+ return (_nfs4_acl_strip_np(aclp, 1));
case ACL_BRAND_POSIX:
return (_posix1e_acl_strip_np(aclp, recalculate_mask));
@@ -185,10 +190,25 @@ acl_is_trivial_np(const acl_t aclp, int *trivialp)
}
/*
- * Calculate trivial ACL - using acl_strip_np - and compare
+ * Calculate trivial ACL - using acl_strip_np(3) - and compare
* with the original.
*/
- tmpacl = acl_strip_np(aclp, 0);
+ tmpacl = _nfs4_acl_strip_np(aclp, 0);
+ if (tmpacl == NULL)
+ return (-1);
+
+ differs = _acl_differs(aclp, tmpacl);
+ acl_free(tmpacl);
+
+ if (differs == 0) {
+ *trivialp = 1;
+ return (0);
+ }
+
+ /*
+ * Try again with an old-style, "canonical six" trivial ACL.
+ */
+ tmpacl = _nfs4_acl_strip_np(aclp, 1);
if (tmpacl == NULL)
return (-1);
diff --git a/sys/kern/subr_acl_nfs4.c b/sys/kern/subr_acl_nfs4.c
index 5b2b086..3498ddf 100644
--- a/sys/kern/subr_acl_nfs4.c
+++ b/sys/kern/subr_acl_nfs4.c
@@ -349,6 +349,83 @@ _acl_duplicate_entry(struct acl *aclp, int entry_index)
return (&(aclp->acl_entry[entry_index + 1]));
}
+/*
+ * Calculate trivial ACL in a manner compatible with PSARC/2010/029.
+ * Note that this results in an ACL different from (but semantically
+ * equal to) the "canonical six" trivial ACL computed using algorithm
+ * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2.
+ */
+void
+acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode)
+{
+ acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0;
+ acl_perm_t user_allow, group_allow, everyone_allow;
+
+ KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0"));
+
+ user_allow = group_allow = everyone_allow = ACL_READ_ACL |
+ ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE;
+ user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES |
+ ACL_WRITE_NAMED_ATTRS;
+
+ if (mode & S_IRUSR)
+ user_allow |= ACL_READ_DATA;
+ if (mode & S_IWUSR)
+ user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+ if (mode & S_IXUSR)
+ user_allow |= ACL_EXECUTE;
+
+ if (mode & S_IRGRP)
+ group_allow |= ACL_READ_DATA;
+ if (mode & S_IWGRP)
+ group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+ if (mode & S_IXGRP)
+ group_allow |= ACL_EXECUTE;
+
+ if (mode & S_IROTH)
+ everyone_allow |= ACL_READ_DATA;
+ if (mode & S_IWOTH)
+ everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA);
+ if (mode & S_IXOTH)
+ everyone_allow |= ACL_EXECUTE;
+
+ user_deny = ((group_allow | everyone_allow) & ~user_allow);
+ group_deny = everyone_allow & ~group_allow;
+ user_allow_first = group_deny & ~user_deny;
+
+#if 1
+ /*
+ * This is a workaround for what looks like a bug in ZFS - trivial
+ * ACL for mode 0077 should look like this:
+ *
+ * owner@:rwxp----------:------:deny
+ * owner@:------aARWcCos:------:allow
+ * group@:rwxp--a-R-c--s:------:allow
+ * everyone@:rwxp--a-R-c--s:------:allow
+ *
+ * Instead, ZFS makes it like this:
+ *
+ * owner@:rwx-----------:------:deny
+ * owner@:------aARWcCos:------:allow
+ * group@:rwxp--a-R-c--s:------:allow
+ * everyone@:rwxp--a-R-c--s:------:allow
+ */
+ user_allow_first &= ~ACL_APPEND_DATA;
+ user_deny &= ~ACL_APPEND_DATA;
+ group_deny &= ~ACL_APPEND_DATA;
+#endif
+
+ if (user_allow_first != 0)
+ _acl_append(aclp, ACL_USER_OBJ, user_allow_first, ACL_ENTRY_TYPE_ALLOW);
+ if (user_deny != 0)
+ _acl_append(aclp, ACL_USER_OBJ, user_deny, ACL_ENTRY_TYPE_DENY);
+ if (group_deny != 0)
+ _acl_append(aclp, ACL_GROUP_OBJ, group_deny, ACL_ENTRY_TYPE_DENY);
+ _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW);
+ _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW);
+ _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW);
+}
+
void
acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id)
{
diff --git a/sys/sys/acl.h b/sys/sys/acl.h
index 80a3fe6..614d011 100644
--- a/sys/sys/acl.h
+++ b/sys/sys/acl.h
@@ -285,6 +285,8 @@ mode_t acl_posix1e_newfilemode(mode_t cmode,
struct acl *acl_alloc(int flags);
void acl_free(struct acl *aclp);
+void acl_nfs4_trivial_from_mode(struct acl *aclp,
+ mode_t mode);
void acl_nfs4_sync_acl_from_mode(struct acl *aclp,
mode_t mode, int file_owner_id);
void acl_nfs4_sync_mode_from_acl(mode_t *mode,
OpenPOWER on IntegriCloud