View ACLs

Author: Grzegorz Czapliński gregory at systemics dot pl FreeBSD

Reviewer: name contact BSD flavour

Reviewer: name contact BSD flavour


Concept

Be able to determine if a FreeBSD system is using ACLs, and if so, on which filesystems. In addition, be able to view a file's ACL on a FreeBSD system.

Introduction

ACLs provide an extended set of permissions for a file or directory. These permissions can be used in addition to the conventional UNIX permissions for files and directories. Standard UNIX file permissions (covered in section View file permissions and modify them using either symbolic or octal mode) provide read, write and execute access to three user classes:

  • file owner
  • file group
  • others

ACLs are used to provide greater data access control for each file or directory. They enable you to define permissions for specific users and groups.

Every ACL has the following syntax:

[ACL tag]:[ACL qualifier]:[Access permissions]

ACL tag is a scope of the file permissions to the owner, group, others, specific users, specific groups or ACL's mask.

The ACL qualifier field describes the user or group associated with the ACL entry. It might be UID or user's name, GID or group's name, or empty.

Access permissions are the effective permissions for [ACL tag] and are specified as:

  • r - read
  • w - write
  • x - execute

Entry types:

u::perm permissions for the file owner g::perm permissions for the file group o::perm permissions for the others u:UID:perm permissions for the specific user identified by UID u:username:perm permissions for the specific user identified by username g:GID:perm permissions for the specific group identified by GID g:groupname:perm permissions for the specific group identified by groupname m::perm maximum effective permissions allowed for specific users or groups.

The mask does not set the permissions for the file owner or others. It is used as a quick way to change effective permissions for all specific users or groups. 

ACLs are part of UFS2 filesystem shipped with FreeBSD 5.0-RELEASE as an option or FreeBSD 5.1-RELEASE as the default filesystem during the installation. To check which filesystem you have on your system type:

# dumpfs /tmp | head -1
magic   19540119 (UFS2) time    Fri Aug 15 19:23:30 2003

You must have ACL support compiled into the kernel too.

Add:

options         UFS_ACL            #Support for access control lists

to your kernel config compile and install a new kernel according to the instructions in the June 2003 Answerman column.

To enable ACLs on a partition, after newfs(1)'ing it issue the commands:

# tunefs -a enable /dev/da1s1e
# mount /dev/da1s1e /mountpoint
# mount | grep acl
/dev/da1s1e on /mountpoint (ufs, local, soft-updates, acls)

This indicates that soft-updates and acls are enabled on the /dev/da1s1e partition mounted under /mountpoint.

The other way to check if ACLs are enabled is to use tunefs(1) command:

# tunefs -p /dev/da1s1e
tunefs: ACLs: (-a)                                         enabled
tunefs: MAC multilabel: (-l)                               disabled
tunefs: soft updates: (-n)                                 enabled
tunefs: maximum blocks per file in a cylinder group: (-e)  2048
tunefs: average file size: (-f)                            16384
tunefs: average number of files in a directory: (-s)       64
tunefs: minimum percentage of free space: (-m)             8%
tunefs: optimization preference: (-o)                      time
tunefs: volume label: (-L)

Before I show some examples please read the manpage for getfacl(1). The commands and their output below are separated by one empty line for clarity. On my test system I have a user called acl and he belongs to wheel group. When you see touch(1) command in an example, that means I recreated a file after it was removed.

Create an empty file:

% umask 027
% touch file.txt
% ls -l file.txt
-rw-r-----  1 acl  wheel  0 Aug  5 22:35 file.txt

% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
group::r--
other::---

The file.txt is a normal file without any ACL permissions set yet.

TODO: need to clean this part up (and others with setfacl) and just show your own possible examples without using setfacl in this doc. TODO: it would be good for beginning admin to know that setfacl exists and what it is, but according to the BSD Certification Group, TODO: this doesn't need to target modifying ACLs.

% ls -l file.txt
-rw-rw----+ 1 acl  wheel  0 Aug  5 22:41 file.txt

The little "+" at the end of access rights column indicates that the file has ACL set.

% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::r--
mask::rw-
other::---

This command shows that owner has read/write access, group has read access, and user gregory has read/write access. I have to point now that the mask indicates the maximum permissions for user gregory.

If the command was (set the mask - "m::r"):

TODO: remove setfacl from this beginning article:

% setfacl -m u::rw,g::r,u:gregory:rw,m::r file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-        # effective: r--
group::r--
mask::r--
other::---

