Commit 09229edb authored by J.Bruce Fields's avatar J.Bruce Fields Committed by Linus Torvalds

[PATCH] knfsd: nfsd4: acls: relax the nfsv4->posix mapping

Use a different nfsv4->(draft posix) acl mapping which is
	1. completely backwards compatible,
	2. accepts any nfsv4 acl, and
	3. errs on the side of restricting permissions.

In detail:

	1. completely backwards compatible: The new mapping produces the
	same result on any acl produced by the existing (draft
	posix)->nfsv4 mapping; the one exception is that we no longer
	attempt to guess the value of the mask by assuming certain denies
	represent the mask.  Since the server still keeps track of the mask
	locally, sequences of chmod's will still be handled fine; the only
	thing this will change is sequences of chmod's with intervening
	read-modify-writes of the acl.  That last case just isn't worth the
	trouble and the possible misrepresentations of the user's intent
	(if we guess that a certain deny indicates masking is in effect
	when it really isn't).

	2. accepts any nfsv4 acl: That's not quite true: we still reject
	acls that use combinations of inheritance flags that we don't
	support.  We also reject acls that attempt to explicitly deny
	read_acl or read_attributes permissions, or that attempt to deny
	write_acl or write_attributes permissions to the owner of the file.

	3.  errs on the side of restricting permissions: one exception to
	this last rule: we totally ignore some bits (write_owner,
	synchronize, read_named_attributes, etc.) that are completely alien
	to our filesystem semantics, in some cases even if that would mean
	ignoring an explicit deny that we have no intention of enforcing.
	Excepting that, the posix acl produced should be the most
	permissive acl that is not more permissive than the given nfsv4
	acl.

And the new code's shorter, too.  Neato.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d0ebd9c0
...@@ -96,24 +96,26 @@ deny_mask(u32 allow_mask, unsigned int flags) ...@@ -96,24 +96,26 @@ deny_mask(u32 allow_mask, unsigned int flags)
/* XXX: modify functions to return NFS errors; they're only ever /* XXX: modify functions to return NFS errors; they're only ever
* used by nfs code, after all.... */ * used by nfs code, after all.... */
static int /* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) * side of being more restrictive, so the mode bit mapping below is
* pessimistic. An optimistic version would be needed to handle DENY's,
* but we espect to coalesce all ALLOWs and DENYs before mapping to mode
* bits. */
static void
low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
{ {
u32 ignore = 0; u32 write_mode = NFS4_WRITE_MODE;
if (!(flags & NFS4_ACL_DIR)) if (flags & NFS4_ACL_DIR)
ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */ write_mode |= NFS4_ACE_DELETE_CHILD;
perm |= ignore;
*mode = 0; *mode = 0;
if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
*mode |= ACL_READ; *mode |= ACL_READ;
if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE) if ((perm & write_mode) == write_mode)
*mode |= ACL_WRITE; *mode |= ACL_WRITE;
if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
*mode |= ACL_EXECUTE; *mode |= ACL_EXECUTE;
if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
return -EINVAL;
return 0;
} }
struct ace_container { struct ace_container {
...@@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl) ...@@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl)
return; return;
} }
static int
write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
struct posix_acl_entry **pace, short tag, unsigned int flags)
{
struct posix_acl_entry *this = *pace;
if (*pace == pacl->a_entries + pacl->a_count)
return -EINVAL; /* fell off the end */
(*pace)++;
this->e_tag = tag;
if (tag == ACL_USER_OBJ)
flags |= NFS4_ACL_OWNER;
if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
return -EINVAL;
this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
ace->who : ACL_UNDEFINED_ID);
return 0;
}
static struct nfs4_ace *
get_next_v4_ace(struct list_head **p, struct list_head *head)
{
struct nfs4_ace *ace;
*p = (*p)->next;
if (*p == head)
return NULL;
ace = list_entry(*p, struct nfs4_ace, l_ace);
return ace;
}
int int
nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
struct posix_acl **dpacl, unsigned int flags) struct posix_acl **dpacl, unsigned int flags)
...@@ -429,349 +399,311 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, ...@@ -429,349 +399,311 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
return error; return error;
} }
/*
* While processing the NFSv4 ACE, this maintains bitmasks representing
* which permission bits have been allowed and which denied to a given
* entity: */
struct posix_ace_state {
u32 allow;
u32 deny;
};
struct posix_user_ace_state {
uid_t uid;
struct posix_ace_state perms;
};
struct posix_ace_state_array {
int n;
struct posix_user_ace_state aces[];
};
/*
* While processing the NFSv4 ACE, this maintains the partial permissions
* calculated so far: */
struct posix_acl_state {
struct posix_ace_state owner;
struct posix_ace_state group;
struct posix_ace_state other;
struct posix_ace_state everyone;
struct posix_ace_state mask; /* Deny unused in this case */
struct posix_ace_state_array *users;
struct posix_ace_state_array *groups;
};
static int static int
same_who(struct nfs4_ace *a, struct nfs4_ace *b) init_state(struct posix_acl_state *state, int cnt)
{ {
return a->whotype == b->whotype && int alloc;
(a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
memset(state, 0, sizeof(struct posix_acl_state));
/*
* In the worst case, each individual acl could be for a distinct
* named user or group, but we don't no which, so we allocate
* enough space for either:
*/
alloc = sizeof(struct posix_ace_state_array)
+ cnt*sizeof(struct posix_ace_state);
state->users = kzalloc(alloc, GFP_KERNEL);
if (!state->users)
return -ENOMEM;
state->groups = kzalloc(alloc, GFP_KERNEL);
if (!state->groups) {
kfree(state->users);
return -ENOMEM;
}
return 0;
} }
static int static void
complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny, free_state(struct posix_acl_state *state) {
unsigned int flags) kfree(state->users);
{ kfree(state->groups);
int ignore = 0;
if (!(flags & NFS4_ACL_DIR))
ignore |= NFS4_ACE_DELETE_CHILD;
return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
ignore|deny->access_mask) &&
allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
allow->flag == deny->flag &&
same_who(allow, deny);
} }
static inline int static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
struct posix_acl *pacl, struct posix_acl_entry **pace,
unsigned int flags)
{ {
int error = -EINVAL; state->mask.allow |= astate->allow;
struct nfs4_ace *ace, *ace2;
ace = get_next_v4_ace(p, &n4acl->ace_head);
if (ace == NULL)
goto out;
if (ace2type(ace) != ACL_USER_OBJ)
goto out;
error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
if (error < 0)
goto out;
error = -EINVAL;
ace2 = get_next_v4_ace(p, &n4acl->ace_head);
if (ace2 == NULL)
goto out;
if (!complementary_ace_pair(ace, ace2, flags))
goto out;
error = 0;
out:
return error;
} }
static inline int /*
users_from_v4(struct nfs4_acl *n4acl, struct list_head **p, * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
struct nfs4_ace **mask_ace, * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
struct posix_acl *pacl, struct posix_acl_entry **pace, * to traditional read/write/execute permissions.
unsigned int flags) *
{ * It's problematic to reject acls that use certain mode bits, because it
int error = -EINVAL; * places the burden on users to learn the rules about which bits one
struct nfs4_ace *ace, *ace2; * particular server sets, without giving the user a lot of help--we return an
* error that could mean any number of different things. To make matters
* worse, the problematic bits might be introduced by some application that's
* automatically mapping from some other acl model.
*
* So wherever possible we accept anything, possibly erring on the side of
* denying more permissions than necessary.
*
* However we do reject *explicit* DENY's of a few bits representing
* permissions we could never deny:
*/
ace = get_next_v4_ace(p, &n4acl->ace_head); static inline int check_deny(u32 mask, int isowner)
if (ace == NULL) {
goto out; if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
while (ace2type(ace) == ACL_USER) { return -EINVAL;
if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) if (!isowner)
goto out; return 0;
if (*mask_ace && if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) return -EINVAL;
goto out; return 0;
*mask_ace = ace;
ace = get_next_v4_ace(p, &n4acl->ace_head);
if (ace == NULL)
goto out;
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
goto out;
error = write_pace(ace, pacl, pace, ACL_USER, flags);
if (error < 0)
goto out;
error = -EINVAL;
ace2 = get_next_v4_ace(p, &n4acl->ace_head);
if (ace2 == NULL)
goto out;
if (!complementary_ace_pair(ace, ace2, flags))
goto out;
if ((*mask_ace)->flag != ace2->flag ||
!same_who(*mask_ace, ace2))
goto out;
ace = get_next_v4_ace(p, &n4acl->ace_head);
if (ace == NULL)
goto out;
}
error = 0;
out:
return error;
} }
static inline int static struct posix_acl *
group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p, posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
struct nfs4_ace **mask_ace,
struct posix_acl *pacl, struct posix_acl_entry **pace,
unsigned int flags)
{ {
int error = -EINVAL; struct posix_acl_entry *pace;
struct nfs4_ace *ace, *ace2; struct posix_acl *pacl;
struct ace_container *ac; int nace;
struct list_head group_l; int i, error = 0;
INIT_LIST_HEAD(&group_l);
ace = list_entry(*p, struct nfs4_ace, l_ace);
/* group owner (mask and allow aces) */
if (pacl->a_count != 3) { nace = 4 + state->users->n + state->groups->n;
/* then the group owner should be preceded by mask */ pacl = posix_acl_alloc(nace, GFP_KERNEL);
if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) if (!pacl)
goto out; return ERR_PTR(-ENOMEM);
if (*mask_ace &&
!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
goto out;
*mask_ace = ace;
ace = get_next_v4_ace(p, &n4acl->ace_head);
if (ace == NULL)
goto out;
if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace)) pace = pacl->a_entries;
goto out; pace->e_tag = ACL_USER_OBJ;
error = check_deny(state->owner.deny, 1);
if (error)
goto out_err;
low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
pace->e_id = ACL_UNDEFINED_ID;
for (i=0; i < state->users->n; i++) {
pace++;
pace->e_tag = ACL_USER;
error = check_deny(state->users->aces[i].perms.deny, 0);
if (error)
goto out_err;
low_mode_from_nfs4(state->users->aces[i].perms.allow,
&pace->e_perm, flags);
pace->e_id = state->users->aces[i].uid;
add_to_mask(state, &state->users->aces[i].perms);
} }
if (ace2type(ace) != ACL_GROUP_OBJ) pace++;
goto out; pace->e_tag = ACL_GROUP_OBJ;
error = check_deny(state->group.deny, 0);
ac = kmalloc(sizeof(*ac), GFP_KERNEL); if (error)
error = -ENOMEM; goto out_err;
if (ac == NULL) low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
goto out; pace->e_id = ACL_UNDEFINED_ID;
ac->ace = ace; add_to_mask(state, &state->group);
list_add_tail(&ac->ace_l, &group_l);
for (i=0; i < state->groups->n; i++) {
error = -EINVAL; pace++;
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) pace->e_tag = ACL_GROUP;
goto out; error = check_deny(state->groups->aces[i].perms.deny, 0);
if (error)
error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags); goto out_err;
if (error < 0) low_mode_from_nfs4(state->groups->aces[i].perms.allow,
goto out; &pace->e_perm, flags);
pace->e_id = state->groups->aces[i].uid;
error = -EINVAL; add_to_mask(state, &state->groups->aces[i].perms);
ace = get_next_v4_ace(p, &n4acl->ace_head); }
if (ace == NULL)
goto out;
/* groups (mask and allow aces) */
while (ace2type(ace) == ACL_GROUP) {
if (*mask_ace == NULL)
goto out;
if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
goto out;
*mask_ace = ace;
ace = get_next_v4_ace(p, &n4acl->ace_head); pace++;
if (ace == NULL) pace->e_tag = ACL_MASK;
goto out; low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
ac = kmalloc(sizeof(*ac), GFP_KERNEL); pace->e_id = ACL_UNDEFINED_ID;
error = -ENOMEM;
if (ac == NULL)
goto out;
error = -EINVAL;
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
!same_who(ace, *mask_ace))
goto out;
ac->ace = ace; pace++;
list_add_tail(&ac->ace_l, &group_l); pace->e_tag = ACL_OTHER;
error = check_deny(state->other.deny, 0);
if (error)
goto out_err;
low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
pace->e_id = ACL_UNDEFINED_ID;
error = write_pace(ace, pacl, pace, ACL_GROUP, flags); return pacl;
if (error < 0) out_err:
goto out; posix_acl_release(pacl);
error = -EINVAL; return ERR_PTR(error);
ace = get_next_v4_ace(p, &n4acl->ace_head); }
if (ace == NULL)
goto out;
}
/* group owner (deny ace) */ static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
{
/* Allow all bits in the mask not already denied: */
astate->allow |= mask & ~astate->deny;
}
if (ace2type(ace) != ACL_GROUP_OBJ) static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
goto out; {
ac = list_entry(group_l.next, struct ace_container, ace_l); /* Deny all bits in the mask not already allowed: */
ace2 = ac->ace; astate->deny |= mask & ~astate->allow;
if (!complementary_ace_pair(ace2, ace, flags)) }
goto out;
list_del(group_l.next);
kfree(ac);
/* groups (deny aces) */ static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
{
int i;
while (!list_empty(&group_l)) { for (i = 0; i < a->n; i++)
ace = get_next_v4_ace(p, &n4acl->ace_head); if (a->aces[i].uid == uid)
if (ace == NULL) return i;
goto out; /* Not found: */
if (ace2type(ace) != ACL_GROUP) a->n++;
goto out; a->aces[i].uid = uid;
ac = list_entry(group_l.next, struct ace_container, ace_l); a->aces[i].perms.allow = state->everyone.allow;
ace2 = ac->ace; a->aces[i].perms.deny = state->everyone.deny;
if (!complementary_ace_pair(ace2, ace, flags))
goto out;
list_del(group_l.next);
kfree(ac);
}
ace = get_next_v4_ace(p, &n4acl->ace_head); return i;
if (ace == NULL)
goto out;
if (ace2type(ace) != ACL_OTHER)
goto out;
error = 0;
out:
while (!list_empty(&group_l)) {
ac = list_entry(group_l.next, struct ace_container, ace_l);
list_del(group_l.next);
kfree(ac);
}
return error;
} }
static inline int static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
struct nfs4_ace **mask_ace,
struct posix_acl *pacl, struct posix_acl_entry **pace,
unsigned int flags)
{ {
int error = -EINVAL; int i;
struct nfs4_ace *ace;
ace = list_entry(*p, struct nfs4_ace, l_ace); for (i=0; i < a->n; i++)
if (pacl->a_count != 3) { deny_bits(&a->aces[i].perms, mask);
if (*mask_ace == NULL)
goto out;
(*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
}
error = 0;
out:
return error;
} }
static inline int static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
struct posix_acl *pacl, struct posix_acl_entry **pace,
unsigned int flags)
{ {
int error = -EINVAL; int i;
struct nfs4_ace *ace, *ace2;
ace = list_entry(*p, struct nfs4_ace, l_ace); for (i=0; i < a->n; i++)
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) allow_bits(&a->aces[i].perms, mask);
goto out;
error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
if (error < 0)
goto out;
error = -EINVAL;
ace2 = get_next_v4_ace(p, &n4acl->ace_head);
if (ace2 == NULL)
goto out;
if (!complementary_ace_pair(ace, ace2, flags))
goto out;
error = 0;
out:
return error;
} }
static int static void process_one_v4_ace(struct posix_acl_state *state,
calculate_posix_ace_count(struct nfs4_acl *n4acl) struct nfs4_ace *ace)
{ {
if (n4acl->naces == 6) /* owner, owner group, and other only */ u32 mask = ace->access_mask;
return 3; int i;
else { /* Otherwise there must be a mask entry. */
/* Also, the remaining entries are for named users and switch (ace2type(ace)) {
* groups, and come in threes (mask, allow, deny): */ case ACL_USER_OBJ:
if (n4acl->naces < 7) if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
return -EINVAL; allow_bits(&state->owner, mask);
if ((n4acl->naces - 7) % 3) } else {
return -EINVAL; deny_bits(&state->owner, mask);
return 4 + (n4acl->naces - 7)/3; }
break;
case ACL_USER:
i = find_uid(state, state->users, ace->who);
if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->users->aces[i].perms, mask);
} else {
deny_bits(&state->users->aces[i].perms, mask);
mask = state->users->aces[i].perms.deny;
deny_bits(&state->owner, mask);
}
break;
case ACL_GROUP_OBJ:
if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->group, mask);
} else {
deny_bits(&state->group, mask);
mask = state->group.deny;
deny_bits(&state->owner, mask);
deny_bits(&state->everyone, mask);
deny_bits_array(state->users, mask);
deny_bits_array(state->groups, mask);
}
break;
case ACL_GROUP:
i = find_uid(state, state->groups, ace->who);
if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->groups->aces[i].perms, mask);
} else {
deny_bits(&state->groups->aces[i].perms, mask);
mask = state->groups->aces[i].perms.deny;
deny_bits(&state->owner, mask);
deny_bits(&state->group, mask);
deny_bits(&state->everyone, mask);
deny_bits_array(state->users, mask);
deny_bits_array(state->groups, mask);
}
break;
case ACL_OTHER:
if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->owner, mask);
allow_bits(&state->group, mask);
allow_bits(&state->other, mask);
allow_bits(&state->everyone, mask);
allow_bits_array(state->users, mask);
allow_bits_array(state->groups, mask);
} else {
deny_bits(&state->owner, mask);
deny_bits(&state->group, mask);
deny_bits(&state->other, mask);
deny_bits(&state->everyone, mask);
deny_bits_array(state->users, mask);
deny_bits_array(state->groups, mask);
}
} }
} }
static struct posix_acl * static struct posix_acl *
_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
{ {
struct posix_acl_state state;
struct posix_acl *pacl; struct posix_acl *pacl;
int error = -EINVAL, nace = 0; struct nfs4_ace *ace;
struct list_head *p; int ret;
struct nfs4_ace *mask_ace = NULL;
struct posix_acl_entry *pace;
nace = calculate_posix_ace_count(n4acl);
if (nace < 0)
goto out_err;
pacl = posix_acl_alloc(nace, GFP_KERNEL);
error = -ENOMEM;
if (pacl == NULL)
goto out_err;
pace = &pacl->a_entries[0];
p = &n4acl->ace_head;
error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
if (error)
goto out_acl;
error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
if (error)
goto out_acl;
error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace, ret = init_state(&state, n4acl->naces);
flags); if (ret)
if (error) return ERR_PTR(ret);
goto out_acl;
error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); list_for_each_entry(ace, &n4acl->ace_head, l_ace)
if (error) process_one_v4_ace(&state, ace);
goto out_acl;
error = other_from_v4(n4acl, &p, pacl, &pace, flags);
if (error)
goto out_acl;
error = -EINVAL; pacl = posix_state_to_acl(&state, flags);
if (p->next != &n4acl->ace_head)
goto out_acl;
if (pace != pacl->a_entries + pacl->a_count)
goto out_acl;
sort_pacl(pacl); free_state(&state);
return pacl; if (!IS_ERR(pacl))
out_acl: sort_pacl(pacl);
posix_acl_release(pacl);
out_err:
pacl = ERR_PTR(error);
return pacl; return pacl;
} }
...@@ -785,6 +717,10 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) ...@@ -785,6 +717,10 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
list_for_each_safe(h, n, &acl->ace_head) { list_for_each_safe(h, n, &acl->ace_head) {
ace = list_entry(h, struct nfs4_ace, l_ace); ace = list_entry(h, struct nfs4_ace, l_ace);
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
return -EINVAL;
if ((ace->flag & NFS4_INHERITANCE_FLAGS) if ((ace->flag & NFS4_INHERITANCE_FLAGS)
!= NFS4_INHERITANCE_FLAGS) != NFS4_INHERITANCE_FLAGS)
continue; continue;
...@@ -930,23 +866,6 @@ nfs4_acl_write_who(int who, char *p) ...@@ -930,23 +866,6 @@ nfs4_acl_write_who(int who, char *p)
return -1; return -1;
} }
static inline int
match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
{
switch (ace->whotype) {
case NFS4_ACL_WHO_NAMED:
return who == ace->who;
case NFS4_ACL_WHO_OWNER:
return who == owner;
case NFS4_ACL_WHO_GROUP:
return who == group;
case NFS4_ACL_WHO_EVERYONE:
return 1;
default:
return 0;
}
}
EXPORT_SYMBOL(nfs4_acl_new); EXPORT_SYMBOL(nfs4_acl_new);
EXPORT_SYMBOL(nfs4_acl_free); EXPORT_SYMBOL(nfs4_acl_free);
EXPORT_SYMBOL(nfs4_acl_add_ace); EXPORT_SYMBOL(nfs4_acl_add_ace);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment