...making Linux just a little more fun!

Joey's Notes: Access Control Lists

By Joey Prestia

Joey's Notes image

Linux has the ability to use access control lists at the file level. This allows file owners and system administrators to define who has access and what level of access they have beyond the level of fliesystem permissions.

Assume that a company has a team of employees working on a project. Each employee, depending on their role and level of responsibility, needs a different set of permissions; this can be implemented via access control lists (another, and perhaps better term is discretionary access control lists.) In the event that the material is classified to some but not to all, these ACLs make things easy for the company in that security can be handled without the need to involve more people other than those directly concerned.

ACLs are available with the ext3 file system. By default, Red Hat Enterprise Linux 5 sets the capability for ACLs on all the ext3 partitions at install time. What this means is that if you create a new partition that was not in existence at install time and try to use access control lists on it, you can't: you will have to add the mount option ACL in the /etc/fstab file to make that feature available.

Most relevant commands support ACL lists, but some don't; if you're in doubt, you should check the man pages to make sure. "tar", for example, does not support access control lists.

Setting up a partition for ACLs

Let's walk through setting up and using ACLs to get the feel of the fine grained-level of control that is available by using access control lists. Since I have unpartitioned space on this drive, I will run through the process of setting up ACLs on the new partition:

[root@localhost ~]# fdisk /dev/hda
[root@localhost ~]# partprobe
[root@localhost ~]# mkfs.ext3 -L /srv/data /dev/hda10

Next, I need to edit the /etc/fstab file and add the new partition and the mount options for access control lists.

[root@localhost ~]# vi /etc/fstab


LABEL=/            /                       ext3    defaults        1 1
LABEL=/boot    	   /boot                   ext2    defaults        1 2
devpts             /dev/pts                devpts  gid=5,mode=620  0 0
tmpfs              /dev/shm                tmpfs   defaults        0 0
LABEL=/home        /home              	   ext3  usrquota,grpquota 1 2
proc               /proc                   proc    defaults        0 0
sysfs              /sys                    sysfs   defaults        0 0
LABEL=/tmp         /tmp                    ext3    defaults        1 2
LABEL=/usr         /usr                    ext3    defaults        1 2
LABEL=/var         /var                    ext3    defaults        1 2
LABEL=SWAP-hda3    swap                    swap    defaults        0 0
LABEL=/srv/data    /srv/data               ext3    defaults,acl    1 1

After that, I'll make a directory and mount our new partition.

[root@localhost ~]# mkdir /srv/data
[root@localhost ~]# mount -a

Now, I'll add a group called "programming", and create several users belonging to that group: "teamleader", "prog1", "prog2", and "tech". I'll also need to change the ownership and permissions on this directory to those appropriate for our new group. As a result, files created in this directory will belong to group "programming".

[root@localhost ~]# groupadd programming
[root@localhost ~]# chown .programming /srv/data
[root@localhost ~]# chmod 2770 /srv/data
[root@localhost ~]# useradd teamleader -G programming 
[root@localhost ~]# passwd teamleader
[root@localhost ~]# useradd prog1 -G programming
[root@localhost ~]# passwd prog1
[root@localhost ~]# useradd prog2 -G programming
[root@localhost ~]# passwd prog2
[root@localhost ~]# useradd tech -G programming
[root@localhost ~]# passwd tech
[root@localhost ~]# cd /srv/data
[root@localhost data]# ls
lost+found
[root@localhost data]# su teamleader
[teamleader@localhost data]$ 
[teamleader@localhost data]$ touch project
[teamleader@localhost data]$ chmod 700 project 

At this point the teamleader has created a project and restricted access to it via the filesystem.

Using getfacl

The command "getfacl" shows the ACL/permission information for a specified file or directory:

[teamleader@localhost data]$ getfacl project
# file: project
# owner: teamleader
# group: programming
user::rwx
group::---
other::---

Using setfacl

This command sets access controls. There are three fields on the command line that you need to be aware of:

identifier:user/group:permissions

The identifier can be expressed as:

 u - will affect the access rights of the specified user 	
 g - will affect the access rights of the specified group
 o - will affect the access rights of all others
 m - will affect the effective rights mask 

user/group is the intended username or groupname, which can also be expressed as a UID or GID.

permissions are:

 r or 4 - read access
 w or 2 - write access
 x or 1 - execute permission 
 - or 0 - no permissions

Of course permissions may be combined such as r-x or 5 depending on what you want. Using the command in its simplest form looks like this:

setfacl [options] identifier:user/group: permissions filename

Creating ACLs

	
[teamleader@localhost data]$ setfacl -m u:prog1:rwx project 
[teamleader@localhost data]$ setfacl -m u:prog2:rw- project 
[teamleader@localhost data]$ getfacl project
# file: project
# owner: teamleader
# group: programming
user::rwx
user:prog1:rwx
user:prog2:rw-
group::---
mask::rwx
other::---

At this point we promoted our programmers permissions: "prog1" can now read, write, and execute; and "prog2" has read and write access. Notice also that the output from "getfacl" now has a "mask" field at the bottom: the mask is a maximum rights level and can be used to immediately restrict the permissions on this file. In addition, if you do an "ls -l", the listing will show a "+" at the end of the permissions for each filename that has ACLs enabled:

[teamleader@localhost data]$ ls -l
total 13
drwx------  2 root       programming 12288 Mar 19 21:59 lost+found
-rwxrw----+ 1 teamleader programming     0 Mar 22 20:30 project
[teamleader@localhost data]$ 

The "programming" group needs at least read permissions on this file, since other programmers will need to see what is in the document. If we do not specify the group explicitly when we execute the "setfacl" command, it is assumed as you can see below:

[teamleader@localhost data]$ setfacl -m g::r project 
[teamleader@localhost data]$ getfacl project 
# file: project
# owner: teamleader
# group: programming
user::rwx
user:prog1:rwx
user:prog2:rw-
group::r--
mask::rwx
other::---

Restricting effective rights

By changing the mask, I can change the current effective permissions to the most restrictive level as defined by the mask and have those become the effective permissions. Even if a user or group has permissions in excess of what the effective mask is set to, the mask will restrict their effective rights.

[teamleader@localhost data]$ setfacl -m mask::r project 
[teamleader@localhost data]$ getfacl project 
# file: project
# owner: teamleader
# group: programming
user::rwx
user:prog1:rwx                  #effective:r--
user:prog2:rw-                  #effective:r--
group::r--
mask::r--
other::---

Removing a user from an ACL

If we want to remove one of our programmers - e.g., "prog1" - from the ACL for this project and revert his permissions back to what the group has, this would be done as follows:

[teamleader@localhost data]$ setfacl -x u:prog1: project
[teamleader@localhost data]$ getfacl project
# file: project
# owner: teamleader
# group: programming
user::rwx
user:prog2:rw-
group::r--
mask::rw-
other::---

The "-x" switch removes the associated user, group, or other, from the associated access control list - so "prog1" now only has group level access (and probably a pay cut to go with it).

Transfer of ACL attributes from a specification file

What if we were to store our ACL attributes in a file containing the line "u:prog1:rwx"? We could use the "-M" switch to pass the attributes on to a new file.

[teamleader@localhost data]$ touch file
[teamleader@localhost data]$ echo "u:prog1:rwx" > acl 
[teamleader@localhost data]$ setfacl -M acl file
[teamleader@localhost data]$ getfacl file
# file: file
# owner: teamleader
# group: programming
user::rw-
user:prog1:rwx
group::rw-
mask::rwx
other::r--

We have successfully transferred the ACL attributes in the file "acl" to the empty file "file". Did you notice how the effective rights mask jumped up from "rw-" to "rwx"? If you did not want the effective rights mask to change when you modify permissions you could use the "-n" option alongside your other options to prevent it.

Copying the ACLs from one file to another

