Filesystem ACLs and Permissions

Sharing access to files requires strict definitions on how and by whom those files can be accessed. This article explains basic POSIX permissions followed up with Linux ACLs (which is probably what you actually want to use for your share)

Overview

We will first explain simple POSIX permissions, because POSIX ACLs are an extension of them, and understanding the basic concepts is useful for the more complex topic of ACLs. If you are familiar with POSIX file permissions, feel free to skip ahead to the section on ACLs. The section on POSIX permissions serves the purpose of bringing everyone up to speed.

If you are a Windows User, it is still highly reccomended, that you read and understand this documentation. It is possible to grant ACL permissions using Windows Explorer, which provides a graphical interface, but works with the same POSIX ACLs in the backend. Make sure, that the configurations you perform in the GUI actually correspond to what you want on the POSIX side. Spending half an hour thinking about ACLs is time well spent compared to the work accidentally granting the wrong people permissions on your files can cause.

The topic of ACLs can seem a bit complex in the beginning, so we provide examples of common configurations in the best practices section. There is also a very well written article by one of the original implementers of ACLs on Linux.

Where can i request a group?

The instructions in this article will heavily use UNIX groups. If you do not yet have a fitting group for your workgroup / institute / use-case, the process how you can request your own group is described here.

Common POSIX permissions

The basic POSIX permission concept knows three kinds of users: The user (sometimes referred to as owner), to which a file belongs, the group, to which a file belongs and finally all other users. Permissions can be granted to each of these individually. Permissions can grant read, write or execute access and are commonly abbreviated using the letters r w and x and likewise, user, group and other are often abbreviated using u, g and o

Because of the way shares are made available university wide, others in the context of file shares is equivalent to anyone on the university network. Under normal circumstances, you should not grant permissions to the others group.

File Permissions

  • The read permission allows reading the content of simple files, such as with cat or a text editor. Copying a file also requires read permissions, because the copying program needs to read the content of the file to be created from somewhere.
  • The write permission allows modifying the content of simple files and overwriting the file.
  • The execute permission allows the file to be executed as a program by the shell. This is necessary for compiled binaries and scripts alike.

Directory Permissions

  • The read permission allows looking up the content of a directory.
  • The write permission allows modifying the content of directories (adding and removing files).
  • The execute permission works slightly differently for directories. It allows accessing the metadata of files contained within the directory. This is obviously something you need when you want to read or write files within the directory (it is in fact not possible to e.g. access files when only the read permission is set on the directory), so whenever one of these permissions is granted to someone on a directory, the execute permission is usually also granted.

Working with permissions

It is also possible to express POSIX permissions in Octal format, such as 744 or 640. Octal refers to the fact, that each of the digits of the octal number can assume one of eight possible values. The digits correspond to user, group and others, in order of their appearance. r corresponds to 4, w corresponds to 2 and x corresponds to 1. Adding these numbers up results in the actual digit representing the permissions for that group

Consider this output of ls -l:

$ls -l


-rw------- 1 root root  4017 Feb 24  2022 vimrc

Starting from the right side of the output, we can see the following:

  • The file vimrc was created on the 24. of February in 2022 and its size is 4017 bytes.
  • It belongs to the root group and the root user (normally, each user also belongs to a group with the same name and this group will be associated with all files that user creates — members of the group gain access to every file with the respective permissions on that file)
  • It has a total of 1 hard link referring to it
  • Finally, we get the permission block, which looks like this: -rw-------.
    • The first character is a - sign, signifying that this is a normal file (if this were a directory, it would instead read d, for example)
    • The next 9 characters represent the permissions for the user, group and others. The absence of a permission is represented with a -, so none of the three groups has execute permissions on our file, for example.

If we wanted to, we could also express these permissions in octal format, as mentioned above:

User:   rw- = 4+2+0 = 6
Group:  --- = 0+0+0 = 0
Others: --- = 0+0+0 = 0

Currently, the group does not have any permissions. If we want to grant the group read permission, we can use the chmod (change mode) command to do so. We can either define which permissions we want to grant to which group, or we can fully specify the permissions of all groups on the file using octal notation:

$ chmod g+r vimrc
$ chmod 640 vimrc
$ ls -l
-rw-r----- 1 root root  4017 Feb 24  2022 vimrc

If we granted these permissions in error, we can also remove them again:

$ chmod g-r vimrc
$ chmod 600 vimrc
$ ls -l
-rw-r----- 1 root root  4017 Feb 24  2022 vimrc

Linux ACLs

Access Control Lists (ACLs) extend the basic set of POSIX permissions. They were developed because more granular control over file access, rather than only one user, one group and everybody else, was required.

Let’s use a different example now and pretend we work in a university with a hierarchical structure of institutes comprising multiple workgroups each. We are Bernd the phd-student currently setting up a network share for our workgroup. Let’s take a look at the ACLs currently in effect. For this the command getfacl exists:

$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
group::r--
other::---

Apparently, the user has read and write access and the group has only read access. If this seems familiar to you, it’s because these are just the basic permissions from earlier. So far, no ACLs beyond that are in effect. Let’s change that. The command setfacl allows setting ACLs. It has many features, but for this introduction we will only use a few. The -m flag modifies the ACL list:

$ setfacl -m "group:example-workgroup:rw" network-share
$ setfacl -m "group:example-institute:r" network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
group::r--
group:example-institute:r--
group:example-workgroup:rw-
mask::rwx
other::---

Using ls, we can now notice a + next to the permissions of the network-share directory, which is an indicator, that additional ACLs are in effect for this file (the -d flag allows us to list the directory rather than its content):

$ ls -ld
drw-r-----+ 1 bernd bernd  4096 Feb 24  2022 network-share

We granted the group example-workgroup read-write access while granting the group example-institute read access, perhaps because we want to share some of our data with colleagues in our institute. Acute readers will notice, that another entry called mask has also appeared. The permissions in the mask entry define the allowed set of permissions that can be granted by any ACL. The mask entry is required by ACLs and is automatically created based on the permissions of the group, if it is not specified. Permissions that are not set in the mask entry, can not be granted by ACLs. To demonstrate this, we remove some basic permissions from the group, which will modify the derived mask:

chmod 600 network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
group::---
group:example-institute:rw-			#effective:---
group:example-workgroup:rw-			#effective:---
mask::---
other::---

As we can see the effective permissions for the groups defined in the ACLs are ---, which is due to the fact, that the mask entry masks whatever permissions are unset in it. We can explicitly change the mask entry to fix this:

$ setfacl -m "mask:r" network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
group::---
group:example-institute:rw-			#effective:r--
group:example-workgroup:r--
mask::r--
other::---

Now suppose Bernd has a colleague Bob who is only in the institute group, but still closely works together with Bernd. He also needs read and write access to the network share, so we grant it to him as follows (we fix the mask entry first, because otherwise Bob’s effective permissions would amount to read access):

$ setfacl -m "mask:rwx" network-share
$ setfacl -m "user:bob:rw" network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
user:bob:rw-
group::---
group:example-institute:r--
group:example-workgroup:rw-
mask::rwx
other::---

When Bob decides to change careers and become an antiquarian, we can remove the ACL granting his account access as follows:

$ setfacl -x "user:bob" network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
group::---
group:example-institute:r--
group:example-workgroup:rw-
mask::rwx
other::---

This kind of upkeep is obviously not very feasible for large numbers of accounts, so it is usually best to use membership in a group as the criterion for access, automatically removing access through membership expiration. Moreover, Bernd will not be able to modify files created by Bob, which may be a problem when they want to work on the same files. But there is a solution for that too.

Default ACLs

There is a special type of ACLs that is inherited by objects from their parent directory at creation time – Default ACLs. They also grant permissions like normal ACLs, but the inheritance mechanism makes them especially useful for shared directories, because they allow setting an ACL once, which will then propagate to any file and directory created beneath the original parent directory. This obviously reduces the administrative overhead, so it’s highly reccomended (unless there is a specific reason why you don’t want them, you want them). Default ACLs are set using the -d flag of setfacl, everything else works exactly like before (for demonstration purposes, we add another bob-ACL to the network-share directory):

$ setfacl -d -m "group:example-workgroup:rw" network-share
$ setfacl -d -m "group:example-institute:r" network-share
$ setfacl -m "user:bob:rw" network-share
$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rw-
user:bob:rw-
group::---
group:example-institute:r--
group:example-workgroup:rw-
mask::rwx
other::---
default:user::rw-
default:group::---
default:group:example-institute:r--
default:group:example-workgroup:rw-
default:mask::rwx
default:other::---

If we now create another directory in the network-share directory, the default ACLs will be inherited, and regular ACLs will be applied to the new directory based on the defaults. Notice how the user:bob:rw- ACL can not be found in the child directory, because it has no corresponding default ACL.

mkdir network-share/child
$ getfacl network-share/child
# file: network-share/child
# owner: bernd
# group: bernd
user::rw-
group::---
group:example-institute:r--
group:example-workgroup:rw-
mask::rwx
other::---
default:user::rw-
default:group::---
default:group:example-institute:r--
default:group:example-workgroup:rw-
default:mask::rwx
default:other::---

The conclusion from this is, that default ACLs are the most useful in a network-share where new files and directories are created.

Best Practices

Recursively (-R) set a default ACL and a regular ACL granting the permissions you wish. The X permission will set the execute permission, if the file in question is a directory or already has execute set in one of user group and others. This is useful, because execute permissions are required on most directories to do anything with them.

$ setfacl -R -d -m "group:example-workgroup:rwX" network-share
$ setfacl -R -m "group:example-workgroup:rwX" network-share

Make sure you don’t accidentally grant permissions to groups you do not mean to grant access to (especially others or Unix groups with members that should not have access)

$ getfacl network-share
# file: network-share
# owner: bernd
# group: bernd
user::rwx
group::---
group:example-workgroup:rwx
mask::rwx
other::---
default:user::rwx
default:group::---
default:group:example-workgroup:rwx
default:mask::rwx
default:other::---