user gregory would have read/write access, but the mask would downgrade the effective access rights to read only.

There is an "-M" switch that is used to set and modify the ACL entries. The information about actual ACLs are kept in a file (in this example acls.txt).

% touch file.txt

Create acls.txt file which looks like:

% cat acls.txt 
u:bin:rwx

% setfacl -M acls.txt file.txt 
% getfacl file.txt 
#file:file.txt
#owner:1009
#group:0
user::rw-
user:bin:rwx
group::r--
mask::rwx
other::---

In the last example ACL entry for user bin was specified in a file acls.txt. Recalculating an ACL mask

The ACLs look as above (the last getfacl(1) command), issue a command:

% setfacl -m u::rw,g::r,u:bin:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:bin:rw-
user:gregory:rw-
group::r--
mask::rw-
other::---

Now, users gregory and bin have read/write access, and the mask has been "group" ACL entries in the resulting ACL.

If the last command was:

% setfacl -n -m u::rw,g::r,u:bin:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:bin:rw-            # effective: r--
user:gregory:rw-        # effective: r--
group::r--
mask::r--
other::---

the mask would not get recalculated (switch -n). Effective rights for users gregory and bin would be read only. Deleting an ACL

To delete an ACL entry for user bin do:

% setfacl -n -x u:bin:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-        # effective: r--
group::r--
mask::r--
other::---

The entry for user bin was deleted. If you want the mask not to get recalculated, remember to use the "-n" switch. If you didn't use it, the mask would be read/write now, effectively changing permissions for user gregory to read/write.

To remove permanently ACL from a file issue:

% setfacl -bn file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
group::r--
other::---
% ls -l file.txt
-rw-r-----  1 acl  wheel  0 Aug  5 23:08 file.txt

Compare the above with that:

% setfacl -b file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
group::r--
mask::r--
other::---

In the next example, setfacl(1) command is able to change permissions for all user classes - owner, group, others.

% umask 027
% touch file.txt
% ls -l file.txt
-rw-r-----  1 acl  wheel  0 Aug  5 23:13 file.txt

% setfacl -m u::rw,g::r,o::r,u:gregory:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::r--
mask::rw-
other::r--
alphax% ls -l file.txt
-rw-rw-r--+ 1 acl  wheel  0 Aug  5 23:12 file.txt

More interesting example:

% touch file.txt
% ls -l
total 0
-rw-r-----  1 acl  wheel  0 Aug  5 23:24 file.txt

% chmod 660 file.txt
% ls -l
total 0
-rw-rw----  1 acl  wheel  0 Aug  5 23:24 file.txt

% setfacl -m u::rw,g::r,o::r,u:gregory:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::r--
mask::rw-
other::r--

% ls -l
total 2
-rw-rw-r--+ 1 acl  wheel  0 Aug  5 23:25 file.txt

% chmod 644 file.txt
% ls -l
total 2
-rw-r--r--+ 1 acl  wheel  0 Aug  5 23:25 file.txt

% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-        # effective: r--
group::r--
mask::r--
other::r--

The last setfacl(1) command set the access rights as follows:

user::rw-
user:gregory:rw-
group::r--
mask::rw-
other::r--

Then I changed explicitly access rights with chmod(1) command:

% chmod 644 file.txt

and the access rights reapeared as:

user::rw-
user:gregory:rw-        # effective: r--
group::r--
mask::r--
other::r--

Note, the mask is closely associated with group access rights. Changing Unix access rights with chmod(1), you also change the mask value.

Consider this scenario:

% touch file.txt
% setfacl -m u::rw,g::rw,o::r,u:gregory:rw file.txt
% ls -l file.txt
-rw-rw-r--+ 1 acl  wheel  0 Aug  6 20:19 file.txt

% setfacl -m m::r file.txt 
% getfacl file.txt        
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-        # effective: r--
group::rw-              # effective: r--
mask::r--
other::r--

% ls -l file.txt
-rw-r--r--+ 1 acl  wheel  0 Aug  6 20:20 file.txt

Changing the mask value, does change group access rights.

If you see a file with a magic "+" at the end of access rights column, check it with getfacl(1). Copying ACL entries

% touch file.txt
% setfacl -m u::rw,g::r,u:gregory:rw file.txt
% getfacl file.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::rw-
mask::rw-
other::r--
% getfacl file.txt | setfacl -b -n -M - file1.txt

% getfacl file.txt file1.txt
#file:file.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::rw-
mask::rw-
other::r--

#file:file1.txt
#owner:1009
#group:0
user::rw-
user:gregory:rw-
group::rw-
mask::rw-
other::r--

Creating default ACLs

Default ACL entries provide a way to propagate ACL information automatically to files and directories. New files and directories inherit ACL information from their parent directory if that parent has an ACL that contains default entries. You can set default ACL entries only on directories.

Example:

% umask 027
% mkdir dir
% ls -l
total 2
drwxr-x---  2 acl  wheel  512 Aug  6 11:50 dir

% getfacl dir
#file:dir
#owner:1009
#group:0
user::rwx
group::r-x
other::---

Before you set any default ACL entries for users or groups, you must set default ACL entries for owner, group, other, and ACL mask.

Consider this:

% setfacl -m u::rwx,m::rwx,g::rx,o::rx dir 
% getfacl dir 
#file:dir
#owner:1009
#group:0
user::rwx
group::r-x
mask::rwx
other::r-x
% setfacl -dm u:gregory:rwx,m::rwx dir     
setfacl: acl_set_file() failed for dir: Invalid argument

The correct order is:

% setfacl -dm u::rwx,m::rwx,g::rx,o::rx dir
  1. Set default ACL entries for directory owner, group, others and the mask.

    % getfacl -d dir #file:dir #owner:1009 #group:0 user::rwx group::r-x mask::rwx other::r-x

To view default ACLs issue getfacl(1) with the "-d" switch.

% setfacl -dm u:gregory:rwx,m::rwx dir
  1. Set default ALC entry for user gregory.

To see the effect of default ACLs on subdirectories issue the following commands:

% mkdir dir/subdir
% getfacl -d dir 
#file:dir
#owner:1009
#group:0
user::rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

% getfacl -d dir/subdir 
#file:dir/subdir
#owner:1009
#group:0
user::rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

The subdir directory successfully inherited default ACL entries from its parent.

Suppose, you want to set default ACL entries for additional user bin:

% setfacl -dm u:bin:rwx,m::rwx dir
% getfacl -d dir
#file:dir
#owner:1009
#group:0
user::rwx
user:bin:rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

% getfacl -d dir/subdir 
#file:dir/subdir
#owner:1009
#group:0
user::rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

That new default ACL entries for addtional user bin are not visible on dir/subdir as the directory was created before the ACL entry for bin was set.

To see the effect of default ACLs on files, create a file beneath the dir directory:

% touch dir/file.txt
% ls -l dir/file.txt 
-rw-r-----+ 1 acl  wheel  0 Aug  6 12:14 dir/file.txt

% getfacl dir/file.txt 
#file:dir/file.txt
#owner:1009
#group:0
user::rw-
user:bin:rwx            # effective: r--
user:gregory:rwx        # effective: r--
group::r-x              # effective: r--
mask::r--
other::---

The setfacl(1) manual states: "Currently only directories may have default ACL's. Deleting default ACLs

To delete default ACLs on directories, use setfacl(1) with the "-k" switch:

% setfacl -k dir
% getfacl -d dir 
#file:dir
#owner:1009
#group:0

% getfacl dir   
#file:dir
#owner:1009
#group:0
user::rwx
group::r-x
other::---

To delete a default ACL entry for user bin do:

% mkdir dir
% setfacl -dm u::rwx,m::rwx,g::rx,o::rx dir
% setfacl -dm u:gregory:rwx,u:bin:rwx,m::rwx dir

% getfacl -d dir                                
#file:dir
#owner:1009
#group:0
user::rwx
user:bin:rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

Create acls.txt file which looks like:

% cat acls.txt 
u:bin:rwx

% setfacl -dX acls.txt dir 
alphax% getfacl -d dir 
#file:dir
#owner:1009
#group:0
user::rwx
user:gregory:rwx
group::r-x
mask::rwx
other::r-x

or simply type:

% setfacl -d -x u:bin:rwx dir

Things to remember

setfacl(1) always recalculates the ACL mask to allow maximum effective permissions for every ACL entry, unless the "-n" switch is used.

If you use the chmod(1) command to change the file group owner permissions on a file with ACL entries, both the file group owner permissions and the ACL mask are changed to the new permissions. Be aware that the new ACL mask permissions may change the effective permissions for additional users and groups who have ACL entries on the file.

Examples

Practice Exercises

More information

mount(8), ls(1), getfacl(1)