FreeBSD, POSIX.1e ACLs and inheritance


July 2015.
The FreeBSD logo

Introduction


This post does not apply to you if you're using ZFS. In that case, you'll be using NFSv4 ACLs.

First, make sure your UFS volumes are mounted with option acls set.


$ cat /etc/fstab
# Device Mountpoint FStype Options Dump Pass#
/dev/mirror/gm0s1a / ufs rw,acls 1 1

I'm also setting the default umask to 027 in /etc/login.conf, to not have newly created files readable by everyone by default.

File ACLs


Let's create a directory for a website, and give it standard UNIX permissions.

$ mkdir /usr/local/www/truc
$ chown root:wheel /usr/local/www/truc/
$ chmod 2770 /usr/local/www/truc/

$ ll /usr/local/www/
drwxrws--- 2 root wheel 512 Jul 24 09:44 truc/

Let's create two new users, and give them full permissions in the directory:

$ pw useradd jambon
$ pw useradd poulet
$ setfacl -m user:jambon:rwx /usr/local/www/truc/
$ setfacl -m user:poulet:rwx /usr/local/www/truc/

Let's see:

$ getfacl /usr/local/www/truc/
# file: /usr/local/www/truc/
# owner: root
# group: wheel
user::rwx
user:jambon:rwx
user:poulet:rwx
group::rwx
mask::rwx
other::---

So far, so good.

Now, let's connect as the user and create some files.

$ sudo -s -u jambon
% umask 007
% cd /usr/local/www/truc/
% echo "Super script" > index.php

Now let's login as the second user and try to change the file:

$ sudo -s -u poulet
% cd /usr/local/www/truc/
% echo "Better script" > index.php
index.php: Permission denied.

Querying the ACLs confirms that the permissions were not inherited.

$ getfacl index.php
# file: index.php
# owner: jambon
# group: wheel
user::rw-
group::rwx # effective: r--
mask::r--
other::---

Inheritance


Files and directories actually have *two* ACL tables: file and default. The default one can be used to specify what permissions will be set when creating new content. It can queried using option -d.

$ getfacl -d /usr/local/www/truc/
# file: /usr/local/www/truc/
# owner: root
# group: wheel
user::rwx
group::rwx
mask::rwx
other::---

$ getfacl /usr/local/www/truc/
# file: /usr/local/www/truc/
# owner: root
# group: wheel
user::rwx
user:jambon:rwx
user:poulet:rwx
group::rwx
mask::rwx
other::---

This shows that both the users can write in the directory, but the content they write will only have classic UNIX permissions.

Let's change that.


$ setfacl -d -b /usr/local/www/truc/
$ setfacl -d -m u::rwx,g::rwx,o:: /usr/local/www/truc/
$ setfacl -d -m user:poulet:rwx /usr/local/www/truc/
$ setfacl -d -m user:jambon:rwx /usr/local/www/truc/
$ getfacl -d /usr/local/www/truc/
# file: /usr/local/www/truc/
# owner: root
# group: wheel
user::rwx
user:jambon:rwx
user:poulet:rwx
group::rwx
mask::rwx
other::---


$ sudo -s -u jambon
% umask 007
% cd /usr/local/www/truc/
% echo "Super script" > index.php

$ sudo -s -u poulet
% cd /usr/local/www/truc/
% umask 007
% echo "Better script" > index.php

$ getfacl index.php
# file: index.php
# owner: poulet
# group: wheel
user::rw-
user:jambon:rwx # effective: rw-
user:poulet:rwx # effective: rw-
group::rwx # effective: rw-
mask::rw-
other::---

So far, so good.

Let's try that with a directory.


$ sudo -s -u jambon
% umask 007
% cd /usr/local/www/truc/
% mkdir static && cd static
% echo "I hate Javascript" > content.js

% sudo -s -u poulet
% cd /usr/local/www/truc/static/
% echo "I also hate Javascript" > content.js

$ getfacl static/
# file: static/
# owner: jambon
# group: wheel
user::rwx
user:jambon:rwx
user:poulet:rwx
group::rwx
mask::rwx
other::---

$ getfacl static/content.js
# file: static/content.js
# owner: jambon
# group: wheel
user::rw-
user:jambon:rwx # effective: rw-
user:poulet:rwx # effective: rw-
group::rwx # effective: rw-
mask::rw-
other::---

It works exactly the same.

Since we're hosting a website, let's allow user www to read (but not write) the files:

$ find /usr/local/www/truc/ -exec setfacl -m user:www:rx {} \;
$ find /usr/local/www/truc/ -type d -exec setfacl -d -m user:www:rx {} \;

Repeat the same operation with write permissions if you want the server to be able to write in some directories (and configure it to not execute code there, obviously).

The only limitation of this system is that the default ACLs that apply when new files/directories are created are masked with the standard user/group permissions. You'll need to configure the umask each time (manually in the shell, or in the config files of your ftp/samba/whatever server).