Return-Path: Received: from mx1.redhat.com ([209.132.183.28]:46145 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964825AbbKCPVx (ORCPT ); Tue, 3 Nov 2015 10:21:53 -0500 From: Andreas Gruenbacher To: Alexander Viro , "Theodore Ts'o" , Andreas Dilger , "J. Bruce Fields" , Jeff Layton , Trond Myklebust , Anna Schumaker , Dave Chinner , linux-ext4@vger.kernel.org, xfs@oss.sgi.com, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-api@vger.kernel.org Cc: Andreas Gruenbacher Subject: [PATCH v13 37/51] nfsd: Use richacls as internal acl representation Date: Tue, 3 Nov 2015 16:17:13 +0100 Message-Id: <1446563847-14005-38-git-send-email-agruenba@redhat.com> In-Reply-To: <1446563847-14005-1-git-send-email-agruenba@redhat.com> References: <1446563847-14005-1-git-send-email-agruenba@redhat.com> Sender: linux-nfs-owner@vger.kernel.org List-ID: When converting from NFSv4 ACLs to POSIX ACLs, nfsd so far was using struct nfs4_acl as its internal representation. This representation is a subset of richacls, so get rid of struct nfs4_acl. Richacls even have a more compact in-memory representation, so a few more ACL entries can easily be supported. Signed-off-by: Andreas Gruenbacher Acked-by: J. Bruce Fields --- fs/Kconfig | 6 + fs/nfs_common/Makefile | 1 + fs/nfs_common/nfs4acl.c | 44 ++++++ fs/nfsd/Kconfig | 1 + fs/nfsd/acl.h | 24 ++-- fs/nfsd/nfs4acl.c | 368 ++++++++++++++++++++++-------------------------- fs/nfsd/nfs4proc.c | 15 +- fs/nfsd/nfs4xdr.c | 64 +++------ fs/nfsd/xdr4.h | 6 +- include/linux/nfs4.h | 23 --- include/linux/nfs4acl.h | 7 + 11 files changed, 274 insertions(+), 285 deletions(-) create mode 100644 fs/nfs_common/nfs4acl.c create mode 100644 include/linux/nfs4acl.h diff --git a/fs/Kconfig b/fs/Kconfig index bff2879..68bc3e1 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -265,6 +265,12 @@ config NFS_COMMON depends on NFSD || NFS_FS || LOCKD default y +config NFS_RICHACL + bool + depends on NFSD_V4 || NFS_V4 + select FS_RICHACL + default y + source "net/sunrpc/Kconfig" source "fs/ceph/Kconfig" source "fs/cifs/Kconfig" diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile index d153ca3..e055139 100644 --- a/fs/nfs_common/Makefile +++ b/fs/nfs_common/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o nfs_acl-objs := nfsacl.o +obj-$(CONFIG_NFS_RICHACL) += nfs4acl.o obj-$(CONFIG_GRACE_PERIOD) += grace.o diff --git a/fs/nfs_common/nfs4acl.c b/fs/nfs_common/nfs4acl.c new file mode 100644 index 0000000..02df064 --- /dev/null +++ b/fs/nfs_common/nfs4acl.c @@ -0,0 +1,44 @@ +#include +#include +#include + +static struct special_id { + char *who; + int len; +} special_who_map[] = { + [RICHACE_OWNER_SPECIAL_ID] = { + .who = "OWNER@", + .len = sizeof("OWNER@") - 1 }, + [RICHACE_GROUP_SPECIAL_ID] = { + .who = "GROUP@", + .len = sizeof("GROUP@") - 1 }, + [RICHACE_EVERYONE_SPECIAL_ID] = { + .who = "EVERYONE@", + .len = sizeof("EVERYONE@") - 1 } +}; + +int nfs4acl_who_to_special_id(const char *who, u32 len) +{ + int n; + + for (n = 0; n < ARRAY_SIZE(special_who_map); n++) { + if (len == special_who_map[n].len && + !memcmp(who, special_who_map[n].who, len)) + return n; + } + return -1; +} +EXPORT_SYMBOL(nfs4acl_who_to_special_id); + +bool nfs4acl_special_id_to_who(unsigned int special_who, + const char **who, unsigned int *len) +{ + struct special_id *special = &special_who_map[special_who]; + + if (special_who > ARRAY_SIZE(special_who_map) || !special->len) + return false; + *who = special->who; + *len = special->len; + return true; +} +EXPORT_SYMBOL(nfs4acl_special_id_to_who); diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index a0b77fc..811379a 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -70,6 +70,7 @@ config NFSD_V4 depends on NFSD && PROC_FS select NFSD_V3 select FS_POSIX_ACL + select FS_RICHACL select SUNRPC_GSS select CRYPTO select GRACE_PERIOD diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index 4cd7c69..1c5deb5 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h @@ -35,25 +35,27 @@ #ifndef LINUX_NFS4_ACL_H #define LINUX_NFS4_ACL_H -struct nfs4_acl; +struct richacl; +struct richace; struct svc_fh; struct svc_rqst; /* * Maximum ACL we'll accept from a client; chosen (somewhat * arbitrarily) so that kmalloc'ing the ACL shouldn't require a - * high-order allocation. This allows 204 ACEs on x86_64: + * high-order allocation. This allows 339 ACEs on x86_64: */ -#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \ - / sizeof(struct nfs4_ace)) +#define NFSD4_ACL_MAX ((PAGE_SIZE - sizeof(struct richacl)) \ + / sizeof(struct richace)) -int nfs4_acl_bytes(int entries); -int nfs4_acl_get_whotype(char *, u32); -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who); +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, + char *who, u32 len); +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, + struct richace *ace); -int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, - struct nfs4_acl **acl); -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl); +int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct richacl **acl); +__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct richacl *acl); #endif /* LINUX_NFS4_ACL_H */ diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 6adabd6..6d3bb72 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -37,46 +37,50 @@ #include #include #include +#include +#include +#include #include "nfsfh.h" #include "nfsd.h" +#include "idmap.h" #include "acl.h" #include "vfs.h" -#define NFS4_ACL_TYPE_DEFAULT 0x01 -#define NFS4_ACL_DIR 0x02 -#define NFS4_ACL_OWNER 0x04 +#define FLAG_DEFAULT_ACL 0x01 +#define FLAG_DIRECTORY 0x02 +#define FLAG_OWNER 0x04 /* mode bit translations: */ -#define NFS4_READ_MODE (NFS4_ACE_READ_DATA) -#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA) -#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE -#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE) -#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL) +#define RICHACE_READ_MODE (RICHACE_READ_DATA) +#define RICHACE_WRITE_MODE (RICHACE_WRITE_DATA | RICHACE_APPEND_DATA) +#define RICHACE_EXECUTE_MODE RICHACE_EXECUTE +#define RICHACE_ANYONE_MODE (RICHACE_READ_ATTRIBUTES | RICHACE_READ_ACL | RICHACE_SYNCHRONIZE) +#define RICHACE_OWNER_MODE (RICHACE_WRITE_ATTRIBUTES | RICHACE_WRITE_ACL) /* flags used to simulate posix default ACLs */ -#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ - | NFS4_ACE_DIRECTORY_INHERIT_ACE) - -#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ - | NFS4_ACE_INHERIT_ONLY_ACE \ - | NFS4_ACE_IDENTIFIER_GROUP) +#define RICHACE_SUPPORTED_FLAGS ( \ + RICHACE_FILE_INHERIT_ACE | \ + RICHACE_DIRECTORY_INHERIT_ACE | \ + RICHACE_INHERIT_ONLY_ACE | \ + RICHACE_IDENTIFIER_GROUP | \ + RICHACE_SPECIAL_WHO) static u32 mask_from_posix(unsigned short perm, unsigned int flags) { - int mask = NFS4_ANYONE_MODE; + int mask = RICHACE_ANYONE_MODE; - if (flags & NFS4_ACL_OWNER) - mask |= NFS4_OWNER_MODE; + if (flags & FLAG_OWNER) + mask |= RICHACE_OWNER_MODE; if (perm & ACL_READ) - mask |= NFS4_READ_MODE; + mask |= RICHACE_READ_MODE; if (perm & ACL_WRITE) - mask |= NFS4_WRITE_MODE; - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) - mask |= NFS4_ACE_DELETE_CHILD; + mask |= RICHACE_WRITE_MODE; + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) + mask |= RICHACE_DELETE_CHILD; if (perm & ACL_EXECUTE) - mask |= NFS4_EXECUTE_MODE; + mask |= RICHACE_EXECUTE_MODE; return mask; } @@ -86,13 +90,13 @@ deny_mask_from_posix(unsigned short perm, u32 flags) u32 mask = 0; if (perm & ACL_READ) - mask |= NFS4_READ_MODE; + mask |= RICHACE_READ_MODE; if (perm & ACL_WRITE) - mask |= NFS4_WRITE_MODE; - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) - mask |= NFS4_ACE_DELETE_CHILD; + mask |= RICHACE_WRITE_MODE; + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) + mask |= RICHACE_DELETE_CHILD; if (perm & ACL_EXECUTE) - mask |= NFS4_EXECUTE_MODE; + mask |= RICHACE_EXECUTE_MODE; return mask; } @@ -108,32 +112,33 @@ deny_mask_from_posix(unsigned short perm, u32 flags) static void low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) { - u32 write_mode = NFS4_WRITE_MODE; + u32 write_mode = RICHACE_WRITE_MODE; - if (flags & NFS4_ACL_DIR) - write_mode |= NFS4_ACE_DELETE_CHILD; + if (flags & FLAG_DIRECTORY) + write_mode |= RICHACE_DELETE_CHILD; *mode = 0; - if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) + if ((perm & RICHACE_READ_MODE) == RICHACE_READ_MODE) *mode |= ACL_READ; if ((perm & write_mode) == write_mode) *mode |= ACL_WRITE; - if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) + if ((perm & RICHACE_EXECUTE_MODE) == RICHACE_EXECUTE_MODE) *mode |= ACL_EXECUTE; } -static short ace2type(struct nfs4_ace *); -static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, +static short ace2type(struct richace *); +static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *, unsigned int); int -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, - struct nfs4_acl **acl) +nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct richacl **acl) { struct inode *inode = d_inode(dentry); int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; + struct richacl_alloc alloc; unsigned int flags = 0; - int size = 0; + int count; pacl = get_acl(inode, ACL_TYPE_ACCESS); if (!pacl) @@ -143,10 +148,10 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, return PTR_ERR(pacl); /* allocate for worst case: one (deny, allow) pair each: */ - size += 2 * pacl->a_count; + count = 2 * pacl->a_count; if (S_ISDIR(inode->i_mode)) { - flags = NFS4_ACL_DIR; + flags = FLAG_DIRECTORY; dpacl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(dpacl)) { error = PTR_ERR(dpacl); @@ -154,20 +159,20 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, } if (dpacl) - size += 2 * dpacl->a_count; + count += 2 * dpacl->a_count; } - *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL); - if (*acl == NULL) { + if (!richacl_prepare(&alloc, count)) { error = -ENOMEM; goto out; } - (*acl)->naces = 0; - _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); + _posix_to_richacl_one(pacl, &alloc, flags); if (dpacl) - _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); + _posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL); + + *acl = alloc.acl; out: posix_acl_release(dpacl); @@ -230,21 +235,22 @@ summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) /* We assume the acl has been verified with posix_acl_valid. */ static void -_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, - unsigned int flags) +_posix_to_richacl_one(struct posix_acl *pacl, struct richacl_alloc *alloc, + unsigned int flags) { struct posix_acl_entry *pa, *group_owner_entry; - struct nfs4_ace *ace; + struct richace *ace; struct posix_acl_summary pas; unsigned short deny; - int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? - NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0); + int e_flags = ((flags & FLAG_DEFAULT_ACL) ? + (RICHACE_FILE_INHERIT_ACE | + RICHACE_DIRECTORY_INHERIT_ACE | + RICHACE_INHERIT_ONLY_ACE) : 0); BUG_ON(pacl->a_count < 3); summarize_posix_acl(pacl, &pas); pa = pacl->a_entries; - ace = acl->aces + acl->naces; /* We could deny everything not granted by the owner: */ deny = ~pas.owner; @@ -254,42 +260,35 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, */ deny &= pas.users | pas.group | pas.groups | pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_OWNER; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; } - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); - ace->whotype = NFS4_ACL_WHO_OWNER; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pa->e_perm, flags | FLAG_OWNER); + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; pa++; while (pa->e_tag == ACL_USER) { deny = ~(pa->e_perm & pas.mask); deny &= pas.groups | pas.group | pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_uid = pa->e_uid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.uid = pa->e_uid; } - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, - flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_uid = pa->e_uid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags; + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); + ace->e_id.uid = pa->e_uid; pa++; } @@ -300,23 +299,19 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, group_owner_entry = pa; - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pas.group, flags); - ace->whotype = NFS4_ACL_WHO_GROUP; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pas.group, flags); + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; pa++; while (pa->e_tag == ACL_GROUP) { - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, - flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_gid = pa->e_gid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); + ace->e_id.gid = pa->e_gid; pa++; } @@ -326,12 +321,11 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, deny = ~pas.group & pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_GROUP; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; } pa++; @@ -339,24 +333,22 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, deny = ~(pa->e_perm & pas.mask); deny &= pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_gid = pa->e_gid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.gid = pa->e_gid; } pa++; } if (pa->e_tag == ACL_MASK) pa++; - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm, flags); - ace->whotype = NFS4_ACL_WHO_EVERYONE; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pa->e_perm, flags); + ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID; } static bool @@ -500,7 +492,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) * and effective cases: when there are no inheritable ACEs, * calls ->set_acl with a NULL ACL structure. */ - if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) + if (state->empty && (flags & FLAG_DEFAULT_ACL)) return NULL; /* @@ -619,24 +611,24 @@ static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) } static void process_one_v4_ace(struct posix_acl_state *state, - struct nfs4_ace *ace) + struct richace *ace) { - u32 mask = ace->access_mask; + u32 mask = ace->e_mask; int i; state->empty = 0; switch (ace2type(ace)) { case ACL_USER_OBJ: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); } else { deny_bits(&state->owner, mask); } break; case ACL_USER: - i = find_uid(state, ace->who_uid); - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + i = find_uid(state, ace->e_id.uid); + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->users->aces[i].perms, mask); } else { deny_bits(&state->users->aces[i].perms, mask); @@ -645,7 +637,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_GROUP_OBJ: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->group, mask); } else { deny_bits(&state->group, mask); @@ -657,8 +649,8 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_GROUP: - i = find_gid(state, ace->who_gid); - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + i = find_gid(state, ace->e_id.gid); + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->groups->aces[i].perms, mask); } else { deny_bits(&state->groups->aces[i].perms, mask); @@ -671,7 +663,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_OTHER: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); allow_bits(&state->group, mask); allow_bits(&state->other, mask); @@ -689,32 +681,33 @@ static void process_one_v4_ace(struct posix_acl_state *state, } } -static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, +static int nfs4_richacl_to_posix(struct richacl *acl, struct posix_acl **pacl, struct posix_acl **dpacl, unsigned int flags) { struct posix_acl_state effective_acl_state, default_acl_state; - struct nfs4_ace *ace; + struct richace *ace; int ret; - ret = init_state(&effective_acl_state, acl->naces); + ret = init_state(&effective_acl_state, acl->a_count); if (ret) return ret; - ret = init_state(&default_acl_state, acl->naces); + ret = init_state(&default_acl_state, acl->a_count); if (ret) goto out_estate; ret = -EINVAL; - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && - ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) + richacl_for_each_entry(ace, acl) { + if (ace->e_type != RICHACE_ACCESS_ALLOWED_ACE_TYPE && + ace->e_type != RICHACE_ACCESS_DENIED_ACE_TYPE) goto out_dstate; - if (ace->flag & ~NFS4_SUPPORTED_FLAGS) + if (ace->e_flags & ~RICHACE_SUPPORTED_FLAGS) goto out_dstate; - if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { + if ((ace->e_flags & (RICHACE_FILE_INHERIT_ACE | + RICHACE_DIRECTORY_INHERIT_ACE)) == 0) { process_one_v4_ace(&effective_acl_state, ace); continue; } - if (!(flags & NFS4_ACL_DIR)) + if (!(flags & FLAG_DIRECTORY)) goto out_dstate; /* * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT @@ -723,7 +716,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, */ process_one_v4_ace(&default_acl_state, ace); - if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) + if (!(ace->e_flags & RICHACE_INHERIT_ONLY_ACE)) process_one_v4_ace(&effective_acl_state, ace); } *pacl = posix_state_to_acl(&effective_acl_state, flags); @@ -733,7 +726,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, goto out_dstate; } *dpacl = posix_state_to_acl(&default_acl_state, - flags | NFS4_ACL_TYPE_DEFAULT); + flags | FLAG_DEFAULT_ACL); if (IS_ERR(*dpacl)) { ret = PTR_ERR(*dpacl); *dpacl = NULL; @@ -752,8 +745,7 @@ out_estate: } __be32 -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl) +nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl) { __be32 error; int host_error; @@ -774,9 +766,9 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, return nfserr_attrnotsupp; if (S_ISDIR(inode->i_mode)) - flags = NFS4_ACL_DIR; + flags = FLAG_DIRECTORY; - host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags); if (host_error == -EINVAL) return nfserr_attrnotsupp; if (host_error < 0) @@ -803,82 +795,62 @@ out_nfserr: static short -ace2type(struct nfs4_ace *ace) +ace2type(struct richace *ace) { - switch (ace->whotype) { - case NFS4_ACL_WHO_NAMED: - return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? - ACL_GROUP : ACL_USER); - case NFS4_ACL_WHO_OWNER: + if (ace->e_flags & RICHACE_SPECIAL_WHO) { + switch (ace->e_id.special) { + case RICHACE_OWNER_SPECIAL_ID: return ACL_USER_OBJ; - case NFS4_ACL_WHO_GROUP: + case RICHACE_GROUP_SPECIAL_ID: return ACL_GROUP_OBJ; - case NFS4_ACL_WHO_EVERYONE: + case RICHACE_EVERYONE_SPECIAL_ID: return ACL_OTHER; + default: + BUG(); + } } - BUG(); - return -1; -} - -/* - * return the size of the struct nfs4_acl required to represent an acl - * with @entries entries. - */ -int nfs4_acl_bytes(int entries) -{ - return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace); + return ace->e_flags & RICHACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER; } -static struct { - char *string; - int stringlen; - int type; -} s2t_map[] = { - { - .string = "OWNER@", - .stringlen = sizeof("OWNER@") - 1, - .type = NFS4_ACL_WHO_OWNER, - }, - { - .string = "GROUP@", - .stringlen = sizeof("GROUP@") - 1, - .type = NFS4_ACL_WHO_GROUP, - }, - { - .string = "EVERYONE@", - .stringlen = sizeof("EVERYONE@") - 1, - .type = NFS4_ACL_WHO_EVERYONE, - }, -}; - -int -nfs4_acl_get_whotype(char *p, u32 len) +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, + char *who, u32 len) { - int i; - - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { - if (s2t_map[i].stringlen == len && - 0 == memcmp(s2t_map[i].string, p, len)) - return s2t_map[i].type; + int special_id; + + special_id = nfs4acl_who_to_special_id(who, len); + if (special_id >= 0) { + ace->e_flags |= RICHACE_SPECIAL_WHO; + ace->e_flags &= ~RICHACE_IDENTIFIER_GROUP; + ace->e_id.special = special_id; + return nfs_ok; } - return NFS4_ACL_WHO_NAMED; + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) + return nfsd_map_name_to_gid(rqstp, who, len, &ace->e_id.gid); + else + return nfsd_map_name_to_uid(rqstp, who, len, &ace->e_id.uid); } -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who) +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, + struct richace *ace) { - __be32 *p; - int i; - - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { - if (s2t_map[i].type != who) - continue; - p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4); + if (ace->e_flags & RICHACE_SPECIAL_WHO) { + unsigned int special_id = ace->e_id.special; + const char *who; + unsigned int len; + __be32 *p; + + if (!nfs4acl_special_id_to_who(special_id, &who, &len)) { + WARN_ON_ONCE(1); + return nfserr_serverfault; + } + p = xdr_reserve_space(xdr, len + 4); if (!p) return nfserr_resource; - p = xdr_encode_opaque(p, s2t_map[i].string, - s2t_map[i].stringlen); + p = xdr_encode_opaque(p, who, len); return 0; } - WARN_ON_ONCE(1); - return nfserr_serverfault; + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) + return nfsd4_encode_group(xdr, rqstp, ace->e_id.gid); + else + return nfsd4_encode_user(xdr, rqstp, ace->e_id.uid); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 4ce6b97..2430235 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -159,12 +159,12 @@ is_create_with_attrs(struct nfsd4_open *open) * in the returned attr bitmap. */ static void -do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl, u32 *bmval) +do_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl, + u32 *bmval) { __be32 status; - status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); + status = nfsd4_set_acl(rqstp, fhp, acl); if (status) /* * We should probably fail the whole open at this point, @@ -299,7 +299,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru goto out; if (is_create_with_attrs(open) && open->op_acl != NULL) - do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval); + do_set_acl(rqstp, *resfh, open->op_acl, open->op_bmval); nfsd4_set_open_owner_reply_cache(cstate, open, *resfh); accmode = NFSD_MAY_NOP; @@ -672,8 +672,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); if (create->cr_acl != NULL) - do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, - create->cr_bmval); + do_set_acl(rqstp, &resfh, create->cr_acl, create->cr_bmval); fh_unlock(&cstate->current_fh); set_change_info(&create->cr_cinfo, &cstate->current_fh); @@ -938,8 +937,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; if (setattr->sa_acl != NULL) - status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, - setattr->sa_acl); + status = nfsd4_set_acl(rqstp, &cstate->current_fh, + setattr->sa_acl); if (status) goto out; if (setattr->sa_label.len) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b8db5a7..8603f40 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -303,7 +303,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) static __be32 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, - struct iattr *iattr, struct nfs4_acl **acl, + struct iattr *iattr, struct richacl **acl, struct xdr_netobj *label) { int expected_len, len = 0; @@ -326,38 +326,31 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, } if (bmval[0] & FATTR4_WORD0_ACL) { u32 nace; - struct nfs4_ace *ace; + struct richace *ace; READ_BUF(4); len += 4; nace = be32_to_cpup(p++); - if (nace > NFS4_ACL_MAX) + if (nace > NFSD4_ACL_MAX) return nfserr_fbig; - *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); + *acl = svcxdr_alloc_richacl(argp, nace); if (*acl == NULL) return nfserr_jukebox; - (*acl)->naces = nace; - for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { + richacl_for_each_entry(ace, *acl) { READ_BUF(16); len += 16; - ace->type = be32_to_cpup(p++); - ace->flag = be32_to_cpup(p++); - ace->access_mask = be32_to_cpup(p++); + ace->e_type = be32_to_cpup(p++); + ace->e_flags = be32_to_cpup(p++); + ace->e_mask = be32_to_cpup(p++); + if (ace->e_flags & RICHACE_SPECIAL_WHO) + return nfserr_inval; dummy32 = be32_to_cpup(p++); READ_BUF(dummy32); len += XDR_QUADLEN(dummy32) << 2; READMEM(buf, dummy32); - ace->whotype = nfs4_acl_get_whotype(buf, dummy32); - status = nfs_ok; - if (ace->whotype != NFS4_ACL_WHO_NAMED) - ; - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) - status = nfsd_map_name_to_gid(argp->rqstp, - buf, dummy32, &ace->who_gid); - else - status = nfsd_map_name_to_uid(argp->rqstp, - buf, dummy32, &ace->who_uid); + status = nfsd4_decode_ace_who(ace, argp->rqstp, + buf, dummy32); if (status) return status; } @@ -2148,18 +2141,6 @@ static u32 nfs4_file_type(umode_t mode) } static inline __be32 -nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, - struct nfs4_ace *ace) -{ - if (ace->whotype != NFS4_ACL_WHO_NAMED) - return nfs4_acl_write_who(xdr, ace->whotype); - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) - return nfsd4_encode_group(xdr, rqstp, ace->who_gid); - else - return nfsd4_encode_user(xdr, rqstp, ace->who_uid); -} - -static inline __be32 nfsd4_encode_layout_type(struct xdr_stream *xdr, enum pnfs_layouttype layout_type) { __be32 *p; @@ -2303,7 +2284,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, u32 rdattr_err = 0; __be32 status; int err; - struct nfs4_acl *acl = NULL; + struct richacl *acl = NULL; void *context = NULL; int contextlen; bool contextsupport = false; @@ -2349,7 +2330,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, fhp = tempfh; } if (bmval0 & FATTR4_WORD0_ACL) { - err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + err = nfsd4_get_acl(rqstp, dentry, &acl); if (err == -EOPNOTSUPP) bmval0 &= ~FATTR4_WORD0_ACL; else if (err == -EINVAL) { @@ -2504,7 +2485,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, *p++ = cpu_to_be32(rdattr_err); } if (bmval0 & FATTR4_WORD0_ACL) { - struct nfs4_ace *ace; + struct richace *ace; if (acl == NULL) { p = xdr_reserve_space(xdr, 4); @@ -2517,17 +2498,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(acl->naces); + *p++ = cpu_to_be32(acl->a_count); - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { + richacl_for_each_entry(ace, acl) { p = xdr_reserve_space(xdr, 4*3); if (!p) goto out_resource; - *p++ = cpu_to_be32(ace->type); - *p++ = cpu_to_be32(ace->flag); - *p++ = cpu_to_be32(ace->access_mask & - NFS4_ACE_MASK_ALL); - status = nfsd4_encode_aclname(xdr, rqstp, ace); + *p++ = cpu_to_be32(ace->e_type); + *p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO); + *p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL); + status = nfsd4_encode_ace_who(xdr, rqstp, ace); if (status) goto out; } @@ -2792,7 +2772,7 @@ out: if (context) security_release_secctx(context, contextlen); #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - kfree(acl); + richacl_put(acl); if (tempfh) { fh_put(tempfh); kfree(tempfh); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index b698585..c311066 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -118,7 +118,7 @@ struct nfsd4_create { u32 cr_bmval[3]; /* request */ struct iattr cr_iattr; /* request */ struct nfsd4_change_info cr_cinfo; /* response */ - struct nfs4_acl *cr_acl; + struct richacl *cr_acl; struct xdr_netobj cr_label; }; #define cr_datalen u.link.datalen @@ -248,7 +248,7 @@ struct nfsd4_open { struct nfs4_file *op_file; /* used during processing */ struct nfs4_ol_stateid *op_stp; /* used during processing */ struct nfs4_clnt_odstate *op_odstate; /* used during processing */ - struct nfs4_acl *op_acl; + struct richacl *op_acl; struct xdr_netobj op_label; }; @@ -332,7 +332,7 @@ struct nfsd4_setattr { stateid_t sa_stateid; /* request */ u32 sa_bmval[3]; /* request */ struct iattr sa_iattr; /* request */ - struct nfs4_acl *sa_acl; + struct richacl *sa_acl; struct xdr_netobj sa_label; }; diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 00121f2..1422fc6 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -16,29 +16,6 @@ #include #include -enum nfs4_acl_whotype { - NFS4_ACL_WHO_NAMED = 0, - NFS4_ACL_WHO_OWNER, - NFS4_ACL_WHO_GROUP, - NFS4_ACL_WHO_EVERYONE, -}; - -struct nfs4_ace { - uint32_t type; - uint32_t flag; - uint32_t access_mask; - int whotype; - union { - kuid_t who_uid; - kgid_t who_gid; - }; -}; - -struct nfs4_acl { - uint32_t naces; - struct nfs4_ace aces[0]; -}; - #define NFS4_MAXLABELLEN 2048 struct nfs4_label { diff --git a/include/linux/nfs4acl.h b/include/linux/nfs4acl.h new file mode 100644 index 0000000..db9f9a6 --- /dev/null +++ b/include/linux/nfs4acl.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_NFS4ACL_H +#define __LINUX_NFS4ACL_H + +int nfs4acl_who_to_special_id(const char *, u32); +bool nfs4acl_special_id_to_who(unsigned int, const char **, unsigned int *); + +#endif -- 2.5.0