Working with access control lists (ACLs)

Some file systems, such as the Power-Safe (fs-qnx6.so) file system, extend file permissions with access control lists, which are based on the withdrawn IEEE POSIX 1003.1e and 1003.2c draft standards. As described in Access control lists (ACLs) in the BlackBerry 10 OS user's guide, ACLs extend the traditional permissions as set with chmod , giving you finer control over who has access to your files and directories.

If you're using the command line, you can use the getfacl and setfacl utilities to get and set the ACL for a file or directory, but there are also ways to manipulate ACLs from a program.

Let's start with the ways that an ACL can be represented, and then we'll look at how to work with them.

ACL formats

There are several ways to represent an ACL, depending on how it's to be used.

External form
The exportable, contiguous, persistent representation of an ACL in user-managed space. A program such as tar could (but currently doesn't) use this representation so that it could later restore the ACLs, even on a different file system.
Internal form
The internal representation of an ACL in working storage, which you'll work with in your program. As described below, this form uses various data types to represent an ACL, its entries, and each entry's tag and permissions.
text form
The structured textual representation of an ACL, such as getfacl and setfacl use.

The internal form uses the following data types:

acl_t
A pointer to an opaque ACL data structure in working storage.
acl_entry_t
An opaque descriptor for an entry in an ACL.
acl_permset_t
An opaque set of permissions in an ACL entry.
acl_perm_t
An individual permission; one of:
  • ACL_EXECUTE
  • ACL_READ
  • ACL_WRITE
acl_tag_t
The type of tag; one of the following:
  • ACL_GROUP — a named group.
  • ACL_GROUP_OBJ — the owning group.
  • ACL_MASK — the maximum permissions allowed for named users, named groups, and the owning group.
  • ACL_OTHER — users whose process attributes don't match any other ACL entry; the world.
  • ACL_USER — named users.
  • ACL_USER_OBJ — the owning user.
acl_type_t
The type of ACL; one of:
  • ACL_TYPE_ACCESS — an access ACL. (If you expand the abbreviation, this term becomes access access control list, but that's what the POSIX draft called it.)
  • ACL_TYPE_DEFAULT — a default ACL that a directory can have. It specifies the initial ACL for files and directories created in that directory.

    Default ACLs aren't currently implemented.

You can use these functions to translate from one form of an ACL to another:

acl_copy_ext()
Copy an ACL from system space to user space (that is, translate from the external form to the internal).
acl_copy_int()
Copy an ACL from user space to system space (that is, translate from the internal form to the external).
acl_from_text()
Create an internal form of an ACL from a text form.
acl_size()
Determine the size of the external form of an ACL.
acl_to_text()
Convert an internal form of an ACL into a text form.

ACL storage management

There are several functions that manage the memory associated with ACLs.

acl_init()
Allocate and initialize an ACL working storage area. The argument to this function is the number of entries that you want in the list (although acl_init() might allocate more). It returns an acl_t pointer.
acl_dup()
Duplicate a access control list in working storage. You pass it an acl_t pointer, and it returns a pointer to the copy of the list.
acl_free()
Free the working storage area allocated for an access control list (ACL) data object. You should use this function to free the memory allocated by the other acl_*() functions.

Manipulating ACL entries in working storage

An ACL can have a number of entries in it. You can use these functions to work with these entries.

acl_copy_entry()
Copy the contents of one ACL entry into another.
acl_create_entry()
Create an entry in an ACL.
acl_delete_entry()
Delete an entry from an access control list.
acl_get_entry()
Get an entry in an access control list.
acl_valid()
Validate an ACL, which you should do before you assign it to a file or directory. This routine makes sure that the list contains the required entries, and that there's only one entry for each named user or group.

Manipulating permissions in an ACL entry

Each ACL entry has a permission set. These functions work with these sets and the individual permissions. The permissions are represented by the constants ACL_READ, ACL_EXECUTE, and ACL_WRITE. Because a permission set is an opaque data type, you have to use these functions to work with them:

acl_add_perm()
Add a permision to an access control list (ACL) permission set.
acl_calc_mask()
Calculate the group class mask for an access control list (ACL).
acl_clear_perms()
Clear all permissions from an ACL permission set.
acl_del_perm()
Delete a permission from an ACL permissions set.
acl_get_permset()
Get a permission set from an ACL entry.
acl_set_permset()
Set the permissions set in an ACL entry.

Manipulating the tag type and qualifier in an ACL entry

Each ACL entry must have a tag type, and some also require a qualifier.

Entry type Tag type Qualifier
Owner ACL_USER_OBJ
Named user ACL_USER uid_t
Owning group ACL_GROUP_OBJ
Named group ACL_GROUP gid_t
Mask ACL_MASK
Others ACL_OTHER

The uid_t and gid_t data types are defined in <sys/types.h>.

The ACL entry is an opaque data type, so you need to use these functions to get or set the tag type and the qualifier:

acl_get_qualifier()
Get the qualifier from an ACL entry.
acl_get_tag_type()
Get the type of tag from an ACL entry.
acl_set_qualifier()
Set the qualifier for an ACL entry.
acl_set_tag_type()
Set the tag type of an ACL entry.

Manipulating ACLs on a file or directory

You can get or set the ACL for a file, via a file descriptor or a path.

acl_get_fd()
Get the access control list associated with a file descriptor.
acl_get_file()
Get the ACL for a given path.
acl_set_fd()
Set the access ACL for the object associated with a file descriptor.
acl_set_file()
Set the access control list for a path.

Example

This example demonstrates how you can get the ACL for a file, modify it, and then set it for the file.

#include <stdlib.h>
#include <stdio.h>
#include <sys/acl.h>
#include <sys/types.h>

int main(int argc, char *argv[]) {

	acl_t my_acl;
	char  *text_acl;
	ssize_t len;
	acl_entry_t my_entry;
	gid_t  group_id;
	acl_permset_t permset;

	system ("touch my_file.txt");

	/* Get the file's ACL. */
	my_acl = acl_get_file ("my_file.txt", ACL_TYPE_ACCESS);
	if (my_acl == NULL)
	{
		perror ("acl_get_file()");
		return EXIT_FAILURE;
	}

	/* Convert the ACL into text so we can see what it is. */
	text_acl = acl_to_text (my_acl, &len);
	if (text_acl == NULL)
	{
		perror ("acl_to_text()");
		return EXIT_FAILURE;
	}
	printf ("Initial ACL: %s\n", text_acl);

	/* We're done with the text version, so release it. */
	if (acl_free (text_acl) == -1)
	{
		perror ("acl_free()");
		return EXIT_FAILURE;
	}

	/* Add an entry for a named group to the ACL. */
	if (acl_create_entry (&my_acl, &my_entry) == -1)
	{
		perror ("acl_create_entry()");
		return EXIT_FAILURE;
	}

	if (acl_set_tag_type (my_entry, ACL_USER) == -1)
	{
		perror ("acl_set_tag_type");
		return EXIT_FAILURE;
	}

	group_id = 120;
	if (acl_set_qualifier (my_entry, &group_id) == -1)
	{
		perror ("acl_set_qualifier");
		return EXIT_FAILURE;
	}

	/* Modify the permissions. */
	if (acl_get_permset (my_entry, &permset) == -1)
	{
		perror ("acl_get_permset");
		return EXIT_FAILURE;
	}

	if (acl_clear_perms (permset ) == -1)
	{
		perror ("acl_clear_perms");
		return EXIT_FAILURE;
	}

	if (acl_add_perm (permset, ACL_READ))
	{
		perror ("acl_add_perm");
		return EXIT_FAILURE;
	}

	/* Recalculate the mask entry. */
	if (acl_calc_mask (my_acl))
	{
		perror ("acl_calc_mask");
		return EXIT_FAILURE;
	}

	/* Make sure the ACL is valid. */
	if (acl_valid (my_acl) ==-1)
	{
		perror ("acl_valid");
		return EXIT_FAILURE;
	}

	/* Update the ACL for the file. */
	if (acl_set_file ("my_file.txt", ACL_TYPE_ACCESS, my_acl) == -1)
	{
		perror ("acl_set_file");
		return EXIT_FAILURE;
	}

	/* Free the ACL in working storage. */
	if (acl_free (my_acl) == -1)
	{
		perror ("acl_free()");
		return EXIT_FAILURE;
	}

	/* Verify that it all worked, by getting and printing the file's ACL. */
	my_acl = acl_get_file ("my_file.txt", ACL_TYPE_ACCESS);
	if (my_acl == NULL)
	{
		perror ("acl_get_file()");
		return EXIT_FAILURE;
	}

	text_acl = acl_to_text (my_acl, &len);
	if (text_acl == NULL)
	{
		perror ("acl_to_text()");
		return EXIT_FAILURE;
	}
	printf ("Updated ACL: %s\n", text_acl);

	/* We're done with the text version, so release it. */
	if (acl_free (text_acl) == -1)
	{
		perror ("acl_free()");
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

Last modified: 2014-12-11



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus