ACL!… Bless You.

Posted on August 22, 2006

Access Control Lists, or ACL’s, can also often abbreviated as PITA (if you don’t know what that means, ask your local SA). I’ve largely ignored ACL’s becaue they aren’t used very often, around me anyway, and I just feel that they are often a big pain. Thankfully someone realizes my pain and things are getting much better thanks to NFSv4 ACL’s and ZFS. So lets take a couple minutes to talk about ACL’s, why they are a neccsiary evil, and review how they are used.

So, ACL’s are what we use to set permissions on a file. ACL’s exist because the age old UNIX permission scheme (rwxr-xr-x, or 755) is far to limited to solve every concern all of the time. Thus we were curs…blessed with POSIX-draft ACL’s. This is where those horrible old commands getfacl and setfacl come in. These commands, as the names imply, get or set file ACL’s. Let take a look at a plain ol’ file on UFS:

benr@aeon ~$ touch somefile
benr@aeon ~$ ls -l somefile 
-rw-r--r--   1 benr     other          0 Aug 22 00:10 somefile
benr@aeon ~$ umask
0022

So, UNIX 101 for review. We created an empty file. The traditional UNIX permision scheme uses 4 numbers to represent permissions, 3 for user, group, and other, and the fourth to act as a special flag for certain conditions (such as the “sticky bit”, setuid, setgid). Our umask defines what our default permissions should be on new files, the mask is compared against 666 for files and 777 for directories. The scheme goes 4 for read, 2 for write, and 1 for execute. When 4 octets are specified, the first octet has the scheme 4 for setuid, 2 for setgid, and 1 for the sticky bit. Therefore, 4755 would designate a permission where the file has setuid (4) set, full permissions (4, read, plus 2, write, plus 1, execute, is 7) to the owner, read and execute to the group (4, read, plus 1, execute, is 5), and then read and execute to other. And so back to our umask, with a umask of 0022, new files are created in 666 mode and therefore result in a default permission of 644, or r+w to the owner, r to group and r to everyone, as seen above. Okey, there’s the 20 second recap of stuff you should already know.

So in most cases this scheme works out well enough, a file needs an owner, and when multiple users need access you just create a group. Most people realize there is a problem when they want to add a second group to the file, or if they wish to add a second owner to avoid creating a group when they only need it in this one case. The most common answer is to simply give write access to everyone and turn a blind eye… a method which, somewhat sadly, works all too often. I’m sure every admin at one point pulled out the ol’ 777 in an emergancy case, but hopefully thats an extremely limited occurance. You did put those perms back later, right? (If you feel guilty, feel free to go fix those bad perms now.)

ACL’s allow us to go beyond this simple permission scheme, and they come in two varieties: POSIX ACL’s and NFSv4 ACL’s.

POSIX-draft ACL’s are what we’ve had for some time. In this scheme we consider the standard UNIX permissions as a minimal ACL. We can use the getfacl command to view and setfacl to set the ACL. In addition to the miminal permissions of user, group, and other, we can also insert other “masked” permissions which are there but hidden away from what you see via the ls command. Files that have these masked permissions in place are denoted by a “+” in the ls -l output. The most interesting thing here is that we can set additional “named users” with permissions, effectively allowing a single file to have multiple owners without a group, the same thing can be done with a group. Lets take a look at what this looks like:

$ touch myfile
$ ls -l myfile 
-rw-r--r--   1 benr     other          0 Aug 22 01:14 myfile
$ getfacl myfile 

# file: myfile
# owner: benr
# group: other
user::rw-
group::r--              #effective:r--
mask:rwx
other:r--
$ setfacl -m user:tamr:rwx myfile 
root@aeon /$ getfacl myfile 

# file: myfile
# owner: benr
# group: other
user::rw-
user:tamr:rwx           #effective:r--
group::r--              #effective:r--
mask:r--
other:r--
$ ls -l myfile 
-rw-r--r--+  1 benr     other          0 Aug 22 01:14 myfile

Notice that “+” that appeared after I set the ACL. The “benr” user is said to be the “default owner” just as “other” is the “default group”, and thus the ones displayed in the ls output.

While POSIX ACL’s can make life easier, they sure are a pain to manage. When we’re talking about a single file its not a big deal but when we need to work with large numbers of files, like we do in the real world, things get more tricky and getfacl and setfacl aren’t really great tools.

When NFSv4 was being developed it was clear that POSIX-draft ACL’s weren’t going to cut it anymore, both beacuse they are limited and also because they don’t jive well with CIFS which makes for some major problems when accessing files with ACL’s from both CIFS and NFS clients. “But I don’t use NFSv4!” You say… did I mention that ZFS uses NFSv4 style ACL’s?

NFSv4 ACL’s have some major advantages over POSIX, not the least of which is that we can use ls and chmod to control them, leaving the *facl tools on the scrap heap. With ls simply add the -v switch. The following is a standard files ACL entries on ZFS:

benr@aeon ~$ touch file
benr@aeon ~$ ls -v file 
-rw-r--r--   1 benr     other          0 Aug 22 01:32 file
     0:owner@:execute:deny
     1:owner@:read_data/write_data/append_data/write_xattr/write_attributes
         /write_acl/write_owner:allow
     2:group@:write_data/append_data/execute:deny
     3:group@:read_data:allow
     4:everyone@:write_data/append_data/write_xattr/execute/write_attributes
         /write_acl/write_owner:deny
     5:everyone@:read_data/read_xattr/read_attributes/read_acl/synchronize
         :allow

Much more complete. You’ll notice that owner, group, and everyone are represented here and that they have much more granular permissions. Furthermore, each comes in an accept and deny flavor. Its thus very clear what is and isn’t allowed and you have much more control.

I want to highlight something you might easily ignore or neglect to notice. Standard UNIX perms use “other” while NFSv4 perms use “everyone”. There is a simple but important distinction: everyone means just that, everyone, while other means everyone except the owner and group. WIth “other” permisions its possible that the file owner himself couldn’t edit a file with 007 permisions.

Lets look more closely at those new granular permisions:

  • read_data: Ability to read the contents of a file
  • write_data: Ability to modify an existing file
  • list_directory: Ability to list the contents of a directory
  • add_file: Ability to add a new file to a directory
  • append_data: Ability to modify an existing file, but only from EOF
  • add_subdirectory: Ability to create subdirectories
  • read_xattr: Ability to read extended attributes
  • write_xattr: Ability to write extended attributes
  • execute: Ability to execute a file
  • delete_child: Ability to delete a file within a directory
  • read_attributes: Ability to read basic attributes (non-ACL) of a file (ie: ctime, mtime, atime, etc)
  • write_attributes: Ability to write basic attributes to a file or directory (ie: atime, mtime)
  • delete: Ability to delete a file
  • read_acl: Ability to read the ACL
  • write_acl: Ability to modify the ACL (needed to use chmod or setfacl)
  • write_owner: Ability to use chown to change ownership of a file
  • synchronize: Ability to access file locally via synchronous reads and writes

Wow, thats a lot of granularity. Solaris allows us to use these permissions to explicitly allow or deny access to one or more owners, one or more groups, or everyone. Interestingly, the NFSv4 ACL standard also provides an AUDIT case, in which matching permisions flagged as AUDIT would be inserted into an audit trail, which would be pretty sweet but its not supported by Solaris at this time, which is funny because the NFSv4 ACL standard was written by Sun.

Setting the ACL is done by means of chmod. chmod has the ability to modify Access Control Entities (ACE), which are indexed in the ls output. By passing A followed by the ACE index number you can modify existing entries. By using A+ you can add a new ACE. So on and so forth. Lets try it:

benr@aeon ~$ touch file
benr@aeon ~$ ls -v file 
-rw-r--r--   1 benr     other          0 Aug 23 03:07 file
     0:owner@:execute:deny
     1:owner@:read_data/write_data/append_data/write_xattr/write_attributes
         /write_acl/write_owner:allow
     2:group@:write_data/append_data/execute:deny
     3:group@:read_data:allow
     4:everyone@:write_data/append_data/write_xattr/execute/write_attributes
         /write_acl/write_owner:deny
     5:everyone@:read_data/read_xattr/read_attributes/read_acl/synchronize
         :allow
benr@aeon ~$ chmod A0=owner@::deny file
benr@aeon ~$ chmod A1=owner@:read_data/write_data/append_data/write_xattr/write_attributes/write_acl/write_owner/execute:allow file
benr@aeon ~$ ls -v file 
-rwxr--r--   1 benr     other          0 Aug 23 03:07 file
     0:owner@::deny
     1:owner@:read_data/write_data/append_data/write_xattr/execute
         /write_attributes/write_acl/write_owner:allow
     2:group@:write_data/append_data/execute:deny
     3:group@:read_data:allow
     4:everyone@:write_data/append_data/write_xattr/execute/write_attributes
         /write_acl/write_owner:deny
     5:everyone@:read_data/read_xattr/read_attributes/read_acl/synchronize
         :allow

I’m only scratching the surface here. My intent isn’t to highlight every in and out of ACL’s, new and old, but hopefully to remind you that they are here, extremely powerful and perhaps even, on occasion, useful! Someday when your in a jam you might just find that ACL’s are the answer your looking for.

For more information, check out the following resources: