ACL Issues

Connectathon Report

Wu Zheng

version 2.0
The following is a list of issues that different vendors may have different interpretations and implementations. From talking to each other at Connectathon we have reached some conclusions on some of the issues.
 

ACL changes on a directory will not effect the ACL of an existing child file or directory.

Any ACL changes on a directory will only affect the ACL of its offspring that are created after the acl changes. When a child file or directory is created, it inherits its ACL from its parent. After the creation, the child's ACL and parent's ACL are independent from each other. Altering one will not effect the other.

When server cannot map incoming string from client, NFS4ERR_BADOWNER should be returned.

When server receives an ACL from a client, if the who string cannot be mapped to a user or group id known to the server, the server should return NFS4ERR_BADOWNER to client. Server should not store the ACL since the server is incapable of enforcing the ACL. Also, RFC specifies that NFS4ERR_BADOWNER should be returned. We have seen servers map the unknow strings to nobody at Connecthon, but we agreed NFS4ERR_BADOWNER is the right solution.

When a client requests a file's ACL from a server, if the server is unable to map a stored user or group id into a internet name string, what should the server return to the client?

The server can do one of the following.
A) Refuse to send the ACL to the client. Return NFS4ERR_BADOWNER.
B) Return a string which indicates that name string cannot be generated and provide some information about the identify of the user or group. E.g.  ":unknown user:1002:domain.com", "nobody", "1002" or "<unmapped>@". (Assume that id is 1002.)
C) return the ACE with zero length who string

Most of vendor's servers implemeted some form of option B).

Option A) limits the client's ability to read all other ACEs in the ACL. It is a not very good choice. Option B) provides more information to client than option C). On an AIX client, the ACL display utility will display the received who string without interpreting them. As a result, option B) will work very well on a AIX client. On clients which have to map the string name into an id, if servers chooses to implement option B, clients can map invalid name strings to "nobody".

When a directory has an ACE with ACE4_FILE_INHERIT_ACE flag, does the ACE propagate to child file only or does it propagate to all offspring files?

RFC 1030 says:
   ACE4_FILE_INHERIT_ACE
      Can be placed on a directory and indicates that this ACE should be
      added to each new non directory file created.

Options:
A) Only child file has the ACE
B) All offspring files have the ACE.

option B) may meet user's needs better.

Hummingbird and EMC have implemented option B). AIX has implemented option A). After studding the options, AIX decides to change its implementation from option A) to option B).

Here is some detailed information on option B) implementation:  When a directory has an ACE4_FILE_INHERIT_ACE ACE, its child directory will have equivalent ACE with ACE4_INHERIT_ONLY_ACE and ACE4_FILE_INHERIT_ACE flags. As a result, it grandchild file will receive the ACE.

example:
parent:
allow guest read ACE4_FILE_INHERIT_ACE
child dir:
allow guest read  ACE4_INHERIT_ONLY_ACE and ACE4_FILE_INHERIT_ACE
grandchild file
allow guest read ACE4_FILE_INHERIT_ACE

When a directory does not have any inheritable ACEs, what ACL should its newly created child files or child directories get?

It is possible that a parent directory has no inheritable ACEs. When a new file or directory is created under such parent, the new file or directory received no ACE from parent. The issue is what the new file or directory should use to control its access. The following are the possibilities.
A) Child file or directory has an ACL with zero number of ACEs.
B) Child file or directory has no ACL. Umask and create mode bits are used to generate mode bits for the child file or directory. When client calls GETATTR (acl), server maps the mode bits into the ACL.

Option A) sounds like a more logical solution, but option B) is the more user friendly solution. When parent directory does not have an inheritable ACE, it is likely that the server does not support inherence or the user forgot to set the inherit flag.

Most all vendors implemented or will implement option B).
 

Do we need to set the ACE4_IDENTIFIER_GROUP bit in the flag field when a special who is used in an ACE?

When ACE with SPECIAL who id GROUP@, SERVICE@.... is transmitted between client and server, should the ACE4_IDENTIFIER_GROUP bit be set in the flags. The possible solution are:
A) GROUP@ is a group, the ACE4_IDENTIFIER_GROUP flag should be set.
B) GROUP@ is a special who, the ACE4_IDENTIFIER_GROUP flag is not relevant.

The agreement is that when special who is used, the ACE4_IDENTIFIER_GROUP flag should be ignored. On an AIX client, any end user can specify an ACE with special who (GROUP@) though the ACL library API.  Users won't know whether the ACE4_IDENTIFIER_GROUP bit is required. It is better for the server to ignore the bit.

Some vendors implemented option A). But at Connecthon, most of them agreed that we will switch to option B).

File owner always has the right to read and write ACL

File owner always has the right to read and write ACL even when ACL denies file owner permssion to read/write ACL. It is a common mistake that when people set a new ACL to a file, the new ACL does not provide permission for anybody to alter ACL. Even though in most of the OSes super user always has the permission to alter the file's ACL, it becomes a frustration for an end user to contact super user every time this mistake is made. Also, it is a burden for super user to be involved every time end user make this mistakes. As an usability enhancement, we recommend that the right to alter the ACL is always granted to the file owner.

AIX server allows file owner to read and write ACL. It seems to be a good idea for other vendors to follow the same policy.

Super user retains its privilege regardless of any restrictions in ACL

Traditionally super user (root) on a server has the permissions to all file system activities regardless of a file's ACL specification. If client's root is authenticated as root on the server then client's root has the privilege of the local root. The root privilege will be reserved on AIX and Netapp.

When an NFS4 ACL is set on a file, mode bits is altered to match the ACL.

The owner/group/other permission bits will be altered to match ACL. The SUID, SGID and SVTX bit will be preserved. There are slightly different algorithms for generating the new mode bits.

Assume that a file's owner is guest@domain.com and there are both OWNER@ and guest@domain.com ACEs.
A) only OWNER@ ACEs are used to generate owner permission bit MODE4_*USR.
B) both OWNER@ and guest@domain.com are used to generate owner permission bit MODE4_*USR.

Option A) is prefered over option B). If file's owner is changed later, with option A), the mode bits are still correct. Netapp and AIX both implement option A).
 

What happens to ACL when client call SETATTR with mode bit, without ACL?

Options:
A) delete ACL
B) Alter or add OWNER@, GROUP@ and EVERYONE@ ACEs to reflect the mode change.

option B) is a more sensible solution, but the algorithm is hard to define. At this time, both AIX and Netapp implement option A). Hummingbird implements option B).

What should the server do when mode bit and ACL are sent from client to server in one SETATTR command?

NFS4 ACL is finer grained than mode bit. When there is an ACL on the file, the MODE4_*USR, MODE4_*GRP, and MODE4_*OTH are not used for access enforcement, they are for display only (e.g. ls -l).  However, the MODE4_SUID, MODE4_SGID, and MODE4_SVTX bits in the mode are not specified in ACL. When a user executes chmod +s on client, the only thing the user intends is to alter the SUID bit. One implementation is to retrieve both ACL and mode, alter the MODE4_SUID bit, and send them both back in one SETATTR call.

When a server receives mode and ACL in one SETATTR operation, at the end of the operation the SUID, SGID, and SVTX bits in the file's mode and the file's ACL need to match the data received from SETATTR operation. Also they need to be set in an atomic fashion (all or none) in case of system crash. One common code mistake is to consider ACL and mode separately. It may result in one override the other's change.
 

What should a server do when a client sends an ACL with zero number of ACEs?

When a server receives an ACL which has zero number of ACEs, it options are:

A) Reject the ACL and return NFS4ERR_INVAL to the client.
B) Store an ACL with zero number of ACEs. It means no user has access to the file except root, owner. (Server may allow file owner and super user rights to read/write ACL, even when ACL denies all right).
C) Delete the ACL and use other means (mode bits) to control access.

After talking to Saadia and Bruce, we think B) is the right answer. However, AIX currently implements A) and we don't plan to change it anytime soon.

We agree that option C) is not the right answer. Setting an ACL with zero number of ACEs should not grant more permission than an ACL with one ACE such as "allow admin read_attribute". Option C) will grant everyone permission to read attribute.  On an UNIX machine, if we remove ACL, the only thing we can use to enforce access checking is the mode bits. A file with mode permission bit -------- grant some permission to everyone by default. An example is permssion to read file ACL ans attributes.

One question is what is the proper method for a client to remove ACL and return to mode bits only state? On netApp server and AIX server, SETATTR with mode bits without ACL will remove the file's ACL, but other vendors do not do this.

In AIX, option A) is used. There are two reasons for this. First, the server does not know weather the user's intention is B) or C) when it receives an ACL with no ACE. Second, it is hard to convince everyone that option B) is the right choice over option C).

An ACE with permission mask equal to zero is legal.

When a NFS4 client sends an ACL to a server, the ACL may contain one more ACEs which have permission mask bit set to zero. The ACE is almost like an no-op. When receiving this type of ACL, the server's choices are:
A) Reject the SETATTR request with NFS4ERR_INVAL.
B) Accept the ACL and store it. The server may store the NFS4 ACL on disk as it is or map it into some other type of ACL and store it on disk.

We recommend option B). ACEs with permission mask equal to zero are needed as a place holder for Linux clients or servers to work. Linux client maps posix ACL to NFS4 ACL. Linux server maps NFS4 ACL received from the wire to POSIX before storing it. The NFS4 ACL generated by linux client and accepted by linux server follow a very strict format. Linux client may generate this type of ACEs. Sometime, clients have to add zero permission mask ACE in order for that ACL to meet the linux server input ACL format restrictions.

