From the standard:
In words, Common Access Determination Algorithm is to be interpreted as
follows (this description is a loose paraphrase of the common access
determination algorithm which is specified in detailed pseudocode in
ACL Managers ):
Match (in the sense defined in the pseudocode in ACL Managers )
the incoming PAC against the ACL's access ACLEs (in the
top-to-bottom order shown, namely: UO, U, FU, GO/G/FG, O, FO, AO),
stopping at the first such match (except that all matches are
considered "simultaneously" in the case of the indicated group-like
ACLEs), and note the permissions granted by the matched ACLE (or,
in the case of the group-like ACLEs, the union of the permissions
granted by all the matched ACLEs).
Mask (that is, intersect) the acquired permissions against the
permissions in the ACL's mask ACLEs, as necessary (namely, mask
with MASK_OBJ permissions if the match occurred in the center
column1, and/or mask with UNAUTHENTICATED permissions if the PAC
is unauthenticated). (If the ACL Manager doesn't support these two
mask ACLEs, this step is a null operation.)
(emphasis in original, footnote added)
That is, if there is a file with user and group root
and permissions 0600
called acl-test
, containing the single line read possible
, then:
$ getfacl acl-test
# file acl-test
# owner: root
# group: root
user::rw-
group::---
other::---
Now if I (as user fox
) attempt to cat
this:
$ cat acl-test
cat: acl-test: Permission denied
Group permissions are unioned
I happen to be in the groups users
and wheel
, so we can add specific ACLs for these groups:
# setfacl -m g:users:--- -m g:wheel:r-- acl-test
$ cat acl-test
read possible
This is because the group
entries (considered simultaneously) allow read permission to one of my groups. These can be combined:
# setfacl -m g:users:-w- acl-test
$ getfacl acl-test
# file: acl-test
# owner: root
# group: root
user::rw-
group::---
group:wheel:r--
group:users:-w-
mask::rw-
other::---
$ printf '%s\n' 'write possible' >> acl-test
$ cat acl-test
read possible
write possible
So now I can both read and write the file, even though the groups that allow these permissions are not the same group.
User-specific permissions override all groups
Since user rules apply before group rules, we can still restrict a given user from reading and/or writing contents:
# setfacl -m u:fox:--- acl-test
$ getfacl acl-test
# file: acl-test
# owner: root
# group: root
user::rw-
user:fox:---
group::---
group:wheel:r--
group:users:-w-
mask::rw-
other::---
$ cat acl-test
cat: acl-test: Permission denied
A mask, if set, overrides almost everything
If a file is meant to be truly read-only to anyone but the owner:
# setfacl -x u:fox -m g::rw- -m m:r-- acl-test
$ getfacl acl-test
# file: acl-test
# owner: root
# group: root
user::rw-
group::rw- #effective:r--
group:wheel:r--
group:users:-w- #effective:---
mask::r--
other::---
$ printf '%s\n' 'now writing is impossible' >> acl-test
bash: acl-test: Permission denied
# printf '%s\n' 'owner can still write' >> acl-test
Amusingly, the mask does not override the others permissions, so:
# setfacl -x g:users -x g:wheel -m o:rw- -n acl-test
$ getfacl acl-test
# file: acl-test
# owner: root
# group: root
user::rw-
group::rw- #effective:r--
mask::r--
other::rw-
$ printf '%s\n' 'others can write now' >> acl-test
# chown :users acl-test
$ printf '%s\n' 'but not members of the owning group' >> acl-test
bash: acl-test: Permission denied
1 The "center column" refers to this image and contains everything except UO and O, so the owning user and others are unaffected by a mask. All groups and non-owning users with defined rules are affected.