Subject: [nfsv4] NFSv4 ACLs: (acl, masks) pairs

From: Andreas Gruenbacher <[email-masked]>
Date: Mon, 21 Aug 2006 19:34:17 +0200

At the Broomfield ACL meeting this month, we have been discussing how to apply 
a mask to an acl (upon chmod or when applying the create mode for new files). 
Because of the differences between the two access control models, algorithms 
for doing so are inherently complex.

I have proposed to store (acl, masks) pairs on NFSv4 servers instead, and to 
set the acl and masks accordingly upon mode or acl SETATTR. In such pairs, 
the masks element consist of three fields: an owner file mask, a group file 
mask, and an other file mask. The file masks define upper bounds to the 
permissions that the ACL may grant to processes in the file owner, group, and 
other classes.

This approach has the advantage that except for one, all algorithms associated 
with supporting both mode and acl attributes become very simple, without 
loosing any information. The complicated algorithm is needed (and information 
may be lost) when retrieving an acl that has had a mode applied to it. This 
problem is inherently difficult, so the proposed approach is the best 
possible.

In this posting, I will detail how (acl, masks) pairs affect the mode and acl 
GETATTR and SETATTR operations and the permission check algorithm.

Communicating (acl, masks) pairs between servers and clients that support 
these pairs is trivial: both the acl and the masks are either set or 
retrieved in the same operation. Setting (acl, masks) pairs also updates the 
mode attribute to reflect the masks.

When communicating with a client that does not support (acl, masks) pairs, we 
need to consider the following cases (thanks for this diagram, Bruce):

                       acl
                        |
                        v
                +----------------+
                |                |
        mode  ->|  (acl, masks)  | ->  mode
                |                |
                +----------------+
                        |
                        v
                       acl

(1) Mode SETATTR

    This operation sets the mode attribute on the server, and recomputes
    the masks. The masks are computed as follows: convert each of the
    owner, group, and other file permission in the mode into the
    corresponding NFSv4 mask flags, and set the owner, group, and other
    file masks to these new values.

    It is irelevant in this step whether masks define upper bounds to
    the mask flags granted to OWNER@, GROUP@, and EVERYONE, or mask
    flags that those identifiers are actually granted ("write-through").

(2) ACL SETATTR

    This operation is implemented by setting the acl to the new acl, and
    by setting the file masks to values such that they will not mask any
    permissions that the acl may grant. The most simple choice would be
    to set the file masks so that they contain all possible permissions.

    This operation also updates the mode attribute to reflect the acl:
    If the mode attribute is computed as an upper bound to the
    permissions that the ACL grants (this is the symmetric case to mode
    SETATTR, and it is also how POSIX ACLs work), it makes sense to
    compute the mask values so that they reflect the mask flags that the
    acl grants as tightly as possible. If the mode attribute is computed
    differently (as recommended by RFC3530), it is not necessary to
    compute as tight as possible tight masks.

(3) Mode GETATTR

    This operation returns the mode attribute.

(4) ACL GETATTR

    This operation remains complicated: we must return an acl that grants
    no more permissions than the (acl, masks) pair grants, and we want to
    come as close to those permissions as possible.

    Note that this is an inherent problem of supporting both mask and acl
    attributes separately, and no implementation will be able to avoid
    solving it. The algorithm used here is the same as applying a mode
    to an arbitrary NFSv4 acl.

The permission check algorithm for (acl, masks) pairs must take the acl as 
well as the masks into account. A different algorithm is required depending 
on whether the masks define upper bounds to the mask flags granted to OWNER@, 
GROUP@, and EVERYONE, or mask flags that those identifiers are actually 
granted.

Algorithm A: Permission Check with Masking
==========================================

   [1]  If a process does not match the owner, continue with step
        [2]. Else, if the requested mask flags exceed the owner
        file mask, deny access. Else, use the NFSv4 permission
        check algorithm to determine access.

   [2]  Determine if any of the group class ACEs in the ACL match
        the process. If they do not, continue with step [3].
        Else, if the requested mask flags exceed the group file
        mask, deny access. Else, use the NFSv4 permission check
        algorithm to determine access.

   [3]  If the requested mask flags exceed the other file mask,
        deny access. Else, use the NFSv4 permission check
        algorithm to determine access.

Steps [2] and [3] can be combined by remembering whether a group class ACE 
matches the process during the NFSv4 permission check algorithm, and checking 
whether any of the remaining group class ACEs in the ACL match the process 
after access has has already been determined.

Algorithm B: Permission Check with Masking and "Write-Through"
==============================================================

   [1]  If a process does not match the owner, continue with step
        [2]. Else, if the requested mask flags exceed the owner
        file mask, deny access. Else, allow access.

   [2]  If the process is not a member in the owning group, continue
        with step [3]. Else, if the requested mask flags exceed the
        group file mask, deny access. Else, allow access.

   [3]  Determine if any of the group class ACEs in the ACL match
        the process. If they do not, continue with step [4]. Else,
        if the requested mask flags exceed the group file mask, deny
        access. Else, use the NFSv4 permission check algorithm to
        determine access.

   [4]  If the requested mask flags exceed the other file mask, deny
        access. Else, allow access.

Again, step [3] can be implemented more efficiently by remembering whether a 
group class ACE matches the process during the NFSv4 permission check 
algorithm, and checking whether any of the remaining group class ACEs in the 
ACL match the process after access has has already been determined.

---

The only remaining problem that this posting leaves open is which algorithm 
should best be used to apply a mode to an acl (or masks to an acl, which is 
equivalent). I have designed an algorithm that still has a few minor 
disadvantages, and I am in the process of resolving those remainning issues, 
and completing the implementation. I'll post an update as soon as I'm 
finished with the code and have it documented.

Regards,
Andreas

-- 
Andreas Gruenbacher <[email-masked]>
Novell / SUSE Labs

_______________________________________________
nfsv4 mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/nfsv4

---

From: Lisa Week <[email-masked]>
Date: Wed, 30 Aug 2006 15:34:57 -0600

Hi Andreas,

Comments inline...

Thanks,
Lisa

>mode attribute to reflect the masks.

I take the following sentence to mean that the mode will be the same as 
the masks:
"Setting (acl, masks) pairs also updates the mode attribute to reflect 
the masks."

Is this correct?

>need to consider the following cases (thanks for this diagram, Bruce):

I don't understand what this picture is trying to illustrate.  Is it 
that when asked for the mode, the acl and the mask will be taken into 
account when determining what to return?
Also, when just asked for the ACL, the acl and the mask will be taken 
into account?

>    to set the file masks so that they contain all possible permissions.
I've been trying to get my head around how the setting of an ACL would 
modify the file mask attributes.  Also, I don't really get the purpose 
and benefit of exposing the mask to the client.  What would the client 
really do with it?

Can you answer my questions for the following scenario:

1.) Set the following ACL:
lisa:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW

* At this point, what would the masks be?
    Would they be:
    owner mask = all bits off
    group mask = READ_DATA/WRITE_DATA/APPEND_DATA on, EXECUTE off  (just 
assume read write execute for now)
    other mask = all bits off

* What would the mode be?

2.) chmod "600"

* At this point, what would the masks be?
    Would they be:
    owner mask = READ_DATA/WRITE_DATA/APPEND_DATA on, EXECUTE off
    group mask = all bits off
    other mask = all bits off

* What would the mode be?

* What would the ACL be?
    Would it be:
    lisa:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW

3.) At this point, lisa should not be allowed the ability to 
READ_DATA/WRITE_DATA/APPEND_DATA, but now what if you want to ALLOW bob 
READ_DATA/WRITE_DATA/APPEND_DATA?

How would you do this?  What happens to the mask and what happens to 
lisa's permissions?

--------

In step #3, here are the options that I see:

Either you do or don't expose it to applications... so.

If you don't expose it to applications (whatever modifies an ACL -- 
GUIs, CLIs, whatever) you can:

1.) Add a "bob:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW" ACE to the front 
of the ACL and
    a.) Don't change the group mask bits so it has all bits still turned 
off.
            * This has the disadvantage that even after setting the ACL, bob
               won't be able to read and write.
    b.) Change the group mask bits so it has
         READ_DATA/WRITE_DATA/APPEND_DATA on, EXECUTE off
             * This has the disadvantage that lisa now gets granted the 
ability to read
                and write (just from setting the ACL to give bob read 
and write).

2.) Add a "bob:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW" ACE to the front 
of the ACL and
    a.) Have the server automatically remove the
         READ_DATA/WRITE_DATA/APPEND_DATA bits from the lisa ALLOW ACE
         and change the group mask bits so that it has
         READ_DATA/WRITE_DATA/APPEND_DATA on, EXECUTE off
             * This has the disadvantage that you now lose information 
about what
                permissions lisa had anyway...isn't this what masks are 
trying to prevent?
    b.) Have the client do the above by setting the ACL and mask values.
             * This has the same disadvantage as the above.

None of these really seem desireable to me because you are making 
assumptions about what the user really wants to do.  Therefore, it seems 
like in order to not make assumptions, you would want the mask attribute 
to be exposed to the user...

If you do expose it to applications you can:

3.) Have the ACL editor (CLI, GUI, whatever) allow the user to modify 
the ACL and the masks separately.
In this case you would make the user modify the ACL and the mask in 
order to give the permissions that they really want.

So, wait, now we've just introduced something that is 1.) Different than 
Windows ACLs (which is really what NFSv4 ACLs are based on) 2.) 
Different than POSIX-draft ACLS (because we have owner, group and other 
masks rather than just group masks).  Which is yet another thing for the 
end user to learn, right?

Another thing... If you have ACLs and masks, how do you display 
effective permissions?  Is a user supposed to figure this out themselves?

I think introducing these file mask entities makes NFSv4 ACLs harder to 
use and user interfaces harder to write.
...
Even if all servers that support modes and ACLs also supported the mask 
someday, I think introducing these file mask entities makes NFSv4 ACLs 
harder to use and user interfaces harder to write.  Just think about the 
fact that not all protocols will be able to support the mask (e.g. - 
NFSv4.0 and CIFS).

>    This operation returns the mode attribute.

It is still not clear to me what the value of the mode returned would 
be.  Would it be equal to the masks or would it be derived from the acl 
and the mask?

>    to an arbitrary NFSv4 acl.

So, since we have to solve the problem of applying a mode to an 
arbitrary NFSv4 ACL anyway, why would we add the additional complexity 
of having a mask attribute as well?

---

From: "J. Bruce Fields" <[email-masked]>
Date: Wed, 30 Aug 2006 19:32:43 -0400

On Wed, Aug 30, 2006 at 03:34:57PM -0600, Lisa Week wrote:
> modify the file mask attributes.

The important thing is that setting the ACL *must* set the effective
permissions.  The whole proposal is designed exactly so that clients
that only get and set ACLs and modes will see pure 4.0 behavior; the ACL
returned always represents effective permissions accurately, and setting
an ACL sets effective permissions.

(Details: Ideally the mask would be set to the most restrictive mask
bits that are no more restrictive than the given ACL.  But if its set to
something more permissive that's probably not a problem.)

> Also, I don't really get the purpose and benefit of exposing the mask
> to the client.  What would the client really do with it?

Most of the time, nothing.

But when they really care (for example, if they're archiving and NFSv4
filesystem and want to preserve all permissions accurately), then they
can ask for it.

Users should probably never see it; of if they do, it should be hidden
behind some sort of "advanced permissions" button in an ACL editor.

--b.

---

From: "J. Bruce Fields" <[email-masked]>
Date: Wed, 30 Aug 2006 19:36:03 -0400

> of having a mask attribute as well?

Consider the case:

	1. set the acl to (lisa:rw-:allow)
	2. set the mode to 000.

What do you return at this point?  There are a number of choices, which
would all represent the effective permissions correctly:

	1. (lisa:---:allow)

	2. ()			(empty acl--denies everything)

	3. (lisa:rw-:deny,
	    lisa:rw-:allow)

The first two choices have the advantage of simplicity.  The third has
the advantage that it preserves some information.

I'd prefer to have the option of doing 1 or 2, because option 3 gets
more complicated as more users are added to the ACL.

The file_mask attribute allows me to do that, by allowing me to return
option 1 or 2 in the normal case, but allowing me to return

	1. ((lisa:rw-:allow), mask 000)

to the rare client that really cares about the full story.

--b.

---

From: Sam Falkner <[email-masked]>
Date: Wed, 30 Aug 2006 19:53:15 -0600

> filesystem and want to preserve all permissions accurately), then they

I don't understand, "preserve all permissions accurately".  What if  
I'm on a client that understands NFSv4 ACLs but not this mask  
attribute, and I use a version of "tar" that knows how to store/ 
retrieve the ACLs.  What's missing?

> behind some sort of "advanced permissions" button in an ACL editor.

If users don't see it, then how does

setacl bruce:rw-:allow
chmod 600
setacl prepend-to-acl lisa:rw-:allow

work?  Do you get

lisa:rw-:allow
bruce:---:allow

or

lisa:rw-:allow
bruce:rw-:allow

or

lisa:---:allow
bruce:---:allow

Understand that now I'm talking about a client that supports this  
mask attribute, using an ACL editor that supports the mask attribute,  
but not showing it to the user.

- Sam

---

From: Andreas Gruenbacher <[email-masked]>
Date: Thu, 31 Aug 2006 19:31:58 +0200

> Comments inline...

Thanks!

> >retrieved in the same operation. Setting (acl, masks) pairs also updates
> > the mode attribute to reflect the masks.
>

Setting the acl and/or masks also updates the mode, correct.

> >When communicating with a client that does not support (acl, masks) pairs,
> > we need to consider the following cases (thanks for this diagram, Bruce):
> >
> >                       acl
> >
> >                        v
> >                +----------------+
> >

Maybe I should better have drawn the picture as follows:

                       acl
			|
                        v
                +----------------+
                |  (acl, masks)  |
        mode  ->|                | ->  mode
                |      mode      |
                +----------------+
			|
                        v
                       acl

There are multiple ways to compute a mode from an ACL (with or without a mode 
(=masks) applied to it), but in any case after a mode SETATTR, we want to get 
the same mode back. So it's easiest to think of it as having the mode stored 
on the server, and that's also the most realistic implementation.

> and benefit of exposing the mask to the client.  What would the client

I think it would be best to discuss these interactions based on the more 
complete specification of file masks that I'm working on right now, and which 
will be out later this week if things go as planned. This will clarify most 
of your questions I expect.

> * What would the mode be?

This follows from the permission check algorithm that bounds each principal to 
its corresponding file mode: the ACL allows Lisa 
READ_DATA/WRITE_DATA/APPEND_DATA. Lisa may or may not be the file owner, so 
the masks would have to be:

   owner mask = READ_DATA/WRITE_DATA/APPEND_DATA
   group mask = READ_DATA/WRITE_DATA/APPEND_DATA
   other mask = empty

> * At this point, what would the masks be?

   owner mask = READ_DATA/WRITE_DATA/APPEND_DATA
   group mask = empty
   other mask = empty

> * What would the mode be?

0600

>     lisa:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW

Yes. The mode SETATTR doesn't change the ACL as stored on the server. Clients 
requesting the ACL would be presented with an empty ACL though.

> READ_DATA/WRITE_DATA/APPEND_DATA

Mode 600 says to give the owner Read/Write access. So if lisa is the owner, 
it's at least not obvious that she should be denied all access with this ACL 
and mode 600.

It's another problem that "give lisa rw access only if she is the owner" 
cannot be represented as an ACL. It may be a good idea to not allow 
permissions that can't be represented as an ACL, but that's a different 
matter.

> but now what if you want to ALLOW bob READ_DATA/WRITE_DATA/APPEND_DATA?
>

There's no such operation as "allow bob READ_DATA/WRITE_DATA/APPEND_DATA". A 
mask unaware editor would retrieve the ACL with the mask applied (which would 
grant no effective permissions to anybody), and modify it accordingly. A mask 
aware editor may want to choose to throw away or keep the 
lisa:READ_DATA/WRITE_DATA/APPEND_DATA:ALLOW entry, set the masks as it sees 
fit (or not set them and only set the ACL), etc. -- there are several valid 
approaches.

Andreas