diff options
Diffstat (limited to 'sys/kern/subr_acl_nfs4.c')
-rw-r--r-- | sys/kern/subr_acl_nfs4.c | 77 |
1 files changed, 77 insertions, 0 deletions
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) { |