Mac OS X Internals: A Systems Approach

11.9. Access Control Lists

An access control list (ACL) is an ordered list of access control entries (ACEs). ACLs represent a popular implementation approach[17] to the access control mechanism based on the Access Matrix model. In this model, we have the following entities:

[17] Another common approach is the one using capability lists.

  • Objects, which are resources (such as files) that must be accessed in a protected manner

  • Subjects, which are active entities (such as user processes) that access objects

  • Rights, which represent operations (such as read, write, and delete) on objects

An ACL enumerates through its ACEs which objects may or may not access a particular object for one or more rights. As we will see in Section 11.10, ACLs are evaluated by the kauth subsystem in the kernel. Evaluation begins at the first ACE in the list, which may theoretically contain any number of ACEs. The request is denied if an ACE denies any of the requested rights; the remaining ACEs, if any, are not considered. Conversely, the request is granted if all requested rights are satisfied by the ACEs evaluated so faragain, the remaining ACEs are not considered.

The Mac OS X chmod command can be used to insert or delete an ACE at a specific position in an ACL.

The Mac OS X ACL implementation requires extended attributes to be supported in the file system. As we will see in Chapter 12, HFS+, which has native support for extended attributes, stores an ACL as the attribute data of a special attribute named com.apple.system.Security. Before ACLs can be used on an HFS+ volume, they must be enabled on the volumeeither through the fsaclctl command-line program or, programmatically, by using the HFS_SETACLSTATE file system control operation.

... int ret; char volume_path[...]; u_int32_t aclstate = 1; // 1 enables, 0 disables ... // HFS_SETACLSTATE is defined in bsd/hfs/hfs_fsctl.h ret = fsctl(volume_path, HFS_SETACLSTATE, (void *)aclstate, 0); ...

The system library implements the POSIX.1e ACL security API, which is documented in the acl(3) manual page. Figure 1129 shows a program thatgiven a file (or folder) pathnameuses the acl(3) API to create an ACL, add an entry to it that denies deletion of that file to the calling user, and associate the ACL with the file.

Figure 1129. A program to create and set an ACL

// aclset.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/acl.h> #include <membership.h> #define PROGNAME "aclset" #define EXIT_ON_ERROR(msg, retval) if (retval) { perror(msg); exit((retval)); } int main(int argc, char **argv) { int ret, acl_count = 4; acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; acl_perm_t acl_perm; uuid_t uu; if (argc != 2) { fprintf(stderr, "usage: %s <file>\n", PROGNAME); exit(1); } // translate Unix user ID to UUID ret = mbr_uid_to_uuid(getuid(), uu); EXIT_ON_ERROR("mbr_uid_to_uuid", ret); // allocate and initialize working storage for an ACL with acl_count entries if ((acl = acl_init(acl_count)) == (acl_t)NULL) { perror("acl_init"); exit(1); } // create a new ACL entry in the given ACL ret = acl_create_entry(&acl, &acl_entry); EXIT_ON_ERROR("acl_create_entry", ret); // retrieve descriptor to the permission set in the given ACL entry ret = acl_get_permset(acl_entry, &acl_permset); EXIT_ON_ERROR("acl_get_permset", ret); // a permission acl_perm = ACL_DELETE; // add the permission to the given permission set ret = acl_add_perm(acl_permset, acl_perm); EXIT_ON_ERROR("acl_add_perm", ret); // set the permissions of the given ACL entry to those contained in this set ret = acl_set_permset(acl_entry, acl_permset); EXIT_ON_ERROR("acl_set_permset", ret); // set the tag type (we want to deny delete permissions) ret = acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY); EXIT_ON_ERROR("acl_set_tag_type", ret); // set qualifier (in the case of ACL_EXTENDED_DENY, this should be a uuid_t) ret = acl_set_qualifier(acl_entry, (const void *)uu); EXIT_ON_ERROR("acl_set_qualifier", ret); // associate the ACL with the file ret = acl_set_file(argv[1], ACL_TYPE_EXTENDED, acl); EXIT_ON_ERROR("acl_set_file", ret); // free ACL working space ret = acl_free((void *)acl); EXIT_ON_ERROR("acl_free", ret); exit(0); } $ gcc -Wall -o aclset aclset.c $ touch /tmp/file.txt $ ls -le /tmp/file.txt -rw-r--r-- + 1 amit wheel 0 Oct 22 01:49 /tmp/file.txt 0: user:amit deny delete $ rm /tmp/file.txt rm: /tmp/file.txt: Permission denied $ sudo rm /tmp/file.txt $

Figure 1129 illustrates numerous steps involved in manipulating ACLs. However, you can achieve the same effect as the program with a single chmod command line:

$ chmod +a '<username> deny delete' <pathname>

The acl_set_file() function, which is implemented in the system library, internally uses an extended version of the chmod() system call to set the ACL. Given an ACL, it performs the following operations:

  • Creates a file security descriptor object (filesec_t) by calling filesec_init()

  • Adds the ACL to the security descriptor by calling filesec_set_security()

  • Calls chmodx_np() with the security descriptor as an argument (note that np stands for nonportablechmodx_np() invokes the extended chmod() system call)

Besides chmod(), several other system calls were extended in Mac OS X 10.4 to add support for ACLsfor example, there are extended versions of open(), umask(), stat(), lstat(), fstat(), fchmod(), mkfifo(), and mkdir(). The following code excerpt shows how the program from Figure 1129 might be modified to create a file with an ACL.

... // assuming the ACL has been set up at this point // create a file security object filesec = filesec_init(); // set the ACL as the file security object's property filesec_set_property(filesec, FILESEC_ACL, &acl); if ((fd = openx_np(argv[1], O_CREAT | O_RDWR | O_EXCL, filesec)) < 0) perror("openx_np"); else close(fd); filesec_free(filesec); ...

Категории