Tuesday, May 26, 2009

Controlling Group Access To Directories Recursively And Automatically Using Simple FACL's On Linux

Hey there,

Today we're going to take a look at using simple FACL's (file access control lists) to allow additional access restrictions (for one or more groups other than the directory owner's group) to a directory, while ensuring that the change propagates automatically to all subdirectories and files within all or any. Our examples for today should work on most distro's of Linux (and most proprietary Unix distro's), although the actual commands needed may be different ("man getfacl" or "man setfacl" should sort you out). For today's examples, all commands were run on RedHat Enterprise Server 5.2 (Tikanga - A Mãori word idiomatically meaning "The Mãori Way" or, more sanctimoniously, "correct," "right" or "true" - all absolutes ;)

The situation for today's example is pretty simple, although highly useful (of course, those aren't necessarily opposites ;). You have a directory that is owned by the user "user1" and the group "group1." A user name "user2", in the group "group2" needs to have access to your directory and also needs to be able to add new directories and/or files within that directory. To top it off, when either "user1" or "user2" creates a file or directory within the directory to be shared, that directory and/or file must be accessible to both "user1" and "user2" and owned by the group "group1." Simple enough :)

Of course, the easiest way to do this would be to add "user2" to "group1" and be done with it. However, since that might possibly afford "user2" more privilege than is actually needed (he/she may be able to access other files/directories that are owned by "group1"), a more restrictive solution is required. This is where simple FACL's come into play.

First, we'll take a quick look at the directory in question, with ls -l:

host # ls -ld shared_dir
drwxrwx--- 2 user1 group1 512 May 25 13:24 shared_dir


Once we're done, it will look almost exactly the same, except for the "+" symbol at the end of the alpha permissions display (This is an additional field, as opposed to setuid, setgid and sticky bit which replace the final alpha permissions field with a substitute character) As a point of note; some distributions include the "+" symbol at the end of "every" file, since all files/directories (on a filesystem that supports FACL's) have a default FACL. This seem counter-intuitive to me, since it makes it harder to eyeball which files/directories you've mucked with on purpose ;)

host # ls -ld shared_dir
drwxrwx---+ 2 user1 group1 512 May 25 13:24 shared_dir


Now, in order to make the whole concept of FACL's more accessible, it should be noted (at least, these days) that "all" files have FACL's (see slight caveat above), even if you don't explicitly set them. These FACL's mirror the existing file/directory permissions by default and you'll only the see the "+" symbol on files/directories where the default FACL has been modified (which is what we're going to do).

For instance, the FACL for our original shared_dir, looks like this before we even do anything, and can be obtained with the "getfacl" command (consider owner: user1, group:group1 and permissions of 770 - or drwxrwx---):

host # getfacl shared_dir
# file: shared_dir
# owner: user1
# group: group1

user::rwx
group::rwx
mask::rwx
other::---


All pound (#) comments are not acted upon, just like in most scripting languages. You can remove them, but they'll get automatically recreated every time you run a FACL command.

So, for this directory, we want to allow the group "group2" recursive read, write and execute permissions (read permissions, so they can see the contents of the directory or read any files in it, write permissions, so they can create new files/directories within the directory and/or write to files in it, and execute permissions, so that they can cd into the directory and/or execute files within it)

Luckily for us, this is actually fairly simple. All we need to do is to make use of the "setfacl" command.

host # setfacl -m g:group2:rwx shared_dir


This will change the FACL settings for the shared_dir directory, but won't do "exactly" what we want:

host # getfacl shared_dir
# file: shared_dir
# owner: user1
# group: group1

user::rwx
group::rwx
group:group2:rwx
mask::rwx
other::---


While doing this will allow "group2" read, write and execute access to the directory "shared_dir", the extended access will begin and end with the "shared_dir" directory, and any files/directories created by any user in "group2" will still be owned by "group2" when they are written to this directory.

If we want to satisfy the one remaining requirement (allowing "group2" to create new files/directories within "shared_dir" and have them all belong to "group1", with the unique FACL applied to each and every one), we need to set "default FACL's". Again, this is very simply done, and very easy to manage using the setfacl command Our first command will be to remove the rule we added with our last command. Then we'll set default FACL's for everyone and for the specific users and groups:

host # setfacl -x g:group2:rwx shared_dir
host # setfacl -d -m u:user1:rwx shared_dir
host # setfacl -d -m g:group1:rwx shared_dir
host # setfacl -d -m u:user2:rwx shared_dir
host # setfacl -d -m g:group2:rwx shared_dir


If you use the form above (which is, admittedly, more strict than it needs be; but I'm a control freak ;) and don't see the extra "default" FACL entries for the default user and group that own the file/directory, you can set those like this (also using setfacl):

host # setfacl -m d:u:rwx shared_dir
host # setfacl -m d:g:rwx shared_dir
host # setfacl -m d:o:--- shared_dir


These three entries should be put into your new FACL for the shared_dir by default, when you type the highly-specific FACL commands above, but if they're not, you'll want to add them. They are the key to propagating correct permissions on all new files/directories created within that directory.

Now typing "getfacl" should show you a dramatically different output:

host # getfacl shared_dir
# file: shared_dir
# owner: user1
# group: group1

user::rwx
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:user1:rwx
default:user:user2:rwx
default:group::rwx
default:group:group1:rwx
default:group:group2:rwx
default:mask::rwx
default:other::---


As I mentioned, you could leave out all the commands pertaining to the original owner (and group) of the file, but I like to be as specific as possible, just in case. Now, any file/directory that either user1, user2, or members of group1 or group2 create in this directory will have 770 permissions (rwxrwx---+) and their group will be set to "group1." You can also easily tell that your settings have worked by looking for the "+" symbol at the end of newly created files, which indicates that the FACL has been applied to your new file (although with a slightly different output for files than for directories):

host # who am i
user2
host # touch shared_dir/test
host # ls -l shared_dir
total 0
drwxrwx---+ 2 user2 group1 96 May 1 14:01 test

host # getfacl shared_dir/test
# file: test
# owner: user2
# group: group1

user::rw-
user:user1:rwx
user:user2:rwx
group::rwx
group:group1:rwx
group:group2:rwx
mask::rwx
other::---


And that's that :) If you still don't get the group propagation that you're expecting, it may not be supported on your OS. In that case, you can add this additional command (on top of the FACL's) to ensure that the correct group "sticks":

host # chmod g+s shared_dir


And you should be all set :)

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.