diff options
author | J.Bruce Fields <bfields@fieldses.org> | 2006-10-04 05:16:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 10:55:20 -0400 |
commit | 09229edb68a3961db54174a2725055bd1589b4b8 (patch) | |
tree | 44876575189a69021d961345ef9bc75ddffaac1e /fs/nfsd | |
parent | d0ebd9c0e71d20ea8c2b4a071d2a2b4878ef07d6 (diff) |
[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: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4acl.c | 627 |
1 files changed, 273 insertions, 354 deletions
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index edb107e61b91..f2f66b3da7ac 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -96,24 +96,26 @@ deny_mask(u32 allow_mask, unsigned int flags) | |||
96 | /* XXX: modify functions to return NFS errors; they're only ever | 96 | /* XXX: modify functions to return NFS errors; they're only ever |
97 | * used by nfs code, after all.... */ | 97 | * used by nfs code, after all.... */ |
98 | 98 | ||
99 | static int | 99 | /* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the |
100 | mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) | 100 | * side of being more restrictive, so the mode bit mapping below is |
101 | * pessimistic. An optimistic version would be needed to handle DENY's, | ||
102 | * but we espect to coalesce all ALLOWs and DENYs before mapping to mode | ||
103 | * bits. */ | ||
104 | |||
105 | static void | ||
106 | low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) | ||
101 | { | 107 | { |
102 | u32 ignore = 0; | 108 | u32 write_mode = NFS4_WRITE_MODE; |
103 | 109 | ||
104 | if (!(flags & NFS4_ACL_DIR)) | 110 | if (flags & NFS4_ACL_DIR) |
105 | ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */ | 111 | write_mode |= NFS4_ACE_DELETE_CHILD; |
106 | perm |= ignore; | ||
107 | *mode = 0; | 112 | *mode = 0; |
108 | if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) | 113 | if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) |
109 | *mode |= ACL_READ; | 114 | *mode |= ACL_READ; |
110 | if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE) | 115 | if ((perm & write_mode) == write_mode) |
111 | *mode |= ACL_WRITE; | 116 | *mode |= ACL_WRITE; |
112 | if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) | 117 | if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) |
113 | *mode |= ACL_EXECUTE; | 118 | *mode |= ACL_EXECUTE; |
114 | if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags))) | ||
115 | return -EINVAL; | ||
116 | return 0; | ||
117 | } | 119 | } |
118 | 120 | ||
119 | struct ace_container { | 121 | struct ace_container { |
@@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl) | |||
338 | return; | 340 | return; |
339 | } | 341 | } |
340 | 342 | ||
341 | static int | ||
342 | write_pace(struct nfs4_ace *ace, struct posix_acl *pacl, | ||
343 | struct posix_acl_entry **pace, short tag, unsigned int flags) | ||
344 | { | ||
345 | struct posix_acl_entry *this = *pace; | ||
346 | |||
347 | if (*pace == pacl->a_entries + pacl->a_count) | ||
348 | return -EINVAL; /* fell off the end */ | ||
349 | (*pace)++; | ||
350 | this->e_tag = tag; | ||
351 | if (tag == ACL_USER_OBJ) | ||
352 | flags |= NFS4_ACL_OWNER; | ||
353 | if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags)) | ||
354 | return -EINVAL; | ||
355 | this->e_id = (tag == ACL_USER || tag == ACL_GROUP ? | ||
356 | ace->who : ACL_UNDEFINED_ID); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static struct nfs4_ace * | ||
361 | get_next_v4_ace(struct list_head **p, struct list_head *head) | ||
362 | { | ||
363 | struct nfs4_ace *ace; | ||
364 | |||
365 | *p = (*p)->next; | ||
366 | if (*p == head) | ||
367 | return NULL; | ||
368 | ace = list_entry(*p, struct nfs4_ace, l_ace); | ||
369 | |||
370 | return ace; | ||
371 | } | ||
372 | |||
373 | int | 343 | int |
374 | nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, | 344 | nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, |
375 | struct posix_acl **dpacl, unsigned int flags) | 345 | struct posix_acl **dpacl, unsigned int flags) |
@@ -429,349 +399,311 @@ out: | |||
429 | return error; | 399 | return error; |
430 | } | 400 | } |
431 | 401 | ||
402 | /* | ||
403 | * While processing the NFSv4 ACE, this maintains bitmasks representing | ||
404 | * which permission bits have been allowed and which denied to a given | ||
405 | * entity: */ | ||
406 | struct posix_ace_state { | ||
407 | u32 allow; | ||
408 | u32 deny; | ||
409 | }; | ||
410 | |||
411 | struct posix_user_ace_state { | ||
412 | uid_t uid; | ||
413 | struct posix_ace_state perms; | ||
414 | }; | ||
415 | |||
416 | struct posix_ace_state_array { | ||
417 | int n; | ||
418 | struct posix_user_ace_state aces[]; | ||
419 | }; | ||
420 | |||
421 | /* | ||
422 | * While processing the NFSv4 ACE, this maintains the partial permissions | ||
423 | * calculated so far: */ | ||
424 | |||
425 | struct posix_acl_state { | ||
426 | struct posix_ace_state owner; | ||
427 | struct posix_ace_state group; | ||
428 | struct posix_ace_state other; | ||
429 | struct posix_ace_state everyone; | ||
430 | struct posix_ace_state mask; /* Deny unused in this case */ | ||
431 | struct posix_ace_state_array *users; | ||
432 | struct posix_ace_state_array *groups; | ||
433 | }; | ||
434 | |||
432 | static int | 435 | static int |
433 | same_who(struct nfs4_ace *a, struct nfs4_ace *b) | 436 | init_state(struct posix_acl_state *state, int cnt) |
434 | { | 437 | { |
435 | return a->whotype == b->whotype && | 438 | int alloc; |
436 | (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who); | 439 | |
440 | memset(state, 0, sizeof(struct posix_acl_state)); | ||
441 | /* | ||
442 | * In the worst case, each individual acl could be for a distinct | ||
443 | * named user or group, but we don't no which, so we allocate | ||
444 | * enough space for either: | ||
445 | */ | ||
446 | alloc = sizeof(struct posix_ace_state_array) | ||
447 | + cnt*sizeof(struct posix_ace_state); | ||
448 | state->users = kzalloc(alloc, GFP_KERNEL); | ||
449 | if (!state->users) | ||
450 | return -ENOMEM; | ||
451 | state->groups = kzalloc(alloc, GFP_KERNEL); | ||
452 | if (!state->groups) { | ||
453 | kfree(state->users); | ||
454 | return -ENOMEM; | ||
455 | } | ||
456 | return 0; | ||
437 | } | 457 | } |
438 | 458 | ||
439 | static int | 459 | static void |
440 | complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny, | 460 | free_state(struct posix_acl_state *state) { |
441 | unsigned int flags) | 461 | kfree(state->users); |
442 | { | 462 | kfree(state->groups); |
443 | int ignore = 0; | ||
444 | if (!(flags & NFS4_ACL_DIR)) | ||
445 | ignore |= NFS4_ACE_DELETE_CHILD; | ||
446 | return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags), | ||
447 | ignore|deny->access_mask) && | ||
448 | allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && | ||
449 | deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE && | ||
450 | allow->flag == deny->flag && | ||
451 | same_who(allow, deny); | ||
452 | } | 463 | } |
453 | 464 | ||
454 | static inline int | 465 | static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate) |
455 | user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p, | ||
456 | struct posix_acl *pacl, struct posix_acl_entry **pace, | ||
457 | unsigned int flags) | ||
458 | { | 466 | { |
459 | int error = -EINVAL; | 467 | state->mask.allow |= astate->allow; |
460 | struct nfs4_ace *ace, *ace2; | ||
461 | |||
462 | ace = get_next_v4_ace(p, &n4acl->ace_head); | ||
463 | if (ace == NULL) | ||
464 | goto out; | ||
465 | if (ace2type(ace) != ACL_USER_OBJ) | ||
466 | goto out; | ||
467 | error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags); | ||
468 | if (error < 0) | ||
469 | goto out; | ||
470 | error = -EINVAL; | ||
471 | ace2 = get_next_v4_ace(p, &n4acl->ace_head); | ||
472 | if (ace2 == NULL) | ||
473 | goto out; | ||
474 | if (!complementary_ace_pair(ace, ace2, flags)) | ||
475 | goto out; | ||
476 | error = 0; | ||
477 | out: | ||
478 | return error; | ||
479 | } | 468 | } |
480 | 469 | ||
481 | static inline int | 470 | /* |
482 | users_from_v4(struct nfs4_acl *n4acl, struct list_head **p, | 471 | * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS, |
483 | struct nfs4_ace **mask_ace, | 472 | * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate |
484 | struct posix_acl *pacl, struct posix_acl_entry **pace, | 473 | * to traditional read/write/execute permissions. |
485 | unsigned int flags) | 474 | * |
486 | { | 475 | * It's problematic to reject acls that use certain mode bits, because it |
487 | int error = -EINVAL; | 476 | * places the burden on users to learn the rules about which bits one |
488 | struct nfs4_ace *ace, *ace2; | 477 | * particular server sets, without giving the user a lot of help--we return an |
478 | * error that could mean any number of different things. To make matters | ||
479 | * worse, the problematic bits might be introduced by some application that's | ||
480 | * automatically mapping from some other acl model. | ||
481 | * | ||
482 | * So wherever possible we accept anything, possibly erring on the side of | ||
483 | * denying more permissions than necessary. | ||
484 | * | ||
485 | * However we do reject *explicit* DENY's of a few bits representing | ||
486 | * permissions we could never deny: | ||
487 | */ | ||
489 | 488 | ||
490 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 489 | static inline int check_deny(u32 mask, int isowner) |
491 | if (ace == NULL) | 490 | { |
492 | goto out; | 491 | if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL)) |
493 | while (ace2type(ace) == ACL_USER) { | 492 | return -EINVAL; |
494 | if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) | 493 | if (!isowner) |
495 | goto out; | 494 | return 0; |
496 | if (*mask_ace && | 495 | if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)) |
497 | !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) | 496 | return -EINVAL; |
498 | goto out; | 497 | return 0; |
499 | *mask_ace = ace; | ||
500 | ace = get_next_v4_ace(p, &n4acl->ace_head); | ||
501 | if (ace == NULL) | ||
502 | goto out; | ||
503 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) | ||
504 | goto out; | ||
505 | error = write_pace(ace, pacl, pace, ACL_USER, flags); | ||
506 | if (error < 0) | ||
507 | goto out; | ||
508 | error = -EINVAL; | ||
509 | ace2 = get_next_v4_ace(p, &n4acl->ace_head); | ||
510 | if (ace2 == NULL) | ||
511 | goto out; | ||
512 | if (!complementary_ace_pair(ace, ace2, flags)) | ||
513 | goto out; | ||
514 | if ((*mask_ace)->flag != ace2->flag || | ||
515 | !same_who(*mask_ace, ace2)) | ||
516 | goto out; | ||
517 | ace = get_next_v4_ace(p, &n4acl->ace_head); | ||
518 | if (ace == NULL) | ||
519 | goto out; | ||
520 | } | ||
521 | error = 0; | ||
522 | out: | ||
523 | return error; | ||
524 | } | 498 | } |
525 | 499 | ||
526 | static inline int | 500 | static struct posix_acl * |
527 | group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p, | 501 | posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) |
528 | struct nfs4_ace **mask_ace, | ||
529 | struct posix_acl *pacl, struct posix_acl_entry **pace, | ||
530 | unsigned int flags) | ||
531 | { | 502 | { |
532 | int error = -EINVAL; | 503 | struct posix_acl_entry *pace; |
533 | struct nfs4_ace *ace, *ace2; | 504 | struct posix_acl *pacl; |
534 | struct ace_container *ac; | 505 | int nace; |
535 | struct list_head group_l; | 506 | int i, error = 0; |
536 | |||
537 | INIT_LIST_HEAD(&group_l); | ||
538 | ace = list_entry(*p, struct nfs4_ace, l_ace); | ||
539 | |||
540 | /* group owner (mask and allow aces) */ | ||
541 | 507 | ||
542 | if (pacl->a_count != 3) { | 508 | nace = 4 + state->users->n + state->groups->n; |
543 | /* then the group owner should be preceded by mask */ | 509 | pacl = posix_acl_alloc(nace, GFP_KERNEL); |
544 | if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) | 510 | if (!pacl) |
545 | goto out; | 511 | return ERR_PTR(-ENOMEM); |
546 | if (*mask_ace && | ||
547 | !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) | ||
548 | goto out; | ||
549 | *mask_ace = ace; | ||
550 | ace = get_next_v4_ace(p, &n4acl->ace_head); | ||
551 | if (ace == NULL) | ||
552 | goto out; | ||
553 | 512 | ||
554 | if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace)) | 513 | pace = pacl->a_entries; |
555 | goto out; | 514 | pace->e_tag = ACL_USER_OBJ; |
515 | error = check_deny(state->owner.deny, 1); | ||
516 | if (error) | ||
517 | goto out_err; | ||
518 | low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags); | ||
519 | pace->e_id = ACL_UNDEFINED_ID; | ||
520 | |||
521 | for (i=0; i < state->users->n; i++) { | ||
522 | pace++; | ||
523 | pace->e_tag = ACL_USER; | ||
524 | error = check_deny(state->users->aces[i].perms.deny, 0); | ||
525 | if (error) | ||
526 | goto out_err; | ||
527 | low_mode_from_nfs4(state->users->aces[i].perms.allow, | ||
528 | &pace->e_perm, flags); | ||
529 | pace->e_id = state->users->aces[i].uid; | ||
530 | add_to_mask(state, &state->users->aces[i].perms); | ||
556 | } | 531 | } |
557 | 532 | ||
558 | if (ace2type(ace) != ACL_GROUP_OBJ) | 533 | pace++; |
559 | goto out; | 534 | pace->e_tag = ACL_GROUP_OBJ; |
560 | 535 | error = check_deny(state->group.deny, 0); | |
561 | ac = kmalloc(sizeof(*ac), GFP_KERNEL); | 536 | if (error) |
562 | error = -ENOMEM; | 537 | goto out_err; |
563 | if (ac == NULL) | 538 | low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags); |
564 | goto out; | 539 | pace->e_id = ACL_UNDEFINED_ID; |
565 | ac->ace = ace; | 540 | add_to_mask(state, &state->group); |
566 | list_add_tail(&ac->ace_l, &group_l); | 541 | |
567 | 542 | for (i=0; i < state->groups->n; i++) { | |
568 | error = -EINVAL; | 543 | pace++; |
569 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) | 544 | pace->e_tag = ACL_GROUP; |
570 | goto out; | 545 | error = check_deny(state->groups->aces[i].perms.deny, 0); |
571 | 546 | if (error) | |
572 | error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags); | 547 | goto out_err; |
573 | if (error < 0) | 548 | low_mode_from_nfs4(state->groups->aces[i].perms.allow, |
574 | goto out; | 549 | &pace->e_perm, flags); |
575 | 550 | pace->e_id = state->groups->aces[i].uid; | |
576 | error = -EINVAL; | 551 | add_to_mask(state, &state->groups->aces[i].perms); |
577 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 552 | } |
578 | if (ace == NULL) | ||
579 | goto out; | ||
580 | |||
581 | /* groups (mask and allow aces) */ | ||
582 | |||
583 | while (ace2type(ace) == ACL_GROUP) { | ||
584 | if (*mask_ace == NULL) | ||
585 | goto out; | ||
586 | |||
587 | if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE || | ||
588 | !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask)) | ||
589 | goto out; | ||
590 | *mask_ace = ace; | ||
591 | 553 | ||
592 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 554 | pace++; |
593 | if (ace == NULL) | 555 | pace->e_tag = ACL_MASK; |
594 | goto out; | 556 | low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags); |
595 | ac = kmalloc(sizeof(*ac), GFP_KERNEL); | 557 | pace->e_id = ACL_UNDEFINED_ID; |
596 | error = -ENOMEM; | ||
597 | if (ac == NULL) | ||
598 | goto out; | ||
599 | error = -EINVAL; | ||
600 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE || | ||
601 | !same_who(ace, *mask_ace)) | ||
602 | goto out; | ||
603 | 558 | ||
604 | ac->ace = ace; | 559 | pace++; |
605 | list_add_tail(&ac->ace_l, &group_l); | 560 | pace->e_tag = ACL_OTHER; |
561 | error = check_deny(state->other.deny, 0); | ||
562 | if (error) | ||
563 | goto out_err; | ||
564 | low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags); | ||
565 | pace->e_id = ACL_UNDEFINED_ID; | ||
606 | 566 | ||
607 | error = write_pace(ace, pacl, pace, ACL_GROUP, flags); | 567 | return pacl; |
608 | if (error < 0) | 568 | out_err: |
609 | goto out; | 569 | posix_acl_release(pacl); |
610 | error = -EINVAL; | 570 | return ERR_PTR(error); |
611 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 571 | } |
612 | if (ace == NULL) | ||
613 | goto out; | ||
614 | } | ||
615 | 572 | ||
616 | /* group owner (deny ace) */ | 573 | static inline void allow_bits(struct posix_ace_state *astate, u32 mask) |
574 | { | ||
575 | /* Allow all bits in the mask not already denied: */ | ||
576 | astate->allow |= mask & ~astate->deny; | ||
577 | } | ||
617 | 578 | ||
618 | if (ace2type(ace) != ACL_GROUP_OBJ) | 579 | static inline void deny_bits(struct posix_ace_state *astate, u32 mask) |
619 | goto out; | 580 | { |
620 | ac = list_entry(group_l.next, struct ace_container, ace_l); | 581 | /* Deny all bits in the mask not already allowed: */ |
621 | ace2 = ac->ace; | 582 | astate->deny |= mask & ~astate->allow; |
622 | if (!complementary_ace_pair(ace2, ace, flags)) | 583 | } |
623 | goto out; | ||
624 | list_del(group_l.next); | ||
625 | kfree(ac); | ||
626 | 584 | ||
627 | /* groups (deny aces) */ | 585 | static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid) |
586 | { | ||
587 | int i; | ||
628 | 588 | ||
629 | while (!list_empty(&group_l)) { | 589 | for (i = 0; i < a->n; i++) |
630 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 590 | if (a->aces[i].uid == uid) |
631 | if (ace == NULL) | 591 | return i; |
632 | goto out; | 592 | /* Not found: */ |
633 | if (ace2type(ace) != ACL_GROUP) | 593 | a->n++; |
634 | goto out; | 594 | a->aces[i].uid = uid; |
635 | ac = list_entry(group_l.next, struct ace_container, ace_l); | 595 | a->aces[i].perms.allow = state->everyone.allow; |
636 | ace2 = ac->ace; | 596 | a->aces[i].perms.deny = state->everyone.deny; |
637 | if (!complementary_ace_pair(ace2, ace, flags)) | ||
638 | goto out; | ||
639 | list_del(group_l.next); | ||
640 | kfree(ac); | ||
641 | } | ||
642 | 597 | ||
643 | ace = get_next_v4_ace(p, &n4acl->ace_head); | 598 | return i; |
644 | if (ace == NULL) | ||
645 | goto out; | ||
646 | if (ace2type(ace) != ACL_OTHER) | ||
647 | goto out; | ||
648 | error = 0; | ||
649 | out: | ||
650 | while (!list_empty(&group_l)) { | ||
651 | ac = list_entry(group_l.next, struct ace_container, ace_l); | ||
652 | list_del(group_l.next); | ||
653 | kfree(ac); | ||
654 | } | ||
655 | return error; | ||
656 | } | 599 | } |
657 | 600 | ||
658 | static inline int | 601 | static void deny_bits_array(struct posix_ace_state_array *a, u32 mask) |
659 | mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p, | ||
660 | struct nfs4_ace **mask_ace, | ||
661 | struct posix_acl *pacl, struct posix_acl_entry **pace, | ||
662 | unsigned int flags) | ||
663 | { | 602 | { |
664 | int error = -EINVAL; | 603 | int i; |
665 | struct nfs4_ace *ace; | ||
666 | 604 | ||
667 | ace = list_entry(*p, struct nfs4_ace, l_ace); | 605 | for (i=0; i < a->n; i++) |
668 | if (pacl->a_count != 3) { | 606 | deny_bits(&a->aces[i].perms, mask); |
669 | if (*mask_ace == NULL) | ||
670 | goto out; | ||
671 | (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags); | ||
672 | write_pace(*mask_ace, pacl, pace, ACL_MASK, flags); | ||
673 | } | ||
674 | error = 0; | ||
675 | out: | ||
676 | return error; | ||
677 | } | 607 | } |
678 | 608 | ||
679 | static inline int | 609 | static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) |
680 | other_from_v4(struct nfs4_acl *n4acl, struct list_head **p, | ||
681 | struct posix_acl *pacl, struct posix_acl_entry **pace, | ||
682 | unsigned int flags) | ||
683 | { | 610 | { |
684 | int error = -EINVAL; | 611 | int i; |
685 | struct nfs4_ace *ace, *ace2; | ||
686 | 612 | ||
687 | ace = list_entry(*p, struct nfs4_ace, l_ace); | 613 | for (i=0; i < a->n; i++) |
688 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) | 614 | allow_bits(&a->aces[i].perms, mask); |
689 | goto out; | ||
690 | error = write_pace(ace, pacl, pace, ACL_OTHER, flags); | ||
691 | if (error < 0) | ||
692 | goto out; | ||
693 | error = -EINVAL; | ||
694 | ace2 = get_next_v4_ace(p, &n4acl->ace_head); | ||
695 | if (ace2 == NULL) | ||
696 | goto out; | ||
697 | if (!complementary_ace_pair(ace, ace2, flags)) | ||
698 | goto out; | ||
699 | error = 0; | ||
700 | out: | ||
701 | return error; | ||
702 | } | 615 | } |
703 | 616 | ||
704 | static int | 617 | static void process_one_v4_ace(struct posix_acl_state *state, |
705 | calculate_posix_ace_count(struct nfs4_acl *n4acl) | 618 | struct nfs4_ace *ace) |
706 | { | 619 | { |
707 | if (n4acl->naces == 6) /* owner, owner group, and other only */ | 620 | u32 mask = ace->access_mask; |
708 | return 3; | 621 | int i; |
709 | else { /* Otherwise there must be a mask entry. */ | 622 | |
710 | /* Also, the remaining entries are for named users and | 623 | switch (ace2type(ace)) { |
711 | * groups, and come in threes (mask, allow, deny): */ | 624 | case ACL_USER_OBJ: |
712 | if (n4acl->naces < 7) | 625 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { |
713 | return -EINVAL; | 626 | allow_bits(&state->owner, mask); |
714 | if ((n4acl->naces - 7) % 3) | 627 | } else { |
715 | return -EINVAL; | 628 | deny_bits(&state->owner, mask); |
716 | return 4 + (n4acl->naces - 7)/3; | 629 | } |
630 | break; | ||
631 | case ACL_USER: | ||
632 | i = find_uid(state, state->users, ace->who); | ||
633 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | ||
634 | allow_bits(&state->users->aces[i].perms, mask); | ||
635 | } else { | ||
636 | deny_bits(&state->users->aces[i].perms, mask); | ||
637 | mask = state->users->aces[i].perms.deny; | ||
638 | deny_bits(&state->owner, mask); | ||
639 | } | ||
640 | break; | ||
641 | case ACL_GROUP_OBJ: | ||
642 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | ||
643 | allow_bits(&state->group, mask); | ||
644 | } else { | ||
645 | deny_bits(&state->group, mask); | ||
646 | mask = state->group.deny; | ||
647 | deny_bits(&state->owner, mask); | ||
648 | deny_bits(&state->everyone, mask); | ||
649 | deny_bits_array(state->users, mask); | ||
650 | deny_bits_array(state->groups, mask); | ||
651 | } | ||
652 | break; | ||
653 | case ACL_GROUP: | ||
654 | i = find_uid(state, state->groups, ace->who); | ||
655 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | ||
656 | allow_bits(&state->groups->aces[i].perms, mask); | ||
657 | } else { | ||
658 | deny_bits(&state->groups->aces[i].perms, mask); | ||
659 | mask = state->groups->aces[i].perms.deny; | ||
660 | deny_bits(&state->owner, mask); | ||
661 | deny_bits(&state->group, mask); | ||
662 | deny_bits(&state->everyone, mask); | ||
663 | deny_bits_array(state->users, mask); | ||
664 | deny_bits_array(state->groups, mask); | ||
665 | } | ||
666 | break; | ||
667 | case ACL_OTHER: | ||
668 | if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { | ||
669 | allow_bits(&state->owner, mask); | ||
670 | allow_bits(&state->group, mask); | ||
671 | allow_bits(&state->other, mask); | ||
672 | allow_bits(&state->everyone, mask); | ||
673 | allow_bits_array(state->users, mask); | ||
674 | allow_bits_array(state->groups, mask); | ||
675 | } else { | ||
676 | deny_bits(&state->owner, mask); | ||
677 | deny_bits(&state->group, mask); | ||
678 | deny_bits(&state->other, mask); | ||
679 | deny_bits(&state->everyone, mask); | ||
680 | deny_bits_array(state->users, mask); | ||
681 | deny_bits_array(state->groups, mask); | ||
682 | } | ||
717 | } | 683 | } |
718 | } | 684 | } |
719 | 685 | ||
720 | |||
721 | static struct posix_acl * | 686 | static struct posix_acl * |
722 | _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) | 687 | _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags) |
723 | { | 688 | { |
689 | struct posix_acl_state state; | ||
724 | struct posix_acl *pacl; | 690 | struct posix_acl *pacl; |
725 | int error = -EINVAL, nace = 0; | 691 | struct nfs4_ace *ace; |
726 | struct list_head *p; | 692 | int ret; |
727 | struct nfs4_ace *mask_ace = NULL; | ||
728 | struct posix_acl_entry *pace; | ||
729 | |||
730 | nace = calculate_posix_ace_count(n4acl); | ||
731 | if (nace < 0) | ||
732 | goto out_err; | ||
733 | |||
734 | pacl = posix_acl_alloc(nace, GFP_KERNEL); | ||
735 | error = -ENOMEM; | ||
736 | if (pacl == NULL) | ||
737 | goto out_err; | ||
738 | |||
739 | pace = &pacl->a_entries[0]; | ||
740 | p = &n4acl->ace_head; | ||
741 | |||
742 | error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags); | ||
743 | if (error) | ||
744 | goto out_acl; | ||
745 | |||
746 | error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); | ||
747 | if (error) | ||
748 | goto out_acl; | ||
749 | 693 | ||
750 | error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace, | 694 | ret = init_state(&state, n4acl->naces); |
751 | flags); | 695 | if (ret) |
752 | if (error) | 696 | return ERR_PTR(ret); |
753 | goto out_acl; | ||
754 | 697 | ||
755 | error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags); | 698 | list_for_each_entry(ace, &n4acl->ace_head, l_ace) |
756 | if (error) | 699 | process_one_v4_ace(&state, ace); |
757 | goto out_acl; | ||
758 | error = other_from_v4(n4acl, &p, pacl, &pace, flags); | ||
759 | if (error) | ||
760 | goto out_acl; | ||
761 | 700 | ||
762 | error = -EINVAL; | 701 | pacl = posix_state_to_acl(&state, flags); |
763 | if (p->next != &n4acl->ace_head) | ||
764 | goto out_acl; | ||
765 | if (pace != pacl->a_entries + pacl->a_count) | ||
766 | goto out_acl; | ||
767 | 702 | ||
768 | sort_pacl(pacl); | 703 | free_state(&state); |
769 | 704 | ||
770 | return pacl; | 705 | if (!IS_ERR(pacl)) |
771 | out_acl: | 706 | sort_pacl(pacl); |
772 | posix_acl_release(pacl); | ||
773 | out_err: | ||
774 | pacl = ERR_PTR(error); | ||
775 | return pacl; | 707 | return pacl; |
776 | } | 708 | } |
777 | 709 | ||
@@ -785,6 +717,10 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) | |||
785 | list_for_each_safe(h, n, &acl->ace_head) { | 717 | list_for_each_safe(h, n, &acl->ace_head) { |
786 | ace = list_entry(h, struct nfs4_ace, l_ace); | 718 | ace = list_entry(h, struct nfs4_ace, l_ace); |
787 | 719 | ||
720 | if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && | ||
721 | ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) | ||
722 | return -EINVAL; | ||
723 | |||
788 | if ((ace->flag & NFS4_INHERITANCE_FLAGS) | 724 | if ((ace->flag & NFS4_INHERITANCE_FLAGS) |
789 | != NFS4_INHERITANCE_FLAGS) | 725 | != NFS4_INHERITANCE_FLAGS) |
790 | continue; | 726 | continue; |
@@ -930,23 +866,6 @@ nfs4_acl_write_who(int who, char *p) | |||
930 | return -1; | 866 | return -1; |
931 | } | 867 | } |
932 | 868 | ||
933 | static inline int | ||
934 | match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who) | ||
935 | { | ||
936 | switch (ace->whotype) { | ||
937 | case NFS4_ACL_WHO_NAMED: | ||
938 | return who == ace->who; | ||
939 | case NFS4_ACL_WHO_OWNER: | ||
940 | return who == owner; | ||
941 | case NFS4_ACL_WHO_GROUP: | ||
942 | return who == group; | ||
943 | case NFS4_ACL_WHO_EVERYONE: | ||
944 | return 1; | ||
945 | default: | ||
946 | return 0; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | EXPORT_SYMBOL(nfs4_acl_new); | 869 | EXPORT_SYMBOL(nfs4_acl_new); |
951 | EXPORT_SYMBOL(nfs4_acl_free); | 870 | EXPORT_SYMBOL(nfs4_acl_free); |
952 | EXPORT_SYMBOL(nfs4_acl_add_ace); | 871 | EXPORT_SYMBOL(nfs4_acl_add_ace); |