Unix permissions are flexible and can solve almost any access control problem, but what about the ones they can't?
Do you really want to make a group every time you want to share a file with another user? What if you don't have root access and can't create a group at will? What if you want to be able to make a directory available to a web server or other user without making the files world-readable or -writable? Root-owned configuration files often need to be edited by those without root privileges; instead of using a program like sudo (see [Hack #61] and [Hack #62] ), it would be better just to allow certain nonowners to edit these files.
Access Control Lists (ACLs) solve these problems. They allow more flexibility than the standard Unix user/group/other set of permissions. ACLs have been available in commercial Unixes such as IRIX and Solaris, as well as Windows NT, for years. Now, thanks to the TrustedBSD project's work, ACLs are available in FreeBSD 5.0-RELEASE and beyond.
ACLs take care of access control problems that are overly complicated or impossible to solve with the normal Unix permissions system. By avoiding the creation of groups and overuse of root privileges, ACLs can keep administrators saner and servers more secure.
6.3.1 Enabling ACLs
ACLs are enabled by an option in the file system superblock, which contains internal housekeeping information for the file system.
Edit the superblock with the tunefs command, which can be used only on a read-only or unmounted file system. This means that you must first bring the system into single-user mode. Make sure there aren't any active connections to the system, then shut it down:
# shutdown now *** FINAL System shutdown message from firstname.lastname@example.org *** System going down IMMEDIATELY Dec 11 10:28:07 genisis shutdown: shutdown by root: System shutdown time has arrived Writing entropy file:. Shutting down daemon processes:. Saving firewall state tables:. Dec 11 10:28:10 genisis syslogd: exiting on signal 15 Enter full pathname of shell or RETURN for /bin/sh: #
At the prompt, type:
# /sbin/tunefs -a enable / # /sbin/tunefs -a enable /usr # exit
If you use the UFS2 file system, you are done. The UFS_ACL option is enabled in the default GENERIC kernel, so reboot and enjoy. If you use UFS1, though, don't reboot yet.
6.3.2 Additional UFS1 Configuration
Things are more difficult if you, like most FreeBSD 5.0 users, use UFS1. (FreeBSD 5.1 and later come with UFS2 as the default file system.) ACLs are built on top of extended attributes, which are not native to UFS1. To enable extended attributes, you must add options UFS_EXTATTR and options UFS_EXTATTR_AUTOSTART to your kernel configuration and compile and install the new kernel [Hack #54] . Don't reboot yet; you still need to initialize the extended attributes on each file system.
For example, to initialize extended attributes on the /var filesystem, use extattrctl, the extended attributes control command:
# mkdir -p /var/.attribute/system # cd /var/.attribute/system # extattrctl initattr -p /var 388 posix1e.acl_access # extattrctl initattr -p /var 388 posix1e.acl_default
Repeat for each filesystem on which you wish to enable ACL support. Just replace /var with the mount point of the desired file system. After initializing the attributes with reboot, the extended attributes should be enabled.
6.3.3 Viewing ACLs
Okay, you've successfully enabled ACLs. Now what? Let's start by viewing ACLs. Looking at ACLs is simple. Files with ACLs will be designated with a + in the long listing provided by ls -l:
% ls -l acl-test -rw-rw-r--+ 1 rob rob 0 Apr 19 17:27 acl-test
Use the getfacl command to see information about the ACL:
% getfacl acl-test #file:acl-test #owner:1000 #group:1000 user::rw- user:nobody:rw- group::r-- group:wheel:rw- mask::rw- other::r--
The user::, group::, and other:: fields should all be familiar. They are simply the ACL representations of the standard Unix permissions system. The nobody and wheel lines, however, are new. These specify permissions for specific users and groups (in this case, the nobody user and the wheel group) in addition to the normal set of permissions.
The mask field sets maximum permissions, so an r-- mask (set with m::r) in combination with an rw- permission for a user will give the user only r-- permissions on the file.
6.3.4 Adding and Subtracting ACLs
The setfacl command adds, changes, and deletes ACLs. Like chmod, only the file's owner or the superuser can use this command. You only need to use a few of its options to start manipulating ACLs.
First, a word on syntax. ACLs are specified just as they're printed by getfacl. Let's remove and reconstruct the ACL for acl-test:
% setfacl -b acl-test % setfacl -m user:nobody:rw-,group:wheel:rw- acl-test
The -b option removes all ACLs, except for the standard user, group, and other lines. The -m option modifies the ACL with the specified entry (or comma-separated entries). Entries may also be abbreviated: the code here could have been shortened to u:nobody:rw-,g:wheel:rw-.
You can even use setfacl to modify traditional permissions; setting a user::rw- ACL entry is equivalent to running chmod u=rw on a file.
Removing ACLs is almost identical: setfacl -x u:nobody:rw-,g:wheel:rw- removes that ACL. You can also specify ACLs in files. The -M and -X options perform the functions of their lowercase relatives, but read their entries from a file. Consider the acl-test file again:
% cat test-acl-list u:nobody:rw- # this is a comment g:wheel:rw- % setfacl -X test-acl-list acl-test % getfacl acl-test #file:acl-test #owner:1000 #group:1000 user::rw- group::r-- mask::r-- other::r--
6.3.5 Using ACLs with Samba and Windows
If you compile Samba with ACL support, you can edit ACLs on files shared by Samba with the native Windows ACL tools. Simply compile (or recompile) Samba with ACL support:
# cd /usr/ports/net/samba # make -DWITH_ACL_SUPPORT install clean
You will see the Samba port configuration dialog with ACL support enabled, as shown in Figure 6-1.
Figure 6-1. Configuring Samba with ACLs
Once you have Samba up and running, browse to a share on an ACL-enabled file system. Right-click any file and select Properties, and you'll see something like Figure 6-2. Go to the Security tab, and you can see and change the ACL as though it were on a Windows server.
Figure 6-2. Manipulating ACLs on FreeBSD from a Samba client
If you've been reluctant to move from a Windows server to Samba because of its lack of ACLs, you can start thinking seriously about deploying Samba and FreeBSD on your file servers.
6.3.6 Setting Default ACLs
Let's consider a more advanced example. You want to make your cool_widgets directory accessible to Bob, your partner in coolness, but not to the world. If you just add an ACL entry, added files won't automatically pick up the directory's ACL. You should instead set a default ACL on the directory. Any files created in the directory will inherit the default ACL.
Passing the -d option to either getfacl or setfacl will operate on the default ACL of a directory, instead of on the directory itself:
% mkdir cool_widgets % chmod o-rwx cool_widgets % ls -l drwxr-x--- 2 rob rob 512 Apr 19 21:21 cool_widgets % getfacl -d cool_widgets #file:cool_widgets #owner:1000 #group:1000
Pretty boring, isn't it? Let's try to add a default ACL:
% setfacl -d -m u:bob:rw- cool_widgets setfacl: acl_calc_mask( ) failed: Invalid argument setfacl: failed to set ACL mask on cool_widgets
Oops. Default ACLs don't work quite like regular ACLs do. You cannot set specific entries on a default ACL until you add the generic user::, group::, and other:: entries:
% setfacl -d -m u::rw-,g::r--,o::---,u:bob:rw- cool_widgets % setfacl -m u:bob:r-x cool_widgets
Note the nondefault r-x entry for bob on the directory. The default ACL affects files that will be created inside the directory but not the directory itself. An ACL entry u:bob:rw- will now be added to any file created in cool_widgets.
Now you have a cool_widgets directory whose files can be read and written by both yourself and Bob, without the use of a group. If you later decide to get rid of the default ACL, the -k option to setfacl works for directory ACLs just as the -b option does for file ACLs.
6.3.7 See Also