IBM, NetApp, Linux, EMC, Hummingbird server and client implemet option B).

Relationship between ACE4_DELETE and ACE4_DELETE_CHILD

There are two permission mask bits which control the deletion of the a file and directory. One is the ACE4_DELETE_CHILD bit in the parent directory's ACL. The other one is the ACE4_DELETE bit in the ACL of the file to be deleted. There are two interpretations of the relationship between the two bits.

A) A file/directory can be removed only if the process has both ACE4_DELETE_CHILD and ACE4_DELETE permissions.
B) ACE4_DELETE overrides ACE4_DELETE_CHILD. When an ACL explicitly specifies ACE4_DELETE in ALLOW ACE(s) or DENY ACE(s), ACE4_DELETE take precedence over ACE4_DELETE_CHILD. If ACE4_DELETE is unspecified, then ACE4_DELETE_CHILD defines the permission. In the case both are not specified, deny is the default.

AIX currently implements A). Hummingbird currently implements B). Netapp will implement B).
 

Mode to NFS4 ACL mapping algorithm

The follow is the mode bits to ACL mapping algorithm used by AIX. Similar algorithm is being discussed among connectathon attendees.

OWNER@  always allow:
ACE4_WRITE_ACL | ACE4_WRITE_ATTRIBUTES | ACE4_WRITE_NAMED_ATTRIBUTES | ACE4_READ_ACL | ACE4_READ_ATTRIBUTES | ACE4_READ_NAMED_ATTRIBUTES | ACE4_DELETE

GROUP@ and EVERYONE@  always allow:
ACE4_READ_ACL | ACE4_READ_ATTRIBUTES | ACE4_READ_NAMED_ATTRIBUTES | ACE4_DELETE

mask bits are related to "r', "w" and "x".
For Directory:
read:     ACE4_LIST_DIRECTORY
write:     ACE4_ADD_FILE | ACE4_ADD_SUBDIRECTORY | ACE4_DELETE_CHILD
execute:      ACE4_EXECUTE

For File:
read:     ACE4_READ_DATA
write:     ACE4_WRITE_DATA | ACE4_APPEND_DATA | ACE4_DELETE_CHILD (optional )
execute:     ACE4_EXECUTE

note: None of the above ( i.e. OWNER, GROUP and EVERYONE)  is allowed for WRITE_OWNER. Only the root user has the privilege for that operation.

UNIX mode is mapped into 6 NFS4 aces.
allow OWNER@ owner_allow_mask
deny  OWER@ all_mask&~owner_allow_mask
allow GROUP@ group_allow_mask
deny GROUP@ all_mask&~group_allow_mask
allow EVERYONE@ everyone_allow_mask
deny EVERYONE@ all_mask&~everyone_allow_mask

The following definitions in RFC are intend to guide the mode to NFS4 acl mapping, but it does not match any discussed algorithm. It needs to be changed.
> /*
>  * ACE4_GENERIC_READ -- defined as combination of
>  *      ACE4_READ_ACL |
>  *      ACE4_READ_DATA |
>  *      ACE4_READ_ATTRIBUTES |
>  *      ACE4_READ_NAMED_ATTRIBUTES |
>  *      ACE4_SYNCHRONIZE
>  */
> /*
>  * ACE4_GENERIC_WRITE -- defined as combination of
>  *      ACE4_WRITE_DATA |
>  *      ACE4_WRITE_ATTRIBUTES |
>  *      ACE4_WRITE_NAMED_ATTRIBUTES |
>  *      ACE4_WRITE_ACL |
>  *      ACE4_APPEND_DATA |
>  *      ACE4_SYNCHRONIZE
>  */
>
> /*
>  * ACE4_GENERIC_EXECUTE -- defined as combination of
>  *      ACE4_EXECUTE |
>  *      ACE4_SYNCHRONIZE
>  */
> #define ACE4_GENERIC_ALL      (ACE4_GENERIC_READ | \
>                                 ACE4_GENERIC_WRITE | \
>                                 ACE4_GENERIC_EXECUTE | \
>                                 ACE4_DELETE | \
>                                 ACE4_DELETE_CHILD | \
>                                 ACE4_WRITE_OWNER)
>
 

When a UNIX server maps mode bit to NFS4 ACL, the ACE4_SYNCHRONIZE permission mask bit should be set for the ALLOW ACEs of OWNER@, GROUP@ and EVERYONE@.

The ACE4_SYNCHRONIZE mask bit has no meaning to most UNIX servers. UNIX does not support threads to wait on a file close event. However, there is a possibility the SYNC behavior can be simulated on a windows client. The ACE4_SYNCHRONIZE permission might mean something to a windows client. Hummingbird developers request that we set the ACE4_SYNCHRONIZE bit in ALLOW ACEs of OWNER@, GROUP@ and EVERYONE@.  AIX, NetApp and CITI (Linux) set or will set the bit.