What are ACLs and why would you want to use them?

ACLs are Access Control Lists for files and directories. They are based on the IEEE's POSIX 1003.1e draft 17, also known simply as POSIX.1e. ACLs are an addition to the standard Unix file permissions (r,w,x,-) for User, Group, and Other. ACLs give users and administrators flexibility and fine-grained control over who can read, write, and execute files. This can all be done without adding mysterious groups and pestering the system administrator.

This document is a basic HOWTO/tutorial on using ACLs on the Snellius system. 

NOTE: the examples are from a system where the default umask is 022. (This means, that for a new created file or directory, the read and execute permission bits are set for group and other). The default umask on Snellius is 077.

On both systems, the default permissions for the home directory are rwx------ (0700)

Supported file systems

ACLs are supported on the file systems of Snellius.

Snellius

Snellius's home and project file systems use POSIX ACLs.

ACLs are NOT supported on the archive file system.


Using POSIX ACLs

The basic commands that we are interested in are:

  • getfacl
  • setfacl

We will first look at the getfacl command. The owner of the directory we will be working with is "tristan", and the guest user will be "axel" and the guest group will be "lensmen". First, create a test file, then look at the permissions and the ACL:

[tristan@login1 tristan]$ cd /home/tristan
[tristan@login1 tristan]$ man bash > pizza

[tristan@login1 tristan]$ ls -l pizza
-rw-r--r--  1 tristan tristan 19936 May 28 16:59 pizza

[tristan@login1 tristan]$ getfacl pizza
# file: pizza
# owner: tristan
# group: tristan
user::rw-
group::r--
other::r--

So far, there is nothing very exciting to see. Now, let's change the ACL so that user "axel" can read and write to the file:

[tristan@login1 tristan]$ setfacl -m u:axel:rw- pizza
[tristan@login1 tristan]$ getfacl pizza
# file: pizza
# owner: tristan
# group: tristan
user::rw-
user:axel:rw-
group::r--
mask::rw-
other::r--
                                                                                
[tristan@login1 tristan]$ ls -l pizza
-rw-rw-r--+ 1 tristan tristan 19936 May 28 16:59 pizza

You will notice that there is now an extra user entry in the ACL, and there is a "+" next to the file in the output from the ls command. The "+" indicates that an ACL has been applied to the file or directory. Now, let's add a group ("lensmen") and another user ("tippy") to the ACL for pizza:

[tristan@login1 tristan]# setfacl -m u:tippy:r--,g:lensmen:r-- pizza

[tristan@login1 tristan]# getfacl pizza
# file: pizza
# owner: tristan
# group: tristan
user::rw-
user:axel:rw-
user:tippy:r--
group::r--
group:lensmen:r--
mask::rw-
other::r--

Hmmm...what's the mask entry? This is the effective rights mask. This entry limits the effective rights granted to all ACL groups and ACL users. The traditional Unix User, Group, and Other entries are not affected. If the mask is more restrictive than the ACL permissions that you grant, then the mask takes precedence. For example, let's change the mask to "r--" and give user "tippy" and group "lensmen" the permissions rwx, and see what happens:

[tristan@login1 tristan]$ setfacl -m u:tippy:rwx,g:lensmen:rwx pizza

[tristan@login1 tristan]$ setfacl -m mask::r-- pizza

[tristan@login1 tristan]$ getfacl --omit-header pizza
user::rw-
user:axel:rw-                #effective:r--
user:tippy:rwx               #effective:r--
group::r--
group:lensmen:rwx            #effective:r--
mask::r--
other::r--

The ACL now shows an "effective" rights mask. Even though "tippy" has been given rwx permissions, he actually only has r-- permissions because of the mask.

In most cases, I want the effective mask to allow whatever permissions I granted to named users and groups, so my mask will be rw- or rwx. I will reset it like this:

[tristan@login1 tristan]$ setfacl -m m::rw- pizza

[tristan@login1 tristan]$ getfacl --omit pizza
user::rw-
user:axel:rw-
user:tippy:rwx
group::r--
group:lensmen:rwx               #effective:rw-
mask::rw-
other::r--

What about using the setfacl command to change normal User, Group, and Other permissions? No problem! This can be used instead of chmod:

[tristan@login1 tristan]$ setfacl -m u::rwx,g::rwx,o:rwx pizza

[tristan@login1 tristan]$ ls -l pizza
-rwxrwxrwx+ 1 tristan tristan 19965 May 29 09:31 pizza

[tristan@login1 tristan]$ getfacl --omit pizza
user::rwx
user:axel:rw-
user:tippy:rw-
group::rwx
group:lensmen:rwx
mask::rwx
other::rwx

Note that the mask changed! Whenever you change the permissions of a user or a group with setfacl, the mask is changed to match. Therefore, if you want a restrictive mask, it must be applied after the user and group permissions are modified.

Another thing to keep in mind is that the chmod command does not alter the file's ACL...the ACL information will remain intact, except that the mask entry can change as described above.

More setfacl Details and Examples

The setfacl command has many options. In this section, we will look at some of the more useful ones. Remove Specific Entries from an ACL

You can remove specific ACL entries with the -x option. In this example, we will remove the entry for user "tippy" and user "axel" but leave the other entries alone:

[tristan@login1 tristan]$ getfacl --omit pizza
user::rwx
user:axel:rw-
user:tippy:rw-
group::rwx
group:lensmen:rwx
mask::rwx
other::rwx

[tristan@login1 tristan]$ setfacl -x u:tippy,u:axel pizza

[tristan@login1 tristan]$ getfacl --omit pizza
user::rwx
group::rwx
group:lensmen:rwx
mask::rwx
other::rwx


Remove Entire ACL

To completely remove an ACL from a file or directory:

[tristan@login1 tristan]$ setfacl -b pizza

You can also use:

[tristan@login1 tristan]$ setfacl --remove-all pizza


Using the --set Option

If you want to explicitly set all of the file permissions on a file or a group of files, you must use the --set option. This is different from the -m option, which only modifies the existing ACL. The --set option replaces all permissions and ACLs with the new values. When you use the --set option, all of the User, Group, and Other permissions must be defined. Here is an example:

[tristan@login1 tristan]$ setfacl --set u::rw,g::rw,o::-,u:tippy:r pizza

[tristan@login1 tristan]$ getfacl --omit pizza
user::rw-
user:tippy:r--
group::rw-
mask::rw-
other::---

Using setfacl recursively

If you want to apply ACLs to an entire directory and all of its subdirectories, use the -R option. Given the directory hierarchy /home/tristan/Level1/Level2/Level3/Level4, the following command will add an ACL entry for group "lensmen" to all of the Level* directories and their contents:

[tristan@login1 tristan]$ setfacl -R -m g:lensmen:r-x /home/tristan/Level1

Using ACL Entries from a File

What if you have a lengthy ACL that needs to be used frequently? Rather than typing it over and over again on the command line, you can save the ACL as a text file and use it to apply ACLs to other files. For example, we will create the ACL config file /home/tristan/myacl:

user:axel:rw-
user:tippy:rw-
group:lensmen:r--
group:marty:r--
group:fafnir:r--
mask::rw-
other::---

Now, we can easily apply these ACL modifications to files:

[tristan@login1 tristan]$ setfacl -M myacl test*

[tristan@login1 tristan]$ ls -l test*
-rw-rw----+ 1 tristan tristan 168 May 30 09:41 test1
-rw-rw----+ 1 tristan tristan 168 May 30 09:42 test2
-rw-rw----+ 1 tristan tristan 168 May 30 09:42 test3

[tristan@login1 tristan]$ getfacl test1
# file: test1
# owner: tristan
# group: tristan
user::rw-
user:axel:rw-
user:tippy:rw-
group::rw-
group:marty:r--
group:lensmen:r--
group:fafnir:r--
mask::rw-
other::---


Note on UID, GID, and Permissions

When you are using setfacl, you can use numeric UIDs and GIDs instead of the actual names. The UIDs and GIDs do not have to exist yet. If you use names, then they must exist or you will get an error. You can use the

getfacl --numeric filename

command to view the numeric values.

Also, when you are specifying permissions, you can use octal permissions (0-7) instead of (r,w,x,-).

Example Scenario

Now that we have seen basic command usage, let's use a practical example to learn some more about ACLs. Tippy is working with Tristan on a project. He needs to be able to read, write, create, and delete files related to the project, which are located in Tristan's home directory. Tristan wants to do this without bothering the system administrator with requests for new groups and group membership changes. When the project is over, Tristan will remove the permissions for user "tippy" without bothering the sysadmin.

All of the project files are located in /home/tristan/Project. Here is how Tristan will handle the situation:

[tristan@login1 tristan]$ setfacl -m user:tippy:--x /home/tristan
[tristan@login1 tristan]$ getfacl /home/tristan
getfacl: Removing leading '/' from absolute path names
# file: home/tristan
# owner: tristan
# group: tristan
user::rwx
user:tippy:--x
group::---
mask::--x
other::---

[tristan@login1 tristan]$ setfacl -R -m u:tippy:rwx,o::--- Project
[tristan@login1 tristan]$ getfacl Project
# file: Project
# owner: tristan
# group: tristan
user::rwx
user:tippy:rwx
group::rwx
mask::rwx
other::---

[tristan@login1 tristan]$ cd Project
[tristan@login1 Project]$ ls -l
total 1560
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2.2
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so.3
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so.3.2
[tristan@login1 Project]$ getfacl --omit libkrb5.so
user::rwx
user:tippy:rwx
group::r-x
mask::rwx
other::---

Now, Tippy can access the /home/tristan/Project directory. He can read, modify, add, and delete files. However, he cannot delete the Project directory, nor can he view any other files in Tristan's home directory. This is good, because Tippy likes to test his limits. Let's see what he can and can't do:

[tippy@login1 tippy]$ cd /home/tristan
[tippy@login1 tristan]$ ls
ls: .: Permission denied
[tippy@login1 tristan]$ rm -rf Project
rm: cannot remove `Project': Permission denied
[tippy@login1 tristan]$ cd Project
[tippy@login1 Project]$ ls -l
total 1560
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2.2
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so.3
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so.3.2
[tippy@login1 Project]$ touch status-report.txt

[tippy@login1 Project]$ date >> libkrb5.so.3
[tippy@login1 Project]$ rm libkrb5.so.3
[tippy@login1 Project]$ ls -l
total 1136
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2
-rwxrwx---+ 1 tristan tristan  86532 May 29 14:02 libgssapi_krb5.so.2.2
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so
-rwxrwx---+ 1 tristan tristan 423572 May 29 14:02 libkrb5.so.3.2
-rw-rw-r--  1 tippy   tippy        0 May 29 16:06 status-report.txt

Now, after the project is complete, it is a simple matter for user Tristan to revoke Tippy's access to /home/tristan:

[tristan@login1 tristan]$ setfacl -x u:tippy: /home/tristan
[tristan@login1 tristan]$ getfacl /home/tristan
getfacl: Removing leading '/' from absolute path names
# file: home/tristan
# owner: tristan
# group: tristan
user::rwx
group::---
mask::---
other::---

If user "tippy" decides to snoop around in /home/tristan/Project again, he will not be able to:

[tippy@login1 tippy]$ cd /home/tristan
-bash: cd: /home/tristan: Permission denied
[tippy@login1 tippy]$ ls /home/tristan/Project
ls: /home/tristan/Project: Permission denied

Note that this entire example was done without having to involve the system administrator!

The Default ACL

Up until now, we have been looking at the access ACL. There is also another type of ACL, called the default ACL. The default ACL is only applied to directories, and it defines the permissions that a newly created file or directory inherits from its parent directory.

When you create a new directory inside a directory that already has a default ACL, the new directory inherits the default ACL both as its access ACL and its default ACL.

Here is an example of defining a default ACL for a directory, and what happens when files and directories are created underneath that directory:

[tristan@login1 tristan]$ mkdir Plato

[tristan@login1 tristan]$ setfacl --set u::rwx,g::r-x,o::- Plato

[tristan@login1 tristan]$ setfacl -d --set \
      u::rwx,u:tippy:rwx,u:axel:rx,g::rx,g:lensmen:rx,o::- Plato
[tristan@login1 tristan]$ getfacl Plato
# file: Plato
# owner: tristan
# group: tristan
user::rwx
group::r-x
other::---
default:user::rwx
default:user:axel:r-x
default:user:tippy:rwx
default:group::r-x
default:group:lensmen:r-x
default:mask::rwx
default:other::---

[tristan@login1 tristan]$ cd Plato
[tristan@login1 Plato]$ touch guitar
[tristan@login1 Plato]$ getfacl guitar
# file: guitar
# owner: tristan
# group: tristan
user::rw-
user:axel:r-x                #effective:r--
user:tippy:rwx               #effective:rw-
group::r-x                   #effective:r--
group:lensmen:r-x            #effective:r--
mask::rw-
other::---

[tristan@login1 Plato]$ mkdir Zep
[tristan@login1 Plato]$ getfacl Zep
# file: Zep
# owner: tristan
# group: tristan
user::rwx
user:axel:r-x
user:tippy:rwx
group::r-x
group:lensmen:r-x
mask::rwx
other::---
default:user::rwx
default:user:axel:r-x
default:user:tippy:rwx
default:group::r-x
default:group:lensmen:r-x
default:mask::rwx
default:other::---

[tristan@login1 Plato]$ cd Zep
[tristan@login1 Zep]$ touch airship
[tristan@login1 Zep]$ getfacl airship
# file: airship
# owner: tristan
# group: tristan
user::rw-
user:axel:r-x                #effective:r--
user:tippy:rwx               #effective:rw-
group::r-x                   #effective:r--
group:lensmen:r-x            #effective:r--
mask::rw-
other::---

The umask has no effect if a default ACL exists. In the following example, the umask is honored when a file is created in the /home/tristan directory, which has no default ACL. When a file is created under /home/tristan/Plato, which has a default ACL, you can see that the umask is ignored:

[tristan@login1 tristan]$ umask ugo=
[tristan@login1 tristan]$ umask
0777
[tristan@login1 tristan]$ touch button
[tristan@login1 tristan]$ ls -l button
----------  1 tristan tristan 0 Jun  1 00:47 button

[tristan@login1 tristan]$ cd Plato
[tristan@login1 Plato]$ touch switch
[tristan@login1 Plato]$ ls -l switch
-rw-rw----+ 1 tristan tristan 0 Jun  1 00:47 switch
You can also modify and create default ACLs with another syntax, prefixing the u, g, or o entries with a "d" :
[tristan@login1 tristan]$ setfacl -m d:u:axel:rwx,d:g:lensmen:rwx Plato
[tristan@login1 tristan]$ getfacl Plato
# file: Plato
# owner: tristan
# group: tristan
user::rwx
group::r-x
other::---
default:user::rwx
default:user:axel:rwx
default:user:tippy:rwx
default:group::r-x
default:group:lensmen:rwx
default:mask::rwx
default:other::---

Using cp and mv with ACLs

Three major file utilities, ls, cp, and mv have been updated to handle ACLs. The mv command will always preserve ACLs if it is possible. If it is not possible, it will issue a warning. The cp command will only preserve ACLs if used with the -p or -a options.

In both cases, if you are trying to copy/move from a filesystem that supports ACLs to a filesystem that does not, only the standard Unix permissions will be retained. In the example below, you can see that using the cp -p command within the ACL-enabled /home filesystem worked, and using the same command to copy the file to the /archive directory (which is not ACL-enabled) resulted in an error message:

[tristan@login1 tristan]# cd /home/tristan
[tristan@login1 tristan]# mkdir ACL
[tristan@login1 tristan]# cp -p pizza ACL/pizza
[tristan@login1 tristan]# ls -l ACL/pizza
-rw-rwx---+ 1 tristan tristan 19965 May 29 09:31 ACL/pizza

[tristan@login1 tristan]# cp -p pizza /archive/tristan
cp: preserving permissions for `/archive/tristan/pizza': Operation not supported
[tristan@login1 tristan]# ls -l /archive/tristan/pizza
-rw-rwx---  1 tristan tristan 19965 May 29 09:31 /archive/tristan/pizza

