This chapter contains the following information:
Tru64 UNIX access control lists (ACLs) are an optional extension to
the discretionary access control (DAC) traditionaly provided on a UNIX system.
Traditional UNIX DAC is the traditional UNIX permission bits; ACLs are an
extension of the UNIX permission bits.
A file or directory that has only the
permission bits may be considered an object with an ACL containing only the
three required or base entries that correspond to the
usr
,
group
, and
other
permission bits.
There are two types of ACLs:
An access ACL is associated with a file or directory, and is used to determine if a process may access the file or directory.
Default ACLs are associated with a directory. Default ACLs are used to determine the ACLs applied to new files and subdirectories created in the given directory. See Section 7.6 for more information.
The Tru64 UNIX ACL implementation is based on Draft 13 with some Draft 15 extensions of the POSIX P1003.6 standard.
ACLs can be applied to any file or directory on a file system that supports property lists. The file systems that support property lists are:
UFS
AdvFS
NFS (between Tru64 UNIX systems)
ACLs can be applied even if ACL processing is not enabled on the system; however, ACL access checks and default ACL inheritance do not take place.
See Security Administration for a more detailed description of using
and administering ACLs.
See the
acl
(4)proplist
(4)7.2 ACL Data Representations
An ACL has an internal and
an external representation.
The external representation consists of text
and is used to enter and display ACLs.
Library routines manipulate ACLs
in working storage in an internal representation that is only indirectly accessible
to the calling routine.
This internal representation can be interpreted with
the
acl.h
header file.
7.2.1 Internal Data Representation
The ACL routines manipulate 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, a 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. A program can convert the working storage representation of an ACL to other representations of an ACL.
The two types most commonly used to access the opaque data are
acl_t
, a pointer to type
acl
(the ACL structure),
and
acl_entry_t
, a pointer to an ACL entry structure.
Note
The structures in the following sections are opaque internal data structures that are subject to change. Always use the defined types and the supplied library routines to access these structures.
The internal representation uses the following basic types and data
structures.
7.2.1.1 typedef struct acl *acl_t;
The
acl_t
type is used to specify an internal (working
storage) format ACL.
struct acl { int acl_magic; /* validation member */ int acl_num; /* number of actual acl entries */ int acl_alloc_size; /* size available in the acl */ acl_entry_t acl_current; /* pointer to current entry in */ acl_entry_t acl_first; /* pointer to ACL linked list */ attribute_t *attr_data; /* Pointer to the attr data */ };
7.2.1.2 typedef struct acl_entry *acl_entry_t;
The
acl_entry_t
type is used to specify an entry
within an ACL.
struct acl_entry{ acle_t *entry; void *head; struct acl_entry *next; struct acl_entry *prev; int acl_magic; int size; };
7.2.1.3 typedef uint_t acl_type_t;
The ACL types supported are as follows:
#define ACL_TYPE_ACC 0 #define ACL_TYPE_ACCESS ACL_TYPE_ACC /* The ACL is an access ACL. The property list entry name for an access ACL is "DEC_ACL_ACC" */ #define ACL_TYPE_DEF 1 #define ACL_TYPE_DEFAULT ACL_TYPE_DEF /* The ACL is a default access ACL. The property list entry name for a default access ACL is "DEC_ACL_ACC" */ #define ACL_TYPE_DEF_DIR 2 #define ACL_TYPE_DEFAULT_DIR ACL_TYPE_DEF_DIR /* The ACL is a default directory ACL. The property list entry name for a default directory ACL is "DEC_ACL_DEF_DIR" */
acl_type_t
is used to specify the ACL type.
7.2.1.4 typedef uint acl_tag_t;
The
acl_tag_t
type is used to specify the tag ( the
type) of an ACL entry.
ACL entries with a tag type of
ACL_USER
or
ACL_GROUP
also have an associated tag qualifier.
The
tag qualifier is the ID of the user or group.
The ACL entry tag types supported
are:
#define ACL_USER_OBJ 0 /* entry that equates to the owning user permission bits. */ #define ACL_GROUP_OBJ 1 /* entry that equates to the owning group permission bits. */ #define ACL_OTHER 2 #define ACL_OTHER_OBJ ACL_OTHER /* entry that equates to the other permission bits. */ #define ACL_USER 23 /* entry specifying permissions for a given user. */ #define ACL_GROUP 24 /* entry specifying permissions for a given group. */
7.2.1.5 typedef uint_t acl_perm_t;
The
acl_perm_t
permission bit definitions are as
follows:
#define ACL_EXECUTE 0X001 #define ACL_WRITE 0X002 #define ACL_READ 0X004
7.2.1.6 typedef acl_perm_t *acl_permset_t;
The
acl_permset_t
type is used to point to the permissions
assigned to an ACL entry.
7.2.1.7 Contiguous Internal Representation ACL
There is also a contiguous persistent data type for an ACL.
This representation
should be used only when the internal format ACL must persist between processes.
7.2.2 External Representation
The human-readable external representation of an ACL consists of a sequence of lines, each of which is terminated by a new-line character. The POSIX routines use the external representation when converting between the working storage representation and the text package.
The external representation is described in Security Administration.
Table 7-1
shows the structure of individual entries.
Table 7-1: ACL Entry External Representation
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 ACL routines are contained in the
libpacl.a
library.
The ACL library routines are based on Draft 13 of the POSIX P1003.6 standard.
See the reference page for each individual routine for detailed information.
The following routines are used to get, set, and validate ACLs:
acl_valid
()Checks the specified internal representation ACL for valid format.
acl_delete_def_fd
()Deletes the default access ACL from the designated directory using the file descriptor.
acl_delete_def_file
()Deletes the default access ACL from the designated directory.
acl_get_fd
()Retrieves the internal representation of the specified ACL type associated with the specific file or directory using the file descriptor.
acl_get_file
()Retrieves the internal representation of the specified ACL type associated with the specific file or directory.
acl_set_fd
()Sets the specified ACL type on the given file or directory to the specified ACL internal representation using the file descriptor.
acl_set_file
()Sets the specified ACL type on the given file or directory to the specified ACL internal representation.
The following routines retrieve and manipulate ACL entries:
acl_copy_entry
()Copies an ACL entry into the memory provided.
acl_create_entry
()Creates an empty ACL entry for the given ACL, allocating memory as necessary.
acl_delete_entry
()Deletes the designated ACL entry from an ACL.
acl_first_entry
()Resets the
current ACL entry so that the next call to
acl_get_entry
()
returns the first entry.
acl_get_entry
()Returns a pointer to the next ACL entry of the given ACL.
The following routines retrieve and manipulate fields in an ACL entry:
acl_add_perm
()Adds a permission to a set of permissions belonging to an ACL entry.
acl_clear_perm
()Clears a permission in a given ACL entry.
acl_delete_perm
()Removes permissions from a set of permissions belonging to an ACL entry.
acl_get_permset
()Copies the permissions from a given ACL entry to the location provided.
acl_get_qualifier
()Returns a pointer to the tag qualifier (ID) associated with a given ACL entry.
acl_get_tag_type
()Copies the tag (type) from the given ACL entry to the location provided.
acl_set_permset
()Sets the permissions in a given ACL entry to the given permissions.
acl_set_qualifier
()Sets the tag qualifier (ID) of the specified ACL entry to the given UID or GID.
acl_set_tag_type
()Sets the tag (type) of the specified ACL entry to the given type.
The following routines manage working storage for the ACL manipulation:
acl_free
()Releases all working storage associated with the given ACL.
acl_free_qualifier
()Releases working storage associated with the given tag qualifier.
acl_free_text
()Releases the buffer associated with the given external representation (text) ACL.
acl_init
()Allocates and initializes ACL internal representation working storage.
acl_copy_ext
()Copies the working storage internal format ACL data to the contiguous persistent ACL format.
acl_copy_int
()Copies contiguous persistent ACL data to working storage.
acl_dup
()Creates a copy of the designated ACL. The copy is independent of the original entry.
acl_size
()Calculates the size of the given ACL.
The following routines convert ACLs between external and internal representations:
acl_from_text
()Creates an internal representation ACL from the given external representation (text) ACL.
acl_to_text
()Creates an external representation (text) ACL from the given internal representation ACL.
Some interactions between the ACL and the UNIX permissions are subtle. Unless you understand the interaction between ACL routines and the system calls that manipulate UNIX DAC attributes, you might get different permissions than you intended.
The following sections describe rules for programs that handle ACLs.
7.4.1 Object Creation
If ACLs are enabled and are supported on the file system, the
open
(),
creat
(), and
mkdir
()
functions perform ACL inheritance when creating a file or directory.
See
for a description of ACL inheritance.
When ACL inheritance is performed, the permissions on a created file
come from the mode you provide and the inherited ACL, not the
umask
.
Therefore, your program must set the mode when creating files
and directories.
The program must not depend on
umask
to
protect the files and directories.
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.
If the source
file has an ACL, your program should propagate that ACL to the target file
in all cases where the mode is propagated.
7.4.2 ACL Replication
Programs that replicate permissions must preserve the ACL.
The
discretionary protection of a file or directory is no longer described by
the owner, group, and permissions; it includes the ACL which is a superset
of the permissions.
Neglecting to copy the ACL could allow unintended access
to the file or directory.
7.4.3 ACL Validity
Any ACL you create must be valid according to the following POSIX ACL rules:
It must have at least the three base entries
The user entries must have unique valid qualifiers
The group entries must have unique valid qualifiers
The user and group identifiers must be valid
You can use the
acl_valid
() routine to check your
ACLs.
7.5 ACL Creation Example
Assume that you want to set a file's access ACL to the following permissions:
user::rwx user:june:r-x user:sally:r-x group::rwx group:mktg:rwx other::r-x
The following code takes a tabular form of the ACL,
creates a working storage representation of the ACL, and applies it to a file.
If you extract the following code into a file named
acl_example.c
, use the following command to compile it:
# cc -o acl_example -lpacl -lsecurity acl_example.c
#include <unistd.h> #include <sys/types.h> #include <prot.h> #include <errno.h> #include <sys/acl.h> struct entries { acl_tag_t tag_type; char *qualifier; acl_perm_t perms; } table[] = { /* An ACL must (at a minimum) have the three base */ /* entries that correspond to the permission bits */ { ACL_USER_OBJ, NULL, ACL_READ | ACL_WRITE | ACL_EXECUTE }, { ACL_USER, "june", ACL_READ | ACL_EXECUTE }, { ACL_USER, "sally", ACL_READ | ACL_EXECUTE }, { ACL_GROUP_OBJ, NULL, ACL_READ | ACL_WRITE | ACL_EXECUTE }, { ACL_GROUP, "mktg", ACL_READ | ACL_WRITE | ACL_EXECUTE }, { ACL_OTHER_OBJ, NULL, ACL_READ | ACL_EXECUTE }, }; #define TABLE_ENTRIES (sizeof(table)/sizeof(table[0])) main ( argc, argv ) int argc; char *argv[]; { acl_t acl_p; acl_entry_t entry_p; acl_entry_t check_p; int i, ret; uid_t uid; gid_t gid; /* Did the user enter a filename? */ if (argc != 2) { printf("Usage: %s filename\n",argv[0]); exit(1); } /* Check to see if ACLs are supported and enabled for filename */ ret = pathconf(argv[1], _PC_ACL_EXTENDED); /*[1]*/ if (ret == 1) { printf(" ACLs are enabled for file %s\n",argv[1]); } else if (ret == 0) { printf(" ACLs are supported for file %s,\n",argv[1]); printf(" but ACLs are not currently enabled on \n"); printf(" the system\n"); } else if ((ret == -1) && (errno == EINVAL)) { printf(" ACLs not supported on filesystem\n"); exit(1); } else { printf(" Error checking file ACL status for \n"); printf(" file %s, exiting...\n",argv[1]); perror("pathconf"); exit(1); } /* Allocate an ACL */ acl_p = acl_init(1024); /* [2] */ /* Walk through the table creating corresponding ACL entries */ for(i=0;i<TABLE_ENTRIES;i++) { /* Initialize the entry */ entry_p = acl_create_entry(&acl_p); /* [3] */ /* Set the permissions for the entry */ acl_set_permset(entry_p,&table[i].perms); /* [4] */ /* Set the user or group information for the entry */ switch(table[i].tag_type) { case ACL_USER: /* Get the uid from the user name */ uid=pw_nametoid(table[i].qualifier); /* [5] */ if (uid == (uid_t) -1) { printf(" No translation for user name %s\n", table[i].qualifier); printf(" Exiting...\n"); exit(1); } /* Specify this is a "USER:" entry */ acl_set_tag_type(entry_p,table[i].tag_type); /* [6] */ /* Set the uid (entry qualifier) */ acl_set_qualifier(entry_p,(void *)&uid); /* [7] */ break; case ACL_GROUP: /* Get the gid from the group name */ gid=gr_nametoid(table[i].qualifier); /* [8] */ if (gid == (gid_t) -1) { printf(" No translation for group name %s\n", table[i].qualifier); printf(" Exiting...\n"); exit(1); } /* Specify this is a "GROUP:" entry */ acl_set_tag_type(entry_p,table[i].tag_type); /* Set the gid (entry qualifier) */ acl_set_qualifier(entry_p,(void *) &gid); break; default: /* The three entries corresponding to the */ /* Permission bits don't have qualifiers */ acl_set_tag_type(entry_p,table[i].tag_type); acl_set_qualifier(entry_p,NULL); break; } } /* Is the created ACL valid? */ if (acl_valid(acl_p, &check_p) < 0) { /* [9] */ printf(" Not Valid ACL\n"); if (check_p) printf(" Duplicate entries\n"); printf(" Exiting...\n"); exit(1); } /* Set the ACL on the file */ if (acl_set_file(argv[1],ACL_TYPE_ACCESS, acl_p) < 0) perror("acl_set_file"); /* Free the storage allocated for the ACL */ acl_free(acl_p); }
The _PC_ACL_ENABLED attribute of
pathconf
()
returns the status of ACL processing for the given file.
[Return to example]
This demonstrates the use of the initialization call for a working storage
representation of the ACL.
If the storage allocated is not big enough for
all of the entries in the completed ACL, the
acl_create_entry
()
routine will allocate more memory.
[Return to example]
A new ACL entry is allocated with this call. The tag type, qualifier, and permissions in this new entry are unspecified. [Return to example]
The
acl_set_permset
() routine sets the permissions
for the ACL entry.
[Return to example]
The
pw_nametoid
() routine is an optimized
mapping from user name to user ID and works with either Base or Enhanced security
enabled.
The
pw_nametoid
() routine is described in the
pw_mapping
(3)
The
acl_set_tag_type
() function sets the
type for the given ACL entry.
The current tag types are: ACL_USER_OBJ (owner
permission bits), ACL_GROUP_OBJ (group permission bits), ACL_OTHER_OBJ (other
permission bits), ACL_USER (permissions for specified user), ACL_GROUP (permissions
for specified group).
[Return to example]
The
acl_set_qualifier
() function sets the
ID for the ACL_USER and ACL_GROUP tag types.
This specifies which user or
group the entry refers to.
The other tag types do not require an ID.
[Return to example]
The
gr_grouptoid
() routine provides an optimized
mapping from group name to group ID and works with either Base or Enhanced
security enabled.
It is described in the
pw_mapping
(3)
The
acl_valid
() routine checks for missing
and duplicate entries.
[Return to example]
This section shows how a program can specify a default access ACL on a directory and then describes what happens when a file and a directory are created in that directory. There is another type of default ACL called a default directory ACL. ACLs are inherited differently if a directory has a default directory ACL in addition to or in place of a default access ACL. See Security Administration for a complete description of the ACL inheritance rules.
Assume that directory
/usr/john/acl_dir
has the
following access and default access ACLs:
% getacl /usr/john/acl_dir # file: /usr/john/acl_dir # owner: john # group: prog # user::rwx user:june:r-x user:fred:r-x group::rwx group:mktg:rwx other::r-x % getacl -d /usr/john/acl_dir # file: /usr/john/acl_dir # owner: john # group: prog # user::rwx user:june:r-x user:sally:r-x group::rwx group:mktg:rwx other::rwx
The following program can be used to update the default access ACL on
a directory to remove read and write permissions from a group entry and then
create a regular file and a directory in the given directory.
If you extract
the following code into a file named
acl_inheritance.c
,
it can be compiled with the following command:
% cc -o acl_inheritance -lpacl -lsecurity acl_inheritance.c
#include <unistd.h> #include <sys/types.h> #include <prot.h> #include <errno.h> #include <sys/acl.h> #define REGULAR_FILE "regular" #define DIRECTORY_FILE "dir" main (argc, argv) int argc; char *argv[]; { acl_permset_t acl_permset; gid_t *qualifier = NULL; acl_tag_t tag_type; acl_t acl; acl_entry_t acl_entry; gid_t my_gid; int ret; char pathname[PATH_MAX + 1]; int fd; /* Did the user enter a directory name and group name? */ if (argc != 3) { printf("Usage: %s directory group\n",argv[0]); exit(1); } /* Map the group name to a gid */ my_gid = gr_nametoid(argv[2]); if (my_gid == (gid_t) -1) { printf("No translation for group %s\n",argv[2]); exit(1); } /* Read the default ACL from the directory */ acl = acl_get_file(argv[1], ACL_TYPE_DEFAULT); if (!acl) { if (errno) { perror("acl_get_file"); } else { printf("No default ACL found on %s\n", argv[1]); } exit(1); } ret = acl_first_entry(acl); if (ret) { perror("acl_first_entry"); exit(1); } /* Scan the ACL looking for the entry */ while (acl_entry = acl_get_entry(acl)) { /* retrieve the entry type */ ret = acl_get_tag_type(acl_entry, &tag_type); if (ret) { perror("acl_get_tag_type"); exit(1); } if (tag_type != ACL_GROUP) continue; qualifier = (gid_t *)acl_get_qualifier(acl_entry); if (!qualifier) { perror("acl_get_qualifier"); exit(1); } /* Check for appropriate entry */ if (*qualifier != my_gid) continue; ret = acl_get_permset(acl_entry, &acl_permset); if (ret) { perror("acl_get_permset"); exit(1); } *acl_permset = *acl_permset & ~(ACL_READ | ACL_WRITE); ret = acl_set_permset(acl_entry, acl_permset); if (ret) { perror("acl_set_permset"); exit(1); } ret = acl_set_file(argv[1], ACL_TYPE_DEFAULT, acl); if (ret) { perror("acl_set_file"); exit(1); } break; } if (!acl_entry) { if (errno) { perror("acl_get_entry"); } else { printf("ACL entry for %s not found\n", argv[2]); } exit(1); } /* Create the regular file */ sprintf(pathname, "%s/%s", argv[1], REGULAR_FILE); fd = creat(pathname, 0644); if (fd == -1) { perror("creat"); exit(1); } close(fd); /* Create the directory */ sprintf(pathname, "%s/%s", argv[1], DIRECTORY_FILE); ret = mkdir(pathname, 0700); if (ret == -1) { perror("mkdir"); exit(1); } }
When you run the previous example program, it removes the read and write
permissions from the
mktg
group in the default ACL shown
above.
The program then creates a regular file and a directory in that directory
to demonstrate ACL inheritance.
Enter the following command to execute the
example program:
% ./acl_inheritance /usr/john/acl_dir mktg
When the example program is executed, the access ACL on the newly created file and the access and default access ACLs on the newly created directory are as follows:
% getacl /usr/john/acl_dir/regular # file: /usr/john/acl_dir/regular # owner: john # group: prog # user::rw- user:june:r-x user:sally:r-x group::r-- group:mktg:--x other::r--
Note that the permissions for the owning user, the owning group,
and other are set to the logical AND of the default access ACL and the mode
specified with the
creat
() call.
The
umask
is not used when ACL inheritance takes place.
The other entries are taken
from the default access ACL of the parent directory, not the access ACL.
% getacl /usr/john/acl_dir/dir # file: /usr/john/acl_dir/dir # owner: john # group: prog # user::rwx user:june:r-x user:sally:r-x group::--- group:mktg:--x other::---
Note that the access ACL inheritance rules for a subdirectory created in a directory that has a default access ACL are the same as those for a file. This is true only if there is not a default directory ACL on the parent directory in addition to the default access ACL.
The following command line displays the default access ACL:
% getacl -d /usr/john/acl_dir/dir # file: /usr/john/acl_dir/dir # owner: john # group: prog # user::rwx user:june:r-x user:sally:r-x group::rwx group:mktg:--x other::rwx
Note that the default ACL is inherited from the directory's parent.