Native NFSv4 ACLs on Linux

This page hosts an implementation of NFSv4 ACLs on ext3 filesystems.
Please note that this page is slightly outdated, and the code behaves different in some ways nowadays.

The NFSv4 ACL model is close to the CIFS ACL model, so supporting NFSv4
ACLs will provide full NFSv4 ACL support for NFSv4, and allow Samba to
much better support CIFS ACLs. At the same time, the full POSIX
semantics are preserved. This implementation allows to use Linux as a
very capable multi-protocol file server that avoids many of the
interoperability problems of other solutions.

Please also refer to various discussions on the nfsv4@ietf.org mailing
list, archived
here.

Caveats

Native NFSv4 ACLs are only supported on Ext3 filesystems so far.

The prototype does not support NFSv4 ACLs over the NFSv4 protocol,
yet.

The VFS layer in the kernel currently only asks filesystems for
MAY_READ, MAY_WRITE, MAY_EXEC, and MAY_APPEND permissions. This means that
arbitrary NFSv4 ACLs can be stored, but some of the access mask flags
that NFSv4 ACLs offer, such as the WRITE_ACL, will not be granted.

There is experimental support for this ACL format in Samba 4. Samba 3,
the current production quality version of Samba, does not have support for
that, yet.

The CIFS filesystem for accessing remote Samba filesystems also does
not support this ACL format, yet.

How To Use

Apply the kernel patches, and build and install a new kernel.

Note: if you have never applied kernel patches and
build your own kernel, then this code is not for
you. Wait until your favorite distribution offers native
NFSv4 ACLs (or not).

By default, Ext3 filesystems have ACLs disabled. In order to enable
native NFSv4 ACLs, mount the filesystem with the -o acl=nfs4
mount option. With this option, the owner, owning group, and others
are only granted permissions if they are granted both by the file mode
and the ACL.

The nfs4acl user-space utility can be used for retrieving,
setting, and removing NFSv4 ACLs; see below.

The nfs4acl Utility

The nfs4acl utility supports the --get, --set
and --remove options, and takes a number of filenames as
arguments. The --get and --remove
options themselves take no arguments; the --set option takes a text
representation of an NFSv4 ACL as argument. The --get option
writes the text representation of the ACLs of the specified file or
files to standard output. The --set option sets the ACL of the
specified file or files to the ACL defined by the option's argument. The
--remove option removes a file's ACL.

The utility supports short and long names for masks and flags, defaulting to
short (see nfs4acl --help). For each ACL entry, the
fields are printed in who, mask, flags, and type order, separated by colons.
Multiple mode bits and flags are separated by slashes. In the mask field,
permissions that are not effective because they are not also enabled in the
corresponding mask field are enclosed in parentheses. Each entry is printed
on a separate line.

In front of the actual ACL, the Owner, Group, and Other masks are
printed in the same format, even though they are not actual ACL entries:
for those pseudo ACL entries, OWNER@, GROUP@, and
EVERYONE@ is used as the who field, and the type field is
reported as MASK. The flags field is empty for these
pseudo-entries.

The --set option takes the same text representation as its
argument. Multiple ACL entries are separated by whitespace. Mask entries
may be specified in any order and at any position. Each unspecified mask
entry is set to the union of mask flags that the entry applies to (in
other words, it is set so that it does not mask anything).

Local users and group identifiers which can be resolved to names will be
printed with the user or group name as the who field, with no
"@" characters, or with their numeric identifier otherwise,
and can be specified by either name or numeric identifier. Groups must
have the IDENTIFIER_GROUP (g) flag set. Non-local users and groups
are supported by nfs4acl, but not by the kernel.

Note that the mask bits have different semantics for non-directories and
directories, and NFSv4 uses different long mnemonics for the same mask bits
depending on the object type. Nfs4acl currently uses the
non-directory mnemonics for non-directories, and the directory mnemonics
for directories. This is slightly confusing when a file inherits an ACL
from its parent directory: the permissions seem to change during
inheritance, while really only different mnemonics are used.

