This chapter discusses the following topics:
Note
The ACL library routines (-lpacl) are not thread safe.
The Digital UNIX ACLs are based on the POSIX P1003.6 Draft 13 standard. The ACL library routines may change in the final version of the standard.
Aaccess control lists (ACLs) are the method used to implement discretionary access control (DAC). ACLs provide a more granular discretionary access control mechanism than traditional UNIX permission bits. All objects are considered to be protected by an ACL. An object protected by traditional UNIX DAC has a base entry ACL. If additional entries are added to the ACL, they are evaluated according to entry type by rules defined by the POSIX specification.
The POSIX ACL policy has been defined by the POSIX P1003.6 DAC security specification and features the following:
In addition to the POSIX ACLs, Digital UNIX provides enhanced library interfaces.
You can apply ACLs to any traditional UNIX file system object that has permission bits that are used for access control, such as files and directories. Symbolic links have permission bits that are initialized according to the usual rules but are never used for access control; ACLs on this file type are not supported. The guidelines in this chapter apply to all objects that may be protected by ACLs.
Refer to the acl(4) reference page for a description of POSIX ACL support.
Table 21-1 lists the ACL library routines:
Routine | Description |
acl_add_perm() | Add a set of permissions |
acl_clear_perm() | Clear the permissions |
acl_convert_posix() | Remove non-POSIX entries from an ACL |
acl_copy_entry() | Copy an ACL entry |
acl_copy_ext() | Copies an ACL from system to user space |
acl_copy_int() | Copies an ACL from user to system space |
acl_create_entry() | Create a new ACL entry |
acl_delete_def_fd() | Delete the default ACL from a directory |
acl_delete_def_file() | Delete the default ACL from a file |
acl_delete_entry() | Delete an entry |
acl_delete_perm() | Delete a set of permissions |
acl_dup() | Create a duplicate ACL |
acl_first_entry() | Move current entry to first entry |
acl_free() | Free the ACL working storage memory |
acl_free_qualifier() | Free the acl_id entry in an ACL |
acl_free_text() | Free the ACL text working storage memory |
acl_from_text() | Convert the text ACL to the internal representation |
acl_get_entry() | Get the descriptor to an ACL |
acl_get_fd() | Get ACL using the file descriptor |
acl_get_file() | Retrieve an ACL |
acl_get_permset() | Retrieve the permissions for an ACL |
acl_get_qualifier() | Retrieve the ID from the current ACL |
acl_get_tag_type() | Retrieve the entry type identifier |
acl_init() | Allocate and initialize ACL working storage |
acl_locate_entry() | Locate an entry in an ACL |
acl_set_fd() | Set the ACL by the file descriptor |
acl_set_file() | Set the ACL by the pathname |
acl_set_permset() | Set permissions in a ACL entry |
acl_set_qualifier() | Set the ACL entry type |
acl_set_tag_type() | Set the ACL entry type |
acl_size() | Determine the size of an ACL |
acl_to_text() | Convert an IR to an ASCII string |
acl_validate_and_sort() | Check ACL for validity and sort for decision order |
Table 21-2 describes the terms used with discretionary access to objects:
Term | Definition |
Read access | Either the subject is granted read permission by the object's mode and ACL, or the subject is root. |
Write access | Either the subject is granted write permission by the object's mode and ACL, or the subject is root. |
Execute access | Either the subject is granted execute permission by the object's mode and ACL, or the subject is root. |
Search access | Either the subject is granted search permission by the directory's mode or the subject is root. |
Owner access | Either the subject's EUID is the same as the object's UID, or the subject is root. |
Two internal ACL data structures are defined by the POSIX specification. In addition, there is a textual representation for ACLs that is presented to the user. You must be careful not to mix data structures when using the ACL system calls and library routines.
All data representations use the following basic types, most of which are required by the POSIX ACL specification:
typedef unsigned short acl_tag_t; typedef unsigned short acl_permset_t;
/* acl_tag_t values */
#define BOGUS_OBJ 0 #define USER_OBJ 1 #define USER 3 #define GROUP_OBJ 4 #define GROUP 5 #define OTHER_OBJ 6
/* acl_permset_t values */
#define ACL_NOPERM 0x0 #define ACL_PEXECUTE 0x1 #define ACL_PWRITE 0x2 #define ACL_PREAD 0x4
/* tag qualifier type */
typedef union { uid_t _acl_uid; gid_t _acl_gid; } acl_id;
Many of the ACL routines operate on the working storage representation, which is a set of opaque data structures for ACLs and ACL entries. Your program should operate on these data structures only through the defined routines. Because the working storage data structures are subject to change, the interface is the only reliable way to access the data.
The working storage representation is not contiguous in memory. Also, your program cannot determine the sizes of ACL entries and ACL descriptors. The working storage data structures contain internal pointer references and are therefore meaningless if passed between processes or stored in a file. The working storage representation of an ACL can be converted to other representations of an ACL, as described in Section 21.4.2.
The data package represents an ACL in a contiguous section of memory that is independent of the process address space in which it resides. The data package can be passed between processes or stored in a file because it is contiguous and does not have internal pointer references.
The data structure associated with the data package is visible at the programmer interface. It contains a header that includes the number of entries in the ACL and a magic number to identify the data structure type, followed by an array of ACL entries that contain the tag type, permissions, and qualifier.
The following structure describes the header:
/* * Header for data package type. */
typedef struct { ushort acl_num; ushort acl_magic; } aclh_t;
In addition to including the header, the data structure for the data package includes an array of ACL entries of the following format:
/* * Descriptor for a specific ACL entry * in internal representation. */ typedef struct { acl_tag_t acl_tag; acl_permset_t acl_perm; acl_id acl_id; } acle_t; /* * Descriptor for specific ACL entry * in (data package format). */ struct acl_data { aclh_t acl_hdr; /* acle_t *acl_entry; comment; acl entries follow */ }; typedef struct acl_data *acl_data_t;
The following code fragment operates on all entries in a data package ACL representation:
acl_data_t data_p; acle_t *entry_p; int i;
entry_p = (acle_t *) (data_p + 1); /* The pointer arithmetic addresses the first acl entry.*/ for (i = 0; i < data_p->acl_num; i++, entry_p++) { /* reference the ACL entries through entry_p */ }
The external representation is a textual, human readable version of the ACL that corresponds to the text package described in the POSIX specification and the acl(4) reference page. The external representation is composed of a sequence of lines, each of which is terminated by a newline character. Table 21-3 shows how the individual entries are structured.
Entry Type | acl_tag_t Value | Entry |
base user | USER_OBJ | user::perms |
base group | GROUP_OBJ | group::perms |
base other | OTHER_OBJ | other::perms |
user | USER | user:user_name:perms |
group | GROUP | group:group_name:perms |
The external representation is used by the POSIX routines that convert between the working storage representation and the text package.
The POSIX specification allows a default access ACL to be associated with directories. When a directory has a default access ACL, files and directories created in the directory are protected with DAC attributes that are derived from the default ACL and the mode that is specified on the object creation system call. You can set a default access ACL on a directory by using the acl_write() call with a second argument of ACL_TYPE_DEFAULT. You can retrieve a default ACL by using the acl_read() call with a second argument of ACL_TYPE_DEFAULT.
Note that, although the system consults the owner and group of the directory when it is checking for access against the access ACL, the owner and group are not inherited from the default access ACL when a file is created in a directory that has a default access ACL. The default access ACL does not include an owner and group ID. Rather, the base user and group entries include permissions that are used when computing the access ACL for a file; the file owner is set from the process and the group is inherited from the parent directory.
The Digital UNIX system provides an extension of the POSIX ACLs in the form of an added default directory ACL type that can be used by other ACL implementations (for example, the Distributed Computing Environment (DCE)). This ACL is ACL_TYPE_DEFAULT_DIR and is used for directories only. If a parent directory has ACL_TYPE_DEFAULT_DIR, then new directories are set to the parents ACL_TYPE_DEFAULT_DIR.
The inheritance rules are described in detail in the acl(4) reference page and Section 5.9 of this manual.
Some interactions between the ACL and the UNIX permissions are subtle, and you may end up with different permissions than you intended because of the way that ACL system calls interact with the system calls that manipulate the UNIX DAC attributes.
The following sections describe rules for programs that handle ACLs.
When copying one file to another, it is a common practice for a program to create a new file and propagate the owner, group, and mode. The program must now handle the possibility that the file may also be protected by an ACL. Your program should propagate the ACL in all cases where the UNIX DAC attributes would be propagated.
When the parent directory of the file to be created has a default ACL, the owner of the created file is inherited from the process and the group is inherited from the parent directory. In addition, the specified mode is used instead of the process umask. Therefore, your program must specify a proper mode on the object creation system call and must not depend on the umask to properly protect objects.
ACLs are preserved automatically in programs that replicate permissions.
The ACL must be valid according to the following POSIX ACL rules:
Assume that you want to set up a file's access ACL as follows:
user::rwx user:june:r-x user:sally:r-x
group::rwx group:mktg:rwx
other::r-x
The following code takes the tabular form of the ACL, creates a working storage representation of the ACL, and applies it to a file.
struct entries { acl_tag_t tag_type; char *qualifier; acl_permset_t perms; } table[] = { { USER_OBJ, NULL, ACL_PRDWREX }, { USER, "june", ACL_PRDEX }, { USER, "sally", ACL_PRDEX }, { GROUP_OBJ, NULL, ACL_PRDWREX }, { GROUP, "mktg", ACL_PRDWREX }, { OTHER_OBJ, NULL, ACL_PRDEX } };
#define TABLE_ENTRIES (sizeof(table)/sizeof(table[0]))
acl_t acl_p; acl_entry_t entry_p; int i; uid_t uid; gid_t gid;
/* allocate an ACL */ acl_alloc(&acl_p); [1]
/* walk through the table and create entries */ for (i = 0; i < TABLE_ENTRIES; i++) {
/* allocate the entry */ acl_create_entry(acl_p, &entry_p); [2]
/* set the permissions */ acl_set_perm(entry_p, table[i].perms);
/* setting the tag type and qualifier depends on the type */ switch (table[i].tag_type) {
case USER:
/* map user name to ID and specify as qualifier */
uid = pw_nametoid(table[i].qualifier); [3] acl_set_tag(entry_p, table[i].tag_type, (void *) uid); [4]
break;
case GROUP:
/* map group name to ID and specify as qualifier */
gid = gr_nametoid(table[i].qualifier); [5] acl_set_tag(entry_p, table[i].tag_type, (void *) gid); break;
default:
/* qualifier is NULL for other types */
acl_set_tag(entry_p, table[i].tag_type, NULL); break; } }
/* set the ACL on the file */
if (acl_write(filename, ACL_TYPE_ACCESS, acl_p) < 0) perror(filename);
/* free storage allocated for the ACL */
acl_free(acl_p);
Notes:
When imported and exported objects with ACLs are accessed, several issues arise that vary depending on the scenario.
From a Digital UNIX system to the same Digital UNIX system, the ACL does not have to be converted from the internal to the external format. It can be saved in its compacted data format. This saves the effort of having to convert the ACL from the external to internal format and back.
If the two Digital UNIX systems have the exact same password and group files (that is, these files are distributed using NIS or some other means), then saving the ACL is done the same as from a Digital UNIX system to the same Digital UNIX system. If the systems do not share the same password and group files, then the ACLs must be converted to the external format when backing up. If this is not done, unintended access may be granted to the files being restored. Also, this ensures that all the UIDs and GIDs are known.
If you are exporting data to another machine, the remote system's ACL policy needs to be based on Draft 13 of POSIX P1003.6 (or something compatible).
When importing data containing ACLs from another vendor's machine, the ACL format must be based on Draft 13 of POSIX P1003.6. The ACL is validated and then set on the object if valid. If the ACL cannot be set on the object being restored, 0700 is added to the standard UNIX permissions.