Showing posts with label setfacl. Show all posts
Showing posts with label setfacl. Show all posts

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.

Saturday, December 29, 2007

Securing All Of A Host's Network Programs At Once Using Extended ACL's

At most shops where I've worked, a lot of time and effort is put into securing this and that network service from certain users. Mostly, it's done on a per process basis. Like segregating Telnet or RSH, since those are considered insecure. But, for the most part, I find, what security folk really want to do, when locking down a box, is to prevent regular users from running any network commands, and only allow certain people in certain groups to avail themselves of those services. This can be likened to most firewall setups: Block everything and allow what you need to, as opposed to allowing everything and blocking what you find out is dangerous (which can be disastrous)

This is actually very simple to accomplish on both Linux and Solaris by using simple group permissions and File ACL's (or facl's). In this post we'll walk, step by step, through setting up a box with network services totally locked down for any users that we don't explicitly want to use them. Here we go:

First, you'll want to work on the group angle. All users are already members of a group (or groups) and these groups are used to limit (or augment) their access to certain areas of the OS and certain programs. For our purposes here, we'll set up an additional group. We'll call it noudptcp for kicks (since we're not going to let anyone who has this group as their primary group use any udp or tcp-based programs). We'll set it up just like any other group, like so:

bash@host # groupadd -g 999 noudptcp

Next, we'll visit the two critical files that we'll need to change in order to pull this all together in the next few steps: /dev/udp and /dev/tcp. They should look like this by default:

bash@host # ls -lL /dev/udp /dev/tcp
crw-rw-rw- 1 root sys 41, 0 Oct 2 2006 /dev/udp
crw-rw-rw- 1 root sys 42, 0 Oct 2 2006 /dev/tcp


Note that both of these character special files (device drivers) are readable and writable by everyone. This is one of the reasons any user can use Telnet, RSH, SSH and many other network-based programs on your system. Here, we'll run the getfacl command to view the ACL for the /dev/tcp device driver file and take a look at it, like so:

bash@host # getfacl /dev/tcp

# file: /dev/tcp
# owner: root
# group: sys
user::rw-
group::rw- #effective:rw-
mask:rw-
other:rw-


Then, we'll augment the ACL on both files (they're essentially the same) my favorite way. I like to just take the output of getfacl, modify it in a file, and then feed that file to setfacl (Note that I'm doing this on Solaris and that I will point out the differences for Linux along the way - for instance, the Linux getfacl output will look slightly different than this, but you can still dump it to a file and modify it), like so:

bash@host # cat FACL_FILE <--- We'll assume I already edited it, because that's so hard to emulate using a simple keyboard ;) -- Note also that I've removed the comments, as they don't get applied by setfacl and may be confusing.

user::rw-
group::rw- #effective:rw-
group:noudptcp:--- #effective:---
mask:rw-
other:rw-


Now, we feed this file to setfacl (Note that we only added the one extra line to set permissions for the noudptcp group) and the ACL will be updated so that members of the noudptcp group won't have any access to either /dev/tcp or /dev/udp (In Linux, use -M instead of -f):

bash@host # setfacl -f FACL_FILE /dev/tcp
bash@host # setfacl -f FACL_FILE /dev/udp


And now we can use getfacl to show the new permissions. In the "ls -lL" output, you'll notice the "+" at the end of the file listing, indicating that the default ACL has been modified, and the output of the getfacl command will be the same as our FACL_FILE, with the comments added by default:

bash@host # ls -lL /dev/udp /dev/tcp
crw-rw-rw-+ 1 root sys 41, 0 Oct 2 2006 /dev/udp
crw-rw-rw-+ 1 root sys 42, 0 Oct 2 2006 /dev/tcp
bash@host # getfacl /dev/tcp

# file: /dev/tcp
# owner: root
# group: sys
user::rw-
group::rw- #effective:rw-
group:noudptcp:--- #effective:---
mask:rw-
other:rw-


Finally, all we have to do is add any users we deem necessary to the noudptcp group and they will not be able to access any network services! Note that this will not prevent them from connecting "to" the box; it will just prevent them from connecting to another box from your box, or using ping, or any program that needs to access /dev/tcp or /dev/udp.

For instance, a few select lines of truss output show what happens when a user in the noudptcp group attempts to SSH off of the box:

open("/dev/udp", O_RDONLY) Err#13 EACCES
so_socket(2, 2, 0, "", 1) Err#13 EACCES
write(2, 0xFFBEF058, 27) = 27
s o c k e t : P e r m i s s i o n d e n i e d\r\n


Congratulations! Now everyone you don't want to be able to use network services on your box is no longer a threat. At least, not in that way ;) And, even better, they can still use everything else that they would normally be allowed to!

Cheers,

, Mike