|  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.
           |