aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ.Bruce Fields <bfields@fieldses.org>2006-10-04 05:16:11 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:20 -0400
commit09229edb68a3961db54174a2725055bd1589b4b8 (patch)
tree44876575189a69021d961345ef9bc75ddffaac1e /fs
parentd0ebd9c0e71d20ea8c2b4a071d2a2b4878ef07d6 (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')
-rw-r--r--fs/nfsd/nfs4acl.c627
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
99static int 99/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
100mode_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
105static void
106low_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
119struct ace_container { 121struct ace_container {
@@ -338,38 +340,6 @@ sort_pacl(struct posix_acl *pacl)
338 return; 340 return;
339} 341}
340 342
341static int
342write_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
360static struct nfs4_ace *
361get_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
373int 343int
374nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, 344nfs4_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: */
406struct posix_ace_state {
407 u32 allow;
408 u32 deny;
409};
410
411struct posix_user_ace_state {
412 uid_t uid;
413 struct posix_ace_state perms;
414};
415
416struct 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
425struct 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
432static int 435static int
433same_who(struct nfs4_ace *a, struct nfs4_ace *b) 436init_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
439static int 459static void
440complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny, 460free_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
454static inline int 465static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
455user_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;
477out:
478 return error;
479} 468}
480 469
481static inline int 470/*
482users_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); 489static 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;
522out:
523 return error;
524} 498}
525 499
526static inline int 500static struct posix_acl *
527group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p, 501posix_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) 568out_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) */ 573static 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) 579static 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) */ 585static 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;
649out:
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
658static inline int 601static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
659mask_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;
675out:
676 return error;
677} 607}
678 608
679static inline int 609static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
680other_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;
700out:
701 return error;
702} 615}
703 616
704static int 617static void process_one_v4_ace(struct posix_acl_state *state,
705calculate_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
721static struct posix_acl * 686static 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))
771out_acl: 706 sort_pacl(pacl);
772 posix_acl_release(pacl);
773out_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
933static inline int
934match_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
950EXPORT_SYMBOL(nfs4_acl_new); 869EXPORT_SYMBOL(nfs4_acl_new);
951EXPORT_SYMBOL(nfs4_acl_free); 870EXPORT_SYMBOL(nfs4_acl_free);
952EXPORT_SYMBOL(nfs4_acl_add_ace); 871EXPORT_SYMBOL(nfs4_acl_add_ace);