richacl - Rich Access Control Lists
Rich Access Control Lists (RichACLs) are an extension of the traditional POSIX file permission model to support NFSv4 Access Control Lists \(laURL: https://tools.ietf.org/rfc/rfc5661.txt \(ra on local and remote-mounted filesystems.
A RichACL can always be translated into an equivalent NFSv4 ACL which grants the same permissions.
RichACLs can be enabled on supported local filesystems (currently, ext4 and XFS). The in-kernel NFSv4 server and client also include RichACL support.
Enabling RichACLs disables POSIX Access Control Lists; the two ACL models cannot coexist on the same filesystem.
When used on a filesystem that does not support RichACLs, the getrichacl(1) and setrichacl(1) utilities will operate on the file permission bits instead: getrichacl(1) will display the file permission bits as a RichACL; when a RichACL is set with setrichacl(1) which can be represented exactly by the file permission bits, setrichacl(1) will set the file permission bits instead. An attempt to set a RichACL that cannot be represented exactly by the file permission bits results in an error.
This man-page describes the structure, concepts and algorithms involved in RichACLs. For examples, please refer to richaclex(7).
Structure of RichACLs
RichACLs consist of a number of ACL entries, three file masks, and a set of flags specifying attributes of the ACL as a whole (by contrast with the per-ACL-entry flags described below).
The owner, group, and other file masks further control which permissions the ACL grants, subject to the masked (m) and write_through (w) ACL flags: when the permissions of a file or directory are changed with chmod(2), the file masks are set based on the new file mode, and the masked and write_through ACL flags are set. Likewise, when a new file or directory inherits an ACL from its parent directory, the file masks are set to the intersection between the permissions granted by the inherited ACL and the mode parameter as given to open(2), mkdir(2), and similar, and the masked ACL flag is set. In both cases, the file masks limit the permissions that the ACL will grant.
Each of the ACL entries allows or denies some permissions to a particular user, group, or special identifier. An ACL entry consists of four fields:
|o||A tag which specifies the user, group, or special identifier the entry applies to. Special identifiers can be the file owner (owner@), the owning group (group@), or everyone (everyone@).|
|o||A set of permissions the entry allows or denies.|
|o||A set of flags that indicate whether the user or group identifier is mapped or unmapped, and whether the entry has been and can be inherited.|
|o||A type field indicating whether the entry allows or denies the permissions specified in the second field.|
The purpose of the file masks is to allow traditional POSIX applications which are unaware of RichACLs to place limits on the permissions granted by the RichACL without causing the ACL entries to be modified. Without the file mask, the only alternative would be for the kernel to directly modify the ACL entries. However, this latter approach could have a \(lqhysteresis effect\(rq, whereby a RichACL-unaware application that performs a transition from one file mode to another file mode and then back to the original file mode could cause destruction of the permission information in ACL entries. When creating files or directories, the mode parameter to open(2), mkdir(2), and similar would have the same effect.
Note that entries with the identifier everyone@ apply to all processes, whereas the \(lqother\(rq file permissions and \(lqother\(rq (ACL_OTHER) entries in POSIX ACLs apply to all processes which are not the owner, are not in the owning group, and do not match a user or group mentioned in the ACL.
Unlike POSIX ACLs, RichACLs do not have separate \(lqaccess\(rq ACLs that define the access permissions and \(lqdefault\(rq ACLs that define the inheritable permissions. Instead, flags on each ACL entry determine whether the entry is effective during access checks and/or inheritable.
The following ACL flags are defined:
|When set, the file masks define upper limits on the permissions the ACL may grant. When not set, the file masks are ignored.|
|When this flag and the masked flag are both set, the owner and other file masks define the actual permissions granted to the file owner and to others instead of defining an upper limit. When the masked flag is not set, the write_through flag has no effect.|
|Automatic Inheritance is enabled. See Automatic Inheritance.|
|The ACL is protected from modification by Automatic Inheritance.|
|Indicates that the ACL has been assigned in an application-dependent way when the file or directory was created; it has neither been inherited nor set explicitly. ACLs of files created on Linux will never have the defaulted flag set, but the flag may be set on files created on or copied over from other operating systems. When this flag is set for an ACL, Automatic Inheritance will completely replace the ACL.|
ACL entry flags
The following flags on ACL entries are defined:
|When this flag appears in the ACL entry of a directory, then:
|When this flag appears in the ACL entry of a directory, then that entry is inherited by new subdirectories created in the directory such that the permissions of the entry apply to the subdirectory (the inherit_only flag is cleared).|
|Inheritance stops at the next subdirectory level. When a file or directory inherits an entry that has this flag set, the file_inherit, dir_inherit, no_propagate, and inherit_only flags are cleared.|
|The entry defines inheritable permissions only and is ignored for access checking. When a file or directory inherits an entry that has this flag set, the flag is cleared.|
|The entry has been automatically inherited from the parent directory.|
|The user or group identifier is a textual string and is not mapped to a numeric user or group identifier. ACLs with unmapped identifiers can occur on NFSv4 mounted filesystems when the client cannot determine numeric user or group identifiers for some of the NFSv4 user@domain or group@domain who values. They cannot be assigned to local files or directories.|
The following permissions are defined for RichACL entries and for the three file masks:
For the r, w, and p permissions, which have different long forms for files and directories, the getrichacl(1) utility will output the appropriate form(s) depending on the context. The setrichacl(1) utility will accept either form for any file type.
|read_data / list_directory (r)|
|For a file: read the data of the file. For a directory: list the contents of the directory.|
|write_data / add_file (w)|
|For a file: modify the data of the file; does not include opening the file in append mode. For a directory: add a new file in the directory.|
|append_data / add_subdirectory (p)|
|For a file: open the file in append mode. For a directory: create a subdirectory in the directory.|
|For a file: execute the file. For a directory: traverse (search) the directory.|
|Delete a file or directory within a directory. This permission is meaningful only for directories.|
|Delete the file or directory.|
|Read basic attributes of a file or directory (see stat(2)). This permission is defined by NFSv4. It is stored, but ignored. Reading basic attributes of files and directories is always allowed on Linux.|
|Change the times associated with a file or directory to an arbitrary value. This permission is always implicitly granted to the file owner.|
|Read the ACL of a file or directory. Like reading the basic file attributes (the read_attributes permission), reading ACLs is always allowed on Linux.|
|Change the ACL or file mode of a file or directory.|
|Take ownership of a file or directory. Change the owning group of a file or directory to a group of which the calling process is a member.|
|read_named_attrs (R), write_named_attrs (W), synchronize (S), write_retention (e), write_retention_hold (E)||These permissions are defined by NFSv4 and NFSv4.1. They are stored, but ignored.|
The common textual representation of a RichACL consists of the colon-separated fields of the ACL flags, file masks, and ACL entries in the following format:
The ACL flags, file masks, and ACL entries are comma, whitespace, or newline separated.
|The ACL flags.|
|owner:perm::mask, group:perm::mask, other:perm::mask|
|The file masks and their permissions.|
|For each ACL entry, who the entry applies to, the permissions of the entry, the entry flags, and the entry type. The who field is one of the following:
Flags and permissions have single-letter as well as long forms, as listed under ACL flags, ACL entry flags, and Permissions. When the single-letter forms are used, the flags or permissions are concatenated. When the long forms are used, the flags or permissions are separated by slashes. To align permissions or flags vertically, dashes can be used for padding.
Setting and modifying file permissions
The access permissions for a file can either be set by assigning an Access Control List (setrichacl(1)) or by changing the file mode permission bits (chmod(1)). In addition, a file can inherit an ACL from its parent directory at creation time as described under Permissions at file-creation time.
Assigning an Access Control List
When assigning an ACL to a file, unless explicitly specified, the owner, group, and other file masks will be computed from the ACL entries as described in the section Computing the maximum file masks. The owner, group, and other file mode permission bits are then each set from the owner, group, and other file mask as follows:
If the ACL can be represented exactly by the file mode permission bits, the file permission bits are set to match the ACL and no ACL is stored. (When the ACL of a file is requested which doesn’t have an ACL, the file mode permission bits are converted into an equivalent ACL.)
|o||If the file mask includes the r permission, the read file mode permission bit will be set.|
|o||If the file mask includes the w or p permission, the write file mode permission bit will be set.|
|o||If the file mask includes the x permission, the execute file mode permission bit will be set.|
Changing the file mode permission bits
When changing the file mode permission bits with chmod(1), the owner, group, and other file permission bits are set to the permission bits in the new mode, and the owner, group, and other file masks are set based on the new mode bits as follows:
In addition, the masked and write_through ACL flags are set. This has the effect of limiting the permissions granted by the ACL to the file mode permission bits; in addition, the owner is granted the owner mode bits and others are granted the other mode bits. If the auto_inherit flag is set, the protected flag is also set to prevent the Automatic Inheritance algorithm from modifying the ACL.
|o||If the read bit in a set of permissions is set, the r permission in the corresponding file mask will be set.|
|o||If the write bit in a set of permissions is set, the w and p permissions in the corresponding file mask will be set.|
|o||If the execute bit in a set of permissions is set, the x permission in the corresponding file mask will be set.|
Permissions at file-creation time
When a directory has any inheritable ACL entries, the following happens when a file or directory is created inside that directory:
When a directory does not have inheritable ACL entries, files and directories created inside that directory will not be assigned Access Control Lists and the file mode permission bits will be set to (mode & ~umask) where mode is the mode argument of the relevant system call and umask is the process umask (see umask(2)).
|1.||A file created inside that directory will inherit all of the ACL entries that have the file_inherit flag set, and all inheritance-related flags in the inherited entries flag will be cleared.
A subdirectory created inside that directory will inherit all of the ACL entries that either have the dir_inherit flag set, or the file_inherit flag set and the no_propagate flag not set. Entries whose dir_inherit flag is set will have their inherit_only flag cleared, and entries whose dir_inherit flag is not set will have their inherit_only flag set. Finally, entries whose no_propagate flag is set will have all inheritance-related flags cleared.
|2.||If the parent directory’s ACL has the auto_inherit flag set, then the inherited ACL will have its auto_inherit flag set, and all entries will have their inherited flag set. Otherwise, the auto_inherit and inherited flags are cleared.|
|3.||The three file masks are computed from the inherited ACL as described in the section Computing the maximum file masks.|
|4.||The three sets of permissions for the owner, the group, and for others in the mode parameter as given to open(2), mkdir(2), and similar are converted into sets of RichACL permissions. The correspondence between mask flags and RichACL permission bits is described in the section Changing the file mode permission bits. Any RichACL permissions not included in those sets are removed from the owner, group, and other file masks. The file mode permission bits are then computed from the file masks as described in the section Assigning an Access Control List. The process umask (see umask(2)) is ignored.|
|5.||The masked ACL flag is set. The write_through ACL flag remains cleared. In addition, if the auto_inherit flag of the inherited ACL is set, the protected flag is also set to prevent the Automatic Inheritance algorithm from modifying the ACL.|
Automatic Inheritance is a mechanism that allows permission changes to propagate from a directory to files and subdirectories inside that directory, recursively. Propagation is carried out by the process changing the directory permissions (usually, setrichacl(1)); it happens without user intervention albeit not entirely automatically.
A significant limitation of the Automatic Inheritance feature is that this mechanism works only as long as files are created without explicitly specifying the file permissions to use. The standard system calls for creating files and directories (open(2), mkdir(2), mknod(2), and so on) all have mandatory mode parameters which define the maximum allowed permissions of the new files. To take account of this restriction, the protected ACL flag must be set if the inherited flag is set. This effectively disables Automatic Inheritance for that particular file.
Notwithstanding the aforementioned limitation, Automatic Inheritance still remains useful for network protocols like NFSv4 and SMB, which both support creating files and directories without defining their permissions. These protocols can implement those operations by using the standard system calls and by then undoing the effect of applying the mode parameters.
When the ACL of a directory is changed, the following happens for each entry (\(lqchild\(rq) inside that directory:
|1.||If the entry is a symbolic link, skip the child.|
|2.||If the auto_inherit flag of the entry’s ACL is not set or the protected flag is set, skip the child.|
|3.||With the child’s ACL:
|4.||If the child is a directory, recursively apply this algorithm.|
Access check algorithm
When a process requests a particular kind of access (expressed as a set of RichACL permissions) to a file, the following algorithm determines whether the access is granted or denied:
In this algorithm, a process can gain the permissions it requires by accumulating them from multiple RichACL entries. This is in contrast with POSIX ACLs, where access is only granted if an ACL entry exists that matches the requesting process and includes all the requested permissions.
|1.||If the masked ACL flag is set, then:
|2.||Upon reaching this point, the determination of whether or not access is granted is made by scanning all ACL entries to see if one or more applicable entries together grant a cumulative set of permissions that matches the requested permissions or there is an applicable entry that explicitly denies one or more of the requested permissions. The scan of all ACL entries begins by first initializing the set of remaining permissions (i.e., those that have not yet been satisfied during the scan) to be the set of requested permissions. Then the ACL entries are scanned in order, and for each entry:
|3.||If there are no more remaining permissions, access is allowed. Otherwise, access is denied.|
Computing the maximum file masks
When setting an ACL and no file masks have been explicitly specified and when inheriting an ACL from the parent directory (as described in the section Permissions at file-creation time), the following algorithm is used for computing the file masks:
The resulting file masks represent the ACL as closely as possible. With these file masks, the effective permissions that the ACL grants will be the same when the masked flag is set as when it is not set.
|1.||Clear the owner, group, and other file masks. Remember which permissions have already been processed (initially, the empty set).|
|2.||For each ACL entry:
Written by Andreas Grünbacher <agruenba>.
Please send your bug reports, suggested features and comments to the above address.
Rich Access Control Lists are Linux-specific.