15.4 Access Control in UFS
The traditional UNIX File System provides a simple file access scheme based on users, groups, and world, whereby each file is assigned an owner and a UNIX group, and then is assigned a bitmap of permissions for user, group, and world, as illustrated in Figure 15.15.
Figure 15.15 Traditional File Access Scheme
This scheme is flexible when file access permissions align with users and groups of users, but it does not provide a mechanism to assign access to lists of users that do not coincide with a UNIX group. For example, if we want to give read access to file 1 to Mark and Chuck, and then read access to file 2 to Chuck and Barb, then we would need to create two UNIX groups, and Chuck would need to switch groups with the chgrp command to gain access to either file.
To overcome this drawback, some operating systems use an access control list (ACL), whereby lists of users with different permissions can be assigned to a file. Solaris introduced the notion of access control lists in the B1 secure version, known as Trusted Solaris, in 1993. Trusted Solaris ACLs were later integrated with the commercial Solaris version in 1995 with Solaris 2.5.
With Solaris ACLs, administrators can assign a list of UNIX user IDs and groups to a file by using the setfacl command and can review the ACLs by using the getfacl command, as shown below.
# setfacl -m user:jon:rw- memtool.c # getfacl memtool.c # file: memtool.c # owner: rmc # group: staff user::r-- user:jon:rw- #effective:r-- group::r-- #effective:r-- mask:r-- other:r-- # ls -l memtool.c -r--r--r--+ 1 rmc staff 638 Mar 30 11:32 memtool.c
For example, we can assign access to a file for a specific user by using the setfacl command. Note that the UNIX permissions on the file now contain a +, signifying that an access control list is assigned to this file.
Multiple users and groups can be assigned to a file, offering a flexible mechanism for assigning access rights. ACLs can be assigned to directories as well. Note that unlike the case with some other operating systems, access control lists are not inherited from a parent, so a new directory created under a directory with an ACL will not have an ACL assigned by default.
ACLs are divided into three parts: on-disk, in-core, and user level. On-disk format is used to represent the ACL data that is stored in the file's shadow inode, in-core structure is used by UFS internally, and the user-level format is used by the system to present data to the requester.
The ufs_acl structure defines an ACL entry that is encapsulated in the ufs_fsd structure and then stored on disk in a shadow inode. Refer to Section 15.2.4 for more information on shadow inode storage.
/* * On-disk UFS ACL structure */ typedef struct ufs_acl { union { uint32_t acl_next; /* Pad for old structure */ ushort_t acl_tag; /* Entry type */ } acl_un; o_mode_t acl_perm; /* Permission bits */ uid_t acl_who; /* User or group ID */ } ufs_acl_t; See usr/src/uts/common/sys/fs/ufs_acl.h
The in-core format consists of the ufs_ic_acl structure and the in-core ACL mask (ufs_aclmask) structure.
/* * In-core UFS ACL structure */ typedef struct ufs_ic_acl { struct ufs_ic_acl *acl_ic_next; /* Next ACL for this inode */ o_mode_t acl_ic_perm; /* Permission bits */ uid_t acl_ic_who; /* User or group ID */ } ufs_ic_acl_t; /* * In-core ACL mask */ typedef struct ufs_aclmask { short acl_ismask; /* Is mask defined? */ o_mode_t acl_maskbits; /* Permission mask */ } ufs_aclmask_t; See usr/src/uts/common/sys/fs/ufs_acl.h
When ACL data is exchanged to and from the application, a struct acl relays the permission bits, user or group ID, and the type of ACL.
typedef struct acl { int a_type; /* the type of ACL entry */ uid_t a_id; /* the entry in -uid or gid */ o_mode_t a_perm; /* the permission field */ } aclent_t; See usr/src/uuts/common/sys/acl.h
The following routines are available in UFS to manipulate ACLs.
static int ufs_setsecattr(struct vnode *vp, vsecattr_t *vsap, int flag, struct cred *cr) Used primarily for updates to ACLs. The structure vsecattr is converted to ufs_acl for in-core storage of ACLs. All file mode changes are updated via this routine. static int ufs_getsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,struct cred *cr) If ACL data is present, it is converted to vsecattr. Otherwise a new entry is created from the mode bits and returned. int ufs_acl_access(struct inode *ip, int mode, cred_t *cr) Checks the inode's ACLs to see if access of type mode is allowed. int ufs_acl_get(struct inode *ip, vsecattr_t *vsap, int flag, cred_t *cr) Called by ufs_getsecattr() to obtain ACL information. int ufs_acl_set(struct inode *ip, vsecattr_t *vsap, int flag, cred_t *cr) Called by ufs_setsecattr() to set the inode's ACL information. si_t * ufs_acl_cp(si_t *sp) Copies ACL information from one shadow inode into a new created shadow inode. int ufs_acl_setattr(struct inode *ip, struct vattr *vap, cred_t *cr) Sets the inode's ACL attributes. usr/src/uuts/common/fs/ufs/ufs_acl.c