To copy a file's ACL to another file you would execute "getfacl filewith.acl | setfacl -b -n -M - fileneeding.acl" as I will show below. The last "-" is important; it tells "setfacl" to read the data from standard input, which is being supplied by the preceding pipe.

[teamleader@localhost data]$ getfacl filewith.acl 
# file: filewith.acl
# owner: teamleader
# group: programming
user::rw-
user:prog1:rwx
group::rw-
mask::rwx
other::r--

[teamleader@localhost data]$ touch fileneeding.acl
[teamleader@localhost data]$ getfacl filewith.acl | setfacl -b -n -M - fileneeding.acl 
[teamleader@localhost data]$ getfacl fileneeding.acl
# file: fileneeding.acl
# owner: teamleader
# group: programming
user::rw-
user:prog1:rwx
group::rw-
mask::rwx
other::r--

Inheriting a directory's ACL from the parent

Directories can have a default ACL, which defines the access permissions that files under the directory inherit when they are created. A default ACL affects subdirectories as well as files. First, let's set up a directory with a set of default permissions. Access defaults are created by using the "-d" switch when modifying a directory.

[teamleader@localhost data]$ mkdir work
[teamleader@localhost data]$ setfacl -d -m g::r-x work/
[teamleader@localhost data]$ getfacl work/
# file: work
# owner: teamleader
# group: programming
user::rwx
group::rwx
other::r-x
default:user::rwx
default:group::r-x
default:other::r-x

Observe as I create a child directory below, "work/week1". Notice that "week1" will inherit the default ACL permissions of the parent directory "work":

[teamleader@localhost data]$ mkdir work/week1
[teamleader@localhost data]$ getfacl work/week1/
# file: work/week1
# owner: teamleader
# group: programming
user::rwx
group::r-x
other::r-x
default:user::rwx
default:group::r-x
default:other::r-x

Inheriting a file's default ACLs from the parent

Last of all, let's see how these defaults propagate to a simple file created in the "work/week1" directory. I'll show the parent's ACL first, then create the file:

[teamleader@localhost data]$ getfacl work/week1/
# file: work/week1
# owner: teamleader
# group: programming
user::rwx
group::r-x
other::r-x
default:user::rwx
default:group::r-x
default:other::r-x

[teamleader@localhost data]$ touch work/week1/day1
[teamleader@localhost data]$ getfacl work/week1/day1 
# file: work/week1/day1
# owner: teamleader
# group: programming
user::rw-
group::r--
other::r--

[teamleader@localhost data]$ umask 
0002

Note that the file was created with an active umask of 0002. This means that the file should have had permissions of 664; instead it was created with default permissions of 644 because of the default ACL on the directory and the inheriting of the ACL from the parent directory.

This is not an exhaustive list of all the possibilities; however, just these basics should be enough to get you started using access control lists. ACLs can be used to regulate permissions for special situations where regular Linux permissions will not quite handle the job; they can also lighten the administrative overhead when project-level managers learn to use them correctly and effectively. In addition, ACLs can be a valuable tool in any administrator's toolbox to help regulate security.

Resources

Talkback: Discuss this article with The Answer Gang


[BIO]

Joey was born in Phoenix and started programming at the age fourteen on a Timex Sinclair 1000. He was driven by hopes he might be able to do something with this early model computer. He soon became proficient in the BASIC and Assembly programming languages. Joey became a programmer in 1990 and added COBOL, Fortran, and Pascal to his repertoire of programming languages. Since then has become obsessed with just about every aspect of computer science. He became enlightened and discovered RedHat Linux in 2002 when someone gave him RedHat version six. This started off a new passion centered around Linux. Currently Joey is completing his degree in Linux Networking and working on campus for the college's RedHat Academy in Arizona. He is also on the staff of the Linux Gazette as the Mirror Coordinator.


Copyright © 2008, Joey Prestia. Released under the Open Publication License unless otherwise noted in the body of the article. Linux Gazette is not produced, sponsored, or endorsed by its prior host, SSC, Inc.

Published in Issue 152 of Linux Gazette, July 2008

Tux