Code Change Log

May 19, 2008

Fix compilation error when CONFIG_EXT3_FS_NFS4ACL is off.

May 18, 2008

Add full support for the WRITE_OWNER, WRITE_ACL, WRITE_ATTRIBUTES,
ADD_SUBDIRECTORY, ADD_FILE, DELETE_CHILD, and DELETE permissions.

Start splitting the user-space into a library and utility part, so that
other programs can share the acl manipulation functions.

Add minimal support for Automatic Inheritance. (The user-space utility
does not yet implement the propagation of permissions, though.)

ext3-nfs4acl.diff: No longer mask the "system.nfs4acl" attribute, and for
debugging, implement an hidden "system.masked-nfs4acl" attribute instead. Fix
in nfs4acl_permission(): a process that is in the owning group always is in
the group class, even if the acl does not contain a group@ entry. Get rid of
nfs4acl_is_valid(): it does not matter to the kernel whether or not the flags
fields contain reasonable values. nfs4acl_propagate_allow(): avoid to create
some unnecessary entries. __nfsacl_apply_masks(): apply the owner mask to
owner aces as well instead of prepending the acl with owner@ deny entries to
disable those pemrissions. Across the whole patch: add more comments.

nfs4acl: Add a --masked option which requests a masked acl from the
kernel instead of the unmasked version that the filesystem stores. (This is
meant for debugging.) Compute masks that are not specified using the same
algorithm that the kernel uses. Add a --debug-set option for debugging which
acl the nfs4acl utility computes from text form. Some minor cleanups.

August 24, 2006

ext3-nfs4acl.diff: Massively updated. The code seems to be mostly
function complete for the initial version now: The acl=strict-nfs4
mount option is gone. The acl=nfs4+max mount option has been
added. Applying a mask to an ACL (so that the resulting ACL does not grant
more permissions than the "intersection" between the ACL and them mode, in
two variants) has been implemented. Lots of fixes everywhere.

nfa4acl.c: New --set-file option for reading an acl from a file.

July 17, 2006

Add the initial (incomplete and unfinished) design document.

nfs4acl_chmod(): only apply the umask if there is no inheritable acl.

nfa4acl_permission(): add a missing check if the id matches
current->fsuid for user@domain entries.

Put match_string() in its own patch.

July 16, 2006

ext3-nfs4acl.diff: implement nfs4acl_is_well_formed() and add a
acl=strict-nfs4 mount option to enforce well-formed ACLs in
setxattr(). Trying to set an ACL that is not well-formed in strict-nfs4
mode will result in a syslog message. Clarify some issues in comments.

nfa4acl.c: Clear ACE4_IDENTIFIER_GROUP flag in OWNER@, GROUP@, and
EVERYONE@ (but not for actual groups!). Allow to comma-separate ACEs in the
--set argument. Don't show APPEND_DATA as masked when only WRITE_DATA is
granted: currently, the kernel implicitly also grants APPEND_DATA for
WRITE_DATA.

July 15, 2006

ext3-nfs4acl.diff: nfs4acl_permission() must only apply the masks to
ALLOW ACEs, or else masking may result in a more permissive ACL for ACLs that
are not well-formed, which must not happen.

ext3-nfs4acl.diff: The DENY APPEND_DATA permission now also implies DENY WRITE_DATA. I am
still not convinced that it is really necessary to model the
dependency between WRITE_DATA and APPEND_DATA; things might work well enough
without.

nfs4acl.c: Fix a bug in nfs4acl_to_big_endian: only convert the
a_count field after the nfs4acl_for_each_entry loop.

nfs4acl.c: Add a --short option that uses single-letter
abbreviations for permissions and flags, ans accept the single-letter
form in --set.

nfs4acl.c: Enclose groups of denied permissions in parantheses
instead of only single permissions.