Copying ACLs

If you already have a file with a complex ACL, you can easily copy that ACL to other files by piping the output of a getfacl command into the setfacl command. Here is an example of copying the ACL from bingo.txt to all of the files starting with "test":

[tristan@login1 Compaq]$ ls -l
total 4
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:52 bingo.txt
-rw-rw----  1 tristan tristan 0 Jun  2 09:53 testa1
-rw-rw----  1 tristan tristan 0 Jun  2 09:53 testa2
-rw-rw----  1 tristan tristan 0 Jun  2 09:55 testa3
-rw-rw----  1 tristan tristan 0 Jun  2 09:53 testa4
-rw-rw----  1 tristan tristan 0 Jun  2 09:55 testa5

[tristan@login1 Compaq]$ getfacl bingo.txt | setfacl --set-file=- test*

[tristan@login1 Compaq]$ ls -l
total 24
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:52 bingo.txt
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:53 testa1
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:53 testa2
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:55 testa3
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:53 testa4
-rw-rw----+ 1 tristan tristan 0 Jun  2 09:55 testa5

[tristan@login1 Compaq]$ getfacl --omit testa5
user::rw-
user:axel:rw-
user:tippy:rw-
group::rw-
group:marty:r--
group:lensmen:r--
group:fafnir:r--
mask::rw-
other::---

You can also archive all of the ACLs from an entire directory tree, then restore them later. You might want to do this if you are recovering files from backup media that does not support ACLs, like CD-ROM. Here is an example of archiving/saving all of the ACLs in the /home/tristan/Tree directory tree, and restoring them.

There are 898 files in this tree:

[tristan@login1 tristan]$ du -h Tree
9.5M    Tree/A/B/C/D
19M     Tree/A/B/C
29M     Tree/A/B
38M     Tree/A
9.5M    Tree/AA/BB/CC/DD
19M     Tree/AA/BB/CC
29M     Tree/AA/BB
38M     Tree/AA
86M     Tree

Now, let's archive the ACLs into a file in our home directory:

[tristan@login1 tristan]$ getfacl -p -R Tree > Tree.facl
[tristan@login1 tristan]$ ls -l Tree.facl
-rw-rw-r--  1 tristan tristan 120550 Jun  2 12:08 Tree.facl

Now, we will simulate restoring the files from CD without ACLs by stripping all of the ACLs off:

[tristan@login1 tristan]$ setfacl -R -b Tree

Now we can restore all of the ACL entries with one command:

[tristan@login1 tristan]$ setfacl --restore Tree.facl