Achieving
More Flexible File Permissions Using Solaris ACLs
Ross Oliver
The fixed set of UNIX file permissions for owner, group, and world
is simple to understand and easy to manage. However, the simplicity
of this scheme is also its most frustrating limitation. Most UNIX
systems administrators have at one time or another wished for just
one more set of permissions to accomplish some necessary task.
Traditional workarounds include multiple user accounts, multiple
group memberships, and set-UID programs. Although these methods
work, they are not ideal because they add complexity, require root
access to implement, and often raise security problems.
In the Solaris world, these limitations were finally overcome
with the introduction of Access Control Lists (ACLs). Introduced
in Solaris 2.5, ACLs are additional sets of read/write/execute triplets
that can be added on to files, directories, devices, or any other
file system objects. Using ACLs, systems administrators as well
as ordinary users can now fine-tune access without resorting to
multiple groups or set-UID programs. This article is a practical
look at how to use ACLs on a real network.
Managing ACLs
In the fine UNIX tradition, the utilities to manage ACLs have
the awkward but utilitarian names getfacl and setfacl
(I pronounce them GET-fakle and SET-fakle). getfacl takes
file names as command-line arguments, and outputs a textual representation
of all ACLs currently in place for the named files. setfacl
accepts command-line options to install, modify, or remove ACLs.
Here is an example of getfacl output for a file named "samplefile"
that has no ACLs, only the standard UNIX permissions:
$ getacl samplefile
# file: samplefile
# owner: reo
# group: sysadmin
user::rw-
group::r-- #effective:r--
mask:r--
other:r--
The "user," "group," and "other" fields
correspond to the standard UNIX permission bits. The "mask"
field works like a real-time umask, screening off unwanted access
for "group" and "other." So, if "other"
were set to rwx, and "mask" set to ---, the
effective permissions for "other" would be ---.
To give the user "tdk" write permission on the above
file, the setfacl command line would be:
$ setfacl -m user:tdk:rw- samplefile
$ getacl samplefile
# file: samplefile
# owner: reo
# group: sysadmin
user::rw-
user:tdk:rw- #effective:r--
group::r-- #effective:r--
mask:r--
other:r--
Note the new "user:tdk" entry, and the "#effective"
field, which displays the combined results of the user permissions
and the mask. In this case, #effective indicates the mask must be
changed for the new ACL to have the desired effect:
$ setfacl -m mask:rw- samplefile
$ getacl samplefile
# file: samplefile
# owner: reo
# group: sysadmin
user::rw-
user:tdk:rw- #effective:rw-
group::r-- #effective:r--
mask:rw-
other:r--
To indicate the presence of ACLs, Sun modified the format of the ls
-l command so that a "+" character is displayed immediately
to the right of the standard file permissions. For the example file
above, ls -l would show:
$ ls -l samplefile
-rw-rw-r--+ 1 reo sysadmin 6242 Dec 14 15:16 samplefile
Putting ACLs into Practice
Consider that Department Director Laura F. is going on a 2-week
vacation to a South Pacific island that has never heard of email.
Laura would like to give her deputy, James K., read-only access
to her mailbox so he can monitor for any emergencies. At first,
the sys admin is stumped for a solution. She cannot change the group
of Laura's mailbox file; all mailbox files must be in the "mail"
group for the mail delivery agent to function properly:
$ ls -l /usr/spool/mail/lauraf
-rw-rw---- 1 laurak mail 3448683 Aug 21 12:10 /usr/spool/mail/lauraf
The sys admin also rules out making Laura's mailbox publicly
readable, as this would risk exposing sensitive information. Two other
possiblities are similarly unpalatable: adding James to the "mail"
group, or giving him direct access to Laura's account. Finally,
the sys admin remembers an article she read about Solaris ACLs. She
uses setfacl to grant James read-only access to Laura's
mailbox file:
$ setfacl -m user:jamesk:r-- /usr/spool/mail/lauraf
$ getacl /usr/spool/mail/lauraf
# file: /usr/spool/mail/lauraf
# owner: lauraf
# group: mail
user::rw-
user:jamesk:r-- #effective:r--
group::rw- #effective:rw-
mask:r--
other:r--
Thus, functionality and security are preserved, James can monitor
Laura's email, leaving the nightlong beating of native drums
as Laura's only worry.
This example illustrates one of the most useful aspects of ACLs.
They provide the ability to grant access to files in situations
where changing existing permissions or groups would compromise security,
or disrupt the functionality of an existing application.
Default ACLs and Directories
The previous example showed how ACLs can be installed onto existing
files. Is there a way to specify ACLs for files that will be created
in the future? The "default" ACL serves this purpose.
Default ACLs are permitted only on directories, and specify ACLs
that new files will inherit when created within those directories.
Here is a directory that has default ACLs:
$ getfacl sampledir
# file: sampledir
# owner: reo
# group: sysadmin
user::rwx
group::r-x #effective:r-x
mask:r-x
other:r-x
default:user::r-x
default:group::r-x
default:mask:rwx
default:other:r-x
default:user:tdk:rw-
Note that getfacl still reports a type of "file"
even on a directory.
When a file is created in "sampledir", it will automatically
receive the default ACLs from its parent directory as its user,
group, mask, and other ACLs.
This table shows how the default ACLs on the directory "sampledir"
map onto files created in that directory:
ACLs on sampledir ACLs on new files created in sampledir
default:user::r-x -> user::r-x
default:group::r-x -> group::r-x
default:mask:rwx -> mask:rwx
default:other:r-x -> other:r-x
default:user:tdk:rw- -> user:tdk:rw-
Note that setfacl will not allow creation of user- or group-specific
defaults (e.g., default:user:tdk:rw-) unless the directory
already has the four generic defaults. The next example shows the
commands used to manage default ACLs.
Default ACLs in Practice
The fictitious accounting firm of Dewey, Cheetam and Howe (DCH)
has arranged for several clients to transmit their weekly payroll
data via FTP to DCH's Solaris FTP server. Once the data arrives,
Clark, the DCH's payroll clerk, retrieves the data files, also
using FTP. Because these files contain the clients' confidential
data, the clients must be allowed to read and write only their own
files. Additionally, Clark needs full access to all the client files.
Joe, the sys admin in charge of the implementation, has no trouble
meeting the first requirement. He creates a separate directory and
UNIX group for each client, setting the directory permissions accordingly.
However, the clerk's need for universal access poses a problem.
Because newgrp won't work with an FTP login, Joe can't
simply put the Clark's account in all the client groups. However,
by using ACLs, Joe can give Clark access to existing files in all
the client directories, as well as any files created in those directories
in the future.
$ mkdir client1dir
$ chgrp client1 client1dir
$ chmod 770 client1dir
$ ls -l client1dir
-rwxrwx--- 1 root client1 4096 Dec 14 15:16 client1dir
Before Joe can create any user-specific ACLs on the "client1dir"
directory, he must first install the non-specific defaults. All four
non-specific defaults (user, group, other, and mask) must be set simultaneously
in one setfacl command. To make the command line more manageable,
Joe takes advantage of setfacl's recognition of single-letter
abbreviations of the ACL attributes:
$ setfacl -s \
u::rwx,g::rwx,o:---,m:rwx,d:u::rw-,d:g::rw-,d:o:---,d:m:rw clientdir
Finally, Joe adds the user-specific default ACL for Clark's access:
$ setfacl -m default:user:clark:rw- client1dir
Here are the final permissions on the directory "client1dir",
as shown by getfacl:
$ getfacl client1dir
# file: client1dir
# owner: root
# group: client1
user::rwx
group::rwx #effective:rwx
mask:rwx
other:---
default:user::---
default:user:clark:rw-
default:group::---
default:mask:rw-
default:other:---
The default ACL entries do not affect access to the "client1dir"
directory itself. If Clark's account is not a member of the "client1"
group, Joe will also need to add another ACL to the directory to give
Clark read, write, and search access to the "client1dir"
directory:
$ setfacl -m user:clark:rwx client1dir
$ getfacl client1dir
# file: client1dir
# owner: root
# group: client1
user::rwx
user:clark:rwx #effective:rwx
group::rwx #effective:rwx
mask:rwx
other:---
default:user::---
default:user:clark:rw-
default:group::---
default:mask:rw-
default:other:---
Whenever a new file is created in the "client1dir" directory,
it will have the owner and group of the creating account, but will
also automatically receive an ACL allowing Clark read and write access.
Joe tests this out to be sure:
$ touch client1dir/testfile
$ getfacl client1dir/testfile
# file: client1dir/testfile
# owner: root
# group: client1
user::rwx
user:clark:rw- #effective:rw-
group::rw- #effective:rw-
mask:rw-
other:---
Copying ACLs
It would be tedious and troublesome for Joe to repeat the above
process for each client directory. Fortunately, the -f option
to setfacl provides the ability to copy the entire set of
ACLs from one file (or directory) onto another. The -f option
tells setfacl to read ACLs from a file, in the same format
as output by getfacl.
The file name can be "-" to tell setfacl
to read ACLs from the standard input. Thus, Joe can duplicate the
ACLs from the "client1dir" directory onto "client2dir"
and other subsequent directories with one simple command:
$ getfacl client1dir | setfacl -f - client2dir
More ACL Uses
ACLs are also handy in delegating selected systems administration
tasks. This capability is especially useful in certain environments
that prohibit the use of non-commercial tools such as sudo.
For example, a common task to delegate is maintenance of the /etc/aliases
file. If available, sudo can be used to permit a non-root
user to invoke an editor on the /etc/aliases file. However,
this could be a serious security problem. Most editors allow shell
escapes and the execution of arbitrary commands, which would execute
at root privilege. This would bypass sudo security. A more
secure alternative would be to add an ACL to /etc/aliases
to allow the user to edit the file directly, with no need for root
privilege.
The fine-grained access control afforded by ACLs can be helpful
to ordinary users as well. For example, Fred needs to allow Carl
to access files in Fred's home directory, but Carl is not a
member in the group that owns Fred's home directory. Without
ACLs, Fred would have to make his home directory world readable
and searchable for Carl to access it. However, using an ACL, Fred
can grant full access to Carl alone, without opening up Fred's
home directory to everyone on the system.
Say What?
Even after so many years, UNIX programmers still have not learned
how to give their programs good table manners. The ACL management
utilities are no exceptions. So, here is your secret decoder card
for some of the most common crypto-errors from setfacl.
setacl error: Invalid argument
Root is no longer omnipotent. Only the owner of a file or directory
can add or change ACLs. If root tries to set an ACL on a non-root
file, setfacl will respond with this very helpful error message.
Missing user/group owner, other, mask entry
You used the -s option, but did not include the required user::,
group::, and mask:: entries.
Another cause of this message is attempting to add a user or group-specific
default ACL (e.g., default:user:reo:r-x) to a directory when
no non-specific default ACLs (e.g., default:user::r--) exist.
non-digit in id field
The user or group name in an ACL entry does not exist. If the name
is not found in /etc/password or /etc/groups, setfacl
will try to interpret the field as a numeric ID.
Unrecognized character found in mode field
setfacl found a character other than r, w, x,
or - in the permissions field. The message itself is not so
bad, but it would be much more helpful if setfacl specified
which position held the incorrect character.
Some parsing errors will cause setfacl to exit without
producing any error message. If setfacl is silent, but does
not appear to have done what you intended, check the exit status.
If it is non-zero, a parsing error may have occurred. One particular
error I noticed that will cause this behavior is an extraneous colon
character in certain ACLs, such as "other::rwx".
Conclusion
Access Control Lists augment the traditional UNIX file permissions
scheme to permit more flexibility and fine-grained control over
file access. ACLs are especially useful in situations where changing
or adding groups is not possible. Systems administrators no longer
need to resort to convoluted arrangements of multiple groups and
set-UID scripts to achieve the best balance of utility and security.
While ACLs may not be everyday tools, they are an excellent addition
to every Solaris sys admin's bag of tricks for those occasions
when the standard UNIX permissions just aren't enough.
Ross Oliver is Chief Technical Officer for the information
security consulting firm Information Warehouse! Inc. His 15 years
in the high-tech industry has included positions at E*TRADE, Sun
Microsystems, SGI, SCO, and Taos. When not flying a keyboard, Ross
can often be found navigating his Zlin 242L aircraft through California
skies. Ross can be reached at: reo@iwi.com.
|