svn commit: r196936 - head/bin/setfacl

Edward Tomasz Napierala trasz at FreeBSD.org
Mon Sep 7 16:19:33 UTC 2009


Author: trasz
Date: Mon Sep  7 16:19:32 2009
New Revision: 196936
URL: http://svn.freebsd.org/changeset/base/196936

Log:
  Add NFSv4 support to setfacl(1).
  
  Reviewed by:	rwatson

Modified:
  head/bin/setfacl/mask.c
  head/bin/setfacl/merge.c
  head/bin/setfacl/remove.c
  head/bin/setfacl/setfacl.1
  head/bin/setfacl/setfacl.c
  head/bin/setfacl/setfacl.h

Modified: head/bin/setfacl/mask.c
==============================================================================
--- head/bin/setfacl/mask.c	Mon Sep  7 16:18:16 2009	(r196935)
+++ head/bin/setfacl/mask.c	Mon Sep  7 16:19:32 2009	(r196936)
@@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$");
 
 /* set the appropriate mask the given ACL's */
 int
-set_acl_mask(acl_t *prev_acl)
+set_acl_mask(acl_t *prev_acl, const char *filename)
 {
 	acl_entry_t entry;
 	acl_t acl;
@@ -59,7 +59,7 @@ set_acl_mask(acl_t *prev_acl)
 
 	acl = acl_dup(*prev_acl);
 	if (acl == NULL)
-		err(1, "acl_dup() failed");
+		err(1, "%s: acl_dup() failed", filename);
 
 	if (n_flag == 0) {
 		/*
@@ -70,7 +70,7 @@ set_acl_mask(acl_t *prev_acl)
 		 * class in the resulting ACL
 		 */
 		if (acl_calc_mask(&acl)) {
-			warn("acl_calc_mask() failed");
+			warn("%s: acl_calc_mask() failed", filename);
 			acl_free(acl);
 			return (-1);
 		}
@@ -86,7 +86,8 @@ set_acl_mask(acl_t *prev_acl)
 		while (acl_get_entry(acl, entry_id, &entry) == 1) {
 			entry_id = ACL_NEXT_ENTRY;
 			if (acl_get_tag_type(entry, &tag) == -1)
-				err(1, "acl_get_tag_type() failed");
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
 
 			if (tag == ACL_MASK) {
 				acl_free(acl);
@@ -100,7 +101,7 @@ set_acl_mask(acl_t *prev_acl)
 		 * file, then write an error message to standard error and
 		 * continue with the next file.
 		 */
-		warnx("warning: no mask entry");
+		warnx("%s: warning: no mask entry", filename);
 		acl_free(acl);
 		return (0);
 	}

Modified: head/bin/setfacl/merge.c
==============================================================================
--- head/bin/setfacl/merge.c	Mon Sep  7 16:18:16 2009	(r196935)
+++ head/bin/setfacl/merge.c	Mon Sep  7 16:19:32 2009	(r196936)
@@ -36,12 +36,15 @@ __FBSDID("$FreeBSD$");
 
 #include "setfacl.h"
 
-static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new);
+static int merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new,
+    int acl_brand);
 
 static int
-merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new)
+merge_user_group(acl_entry_t *entry, acl_entry_t *entry_new, int acl_brand)
 {
 	acl_permset_t permset;
+	acl_entry_type_t entry_type;
+	acl_flagset_t flagset;
 	int have_entry;
 	uid_t *id, *id_new;
 
@@ -59,6 +62,18 @@ merge_user_group(acl_entry_t *entry, acl
 			err(1, "acl_get_permset() failed");
 		if (acl_set_permset(*entry_new, permset) == -1)
 			err(1, "acl_set_permset() failed");
+
+		if (acl_brand == ACL_BRAND_NFS4) {
+			if (acl_get_entry_type_np(*entry, &entry_type))
+				err(1, "acl_get_entry_type_np() failed");
+			if (acl_set_entry_type_np(*entry_new, entry_type))
+				err(1, "acl_set_entry_type_np() failed");
+			if (acl_get_flagset_np(*entry, &flagset))
+				err(1, "acl_get_flagset_np() failed");
+			if (acl_set_flagset_np(*entry_new, flagset))
+				err(1, "acl_set_flagset_np() failed");
+		}
+
 		have_entry = 1;
 	}
 	acl_free(id);
@@ -71,20 +86,31 @@ merge_user_group(acl_entry_t *entry, acl
  * merge an ACL into existing file's ACL
  */
 int
-merge_acl(acl_t acl, acl_t *prev_acl)
+merge_acl(acl_t acl, acl_t *prev_acl, const char *filename)
 {
 	acl_entry_t entry, entry_new;
 	acl_permset_t permset;
 	acl_t acl_new;
 	acl_tag_t tag, tag_new;
-	int entry_id, entry_id_new, have_entry;
+	acl_entry_type_t entry_type, entry_type_new;
+	acl_flagset_t flagset;
+	int entry_id, entry_id_new, have_entry, entry_number = 0;
+	int acl_brand, prev_acl_brand;
+
+	acl_get_brand_np(acl, &acl_brand);
+	acl_get_brand_np(*prev_acl, &prev_acl_brand);
+
+	if (acl_brand != prev_acl_brand) {
+		warnx("%s: branding mismatch; existing ACL is %s, "
+		    "entry to be merged is %s", filename,
+		    prev_acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e",
+		    acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e");
+		return (-1);
+	}
 
-	if (acl_type == ACL_TYPE_ACCESS)
-		acl_new = acl_dup(prev_acl[ACCESS_ACL]);
-	else
-		acl_new = acl_dup(prev_acl[DEFAULT_ACL]);
+	acl_new = acl_dup(*prev_acl);
 	if (acl_new == NULL)
-		err(1, "acl_dup() failed");
+		err(1, "%s: acl_dup() failed", filename);
 
 	entry_id = ACL_FIRST_ENTRY;
 
@@ -94,28 +120,45 @@ merge_acl(acl_t acl, acl_t *prev_acl)
 
 		/* keep track of existing ACL_MASK entries */
 		if (acl_get_tag_type(entry, &tag) == -1)
-			err(1, "acl_get_tag_type() failed - invalid ACL entry");
+			err(1, "%s: acl_get_tag_type() failed - "
+			    "invalid ACL entry", filename);
 		if (tag == ACL_MASK)
 			have_mask = 1;
 
 		/* check against the existing ACL entries */
 		entry_id_new = ACL_FIRST_ENTRY;
-		while (have_entry == 0 &&
-		    acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
+		while (acl_get_entry(acl_new, entry_id_new, &entry_new) == 1) {
 			entry_id_new = ACL_NEXT_ENTRY;
 
 			if (acl_get_tag_type(entry, &tag) == -1)
-				err(1, "acl_get_tag_type() failed");
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
 			if (acl_get_tag_type(entry_new, &tag_new) == -1)
-				err(1, "acl_get_tag_type() failed");
+				err(1, "%s: acl_get_tag_type() failed",
+				    filename);
 			if (tag != tag_new)
 				continue;
 
+			/*
+			 * For NFSv4, in addition to "tag" and "id" we also
+			 * compare "entry_type".
+			 */
+			if (acl_brand == ACL_BRAND_NFS4) {
+				if (acl_get_entry_type_np(entry, &entry_type))
+					err(1, "%s: acl_get_entry_type_np() "
+					    "failed", filename);
+				if (acl_get_entry_type_np(entry_new, &entry_type_new))
+					err(1, "%s: acl_get_entry_type_np() "
+					    "failed", filename);
+				if (entry_type != entry_type_new)
+					continue;
+			}
+		
 			switch(tag) {
 			case ACL_USER:
 			case ACL_GROUP:
 				have_entry = merge_user_group(&entry,
-				    &entry_new);
+				    &entry_new, acl_brand);
 				if (have_entry == 0)
 					break;
 				/* FALLTHROUGH */
@@ -123,37 +166,127 @@ merge_acl(acl_t acl, acl_t *prev_acl)
 			case ACL_GROUP_OBJ:
 			case ACL_OTHER:
 			case ACL_MASK:
+			case ACL_EVERYONE:
 				if (acl_get_permset(entry, &permset) == -1)
-					err(1, "acl_get_permset() failed");
+					err(1, "%s: acl_get_permset() failed",
+					    filename);
 				if (acl_set_permset(entry_new, permset) == -1)
-					err(1, "acl_set_permset() failed");
+					err(1, "%s: acl_set_permset() failed",
+					    filename);
+
+				if (acl_brand == ACL_BRAND_NFS4) {
+					if (acl_get_entry_type_np(entry, &entry_type))
+						err(1, "%s: acl_get_entry_type_np() failed",
+						    filename);
+					if (acl_set_entry_type_np(entry_new, entry_type))
+						err(1, "%s: acl_set_entry_type_np() failed",
+						    filename);
+					if (acl_get_flagset_np(entry, &flagset))
+						err(1, "%s: acl_get_flagset_np() failed",
+						    filename);
+					if (acl_set_flagset_np(entry_new, flagset))
+						err(1, "%s: acl_set_flagset_np() failed",
+						    filename);
+				}
 				have_entry = 1;
 				break;
 			default:
 				/* should never be here */
-				errx(1, "Invalid tag type: %i", tag);
+				errx(1, "%s: invalid tag type: %i", filename, tag);
 				break;
 			}
 		}
 
 		/* if this entry has not been found, it must be new */
 		if (have_entry == 0) {
-			if (acl_create_entry(&acl_new, &entry_new) == -1) {
-				acl_free(acl_new);
-				return (-1);
+
+			/*
+			 * NFSv4 ACL entries must be prepended to the ACL.
+			 * Appending them at the end makes no sense, since
+			 * in most cases they wouldn't even get evaluated.
+			 */
+			if (acl_brand == ACL_BRAND_NFS4) {
+				if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) {
+					warn("%s: acl_create_entry_np() failed", filename); 
+					acl_free(acl_new);
+					return (-1);
+				}
+				/*
+				 * Without this increment, adding several
+				 * entries at once, for example
+				 * "setfacl -m user:1:r:allow,user:2:r:allow",
+				 * would make them appear in reverse order.
+				 */
+				entry_number++;
+			} else {
+				if (acl_create_entry(&acl_new, &entry_new) == -1) {
+					warn("%s: acl_create_entry() failed", filename); 
+					acl_free(acl_new);
+					return (-1);
+				}
 			}
 			if (acl_copy_entry(entry_new, entry) == -1)
-				err(1, "acl_copy_entry() failed");
+				err(1, "%s: acl_copy_entry() failed", filename);
 		}
 	}
 
-	if (acl_type == ACL_TYPE_ACCESS) {
-		acl_free(prev_acl[ACCESS_ACL]);
-		prev_acl[ACCESS_ACL] = acl_new;
-	} else {
-		acl_free(prev_acl[DEFAULT_ACL]);
-		prev_acl[DEFAULT_ACL] = acl_new;
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
+	return (0);
+}
+
+int
+add_acl(acl_t acl, uint entry_number, acl_t *prev_acl, const char *filename)
+{
+	acl_entry_t entry, entry_new;
+	acl_t acl_new;
+	int entry_id, acl_brand, prev_acl_brand;
+
+	acl_get_brand_np(acl, &acl_brand);
+	acl_get_brand_np(*prev_acl, &prev_acl_brand);
+
+	if (prev_acl_brand != ACL_BRAND_NFS4) {
+		warnx("%s: the '-a' option is only applicable to NFSv4 ACLs",
+		    filename);
+		return (-1);
+	}
+
+	if (acl_brand != ACL_BRAND_NFS4) {
+		warnx("%s: branding mismatch; existing ACL is NFSv4, "
+		    "entry to be added is POSIX.1e", filename);
+		return (-1);
+	}
+
+	acl_new = acl_dup(*prev_acl);
+	if (acl_new == NULL)
+		err(1, "%s: acl_dup() failed", filename);
+
+	entry_id = ACL_FIRST_ENTRY;
+
+	while (acl_get_entry(acl, entry_id, &entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+
+		if (acl_create_entry_np(&acl_new, &entry_new, entry_number) == -1) {
+			warn("%s: acl_create_entry_np() failed", filename); 
+			acl_free(acl_new);
+			return (-1);
+		}
+
+		/*
+		 * Without this increment, adding several
+		 * entries at once, for example
+		 * "setfacl -m user:1:r:allow,user:2:r:allow",
+		 * would make them appear in reverse order.
+		 */
+		entry_number++;
+
+		if (acl_copy_entry(entry_new, entry) == -1)
+			err(1, "%s: acl_copy_entry() failed", filename);
 	}
 
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
 	return (0);
 }

Modified: head/bin/setfacl/remove.c
==============================================================================
--- head/bin/setfacl/remove.c	Mon Sep  7 16:18:16 2009	(r196935)
+++ head/bin/setfacl/remove.c	Mon Sep  7 16:19:32 2009	(r196936)
@@ -41,21 +41,31 @@ __FBSDID("$FreeBSD$");
  * remove ACL entries from an ACL
  */
 int
-remove_acl(acl_t acl, acl_t *prev_acl)
+remove_acl(acl_t acl, acl_t *prev_acl, const char *filename)
 {
 	acl_entry_t	entry;
 	acl_t		acl_new;
 	acl_tag_t	tag;
-	int		carried_error, entry_id;
+	int		carried_error, entry_id, acl_brand, prev_acl_brand;
+
+	carried_error = 0;
+
+	acl_get_brand_np(acl, &acl_brand);
+	acl_get_brand_np(*prev_acl, &prev_acl_brand);
+
+	if (acl_brand != prev_acl_brand) {
+		warnx("%s: branding mismatch; existing ACL is %s, "
+		    "entry to be removed is %s", filename,
+		    prev_acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e",
+		    acl_brand == ACL_BRAND_NFS4 ? "NFSv4" : "POSIX.1e");
+		return (-1);
+	}
 
 	carried_error = 0;
 
-	if (acl_type == ACL_TYPE_ACCESS)
-		acl_new = acl_dup(prev_acl[ACCESS_ACL]);
-	else
-		acl_new = acl_dup(prev_acl[DEFAULT_ACL]);
+	acl_new = acl_dup(*prev_acl);
 	if (acl_new == NULL)
-		err(1, "acl_dup() failed");
+		err(1, "%s: acl_dup() failed", filename);
 
 	tag = ACL_UNDEFINED_TAG;
 
@@ -64,23 +74,68 @@ remove_acl(acl_t acl, acl_t *prev_acl)
 	while (acl_get_entry(acl, entry_id, &entry) == 1) {
 		entry_id = ACL_NEXT_ENTRY;
 		if (acl_get_tag_type(entry, &tag) == -1)
-			err(1, "acl_get_tag_type() failed");
+			err(1, "%s: acl_get_tag_type() failed", filename);
 		if (tag == ACL_MASK)
 			have_mask++;
 		if (acl_delete_entry(acl_new, entry) == -1) {
 			carried_error++;
-			warnx("cannot remove non-existent acl entry");
+			warnx("%s: cannot remove non-existent ACL entry",
+			    filename);
 		}
 	}
 
-	if (acl_type == ACL_TYPE_ACCESS) {
-		acl_free(prev_acl[ACCESS_ACL]);
-		prev_acl[ACCESS_ACL] = acl_new;
-	} else {
-		acl_free(prev_acl[DEFAULT_ACL]);
-		prev_acl[DEFAULT_ACL] = acl_new;
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
+	if (carried_error)
+		return (-1);
+
+	return (0);
+}
+
+int
+remove_by_number(uint entry_number, acl_t *prev_acl, const char *filename)
+{
+	acl_entry_t	entry;
+	acl_t		acl_new;
+	acl_tag_t	tag;
+	int		carried_error, entry_id;
+	uint		i;
+
+	carried_error = 0;
+
+	acl_new = acl_dup(*prev_acl);
+	if (acl_new == NULL)
+		err(1, "%s: acl_dup() failed", filename);
+
+	tag = ACL_UNDEFINED_TAG;
+
+	/*
+	 * Find out whether we're removing the mask entry,
+	 * to behave the same as the routine above.
+	 *
+	 * XXX: Is this loop actually needed?
+	 */
+	entry_id = ACL_FIRST_ENTRY;
+	i = 0;
+	while (acl_get_entry(acl_new, entry_id, &entry) == 1) {
+		entry_id = ACL_NEXT_ENTRY;
+		if (i != entry_number)
+			continue;
+		if (acl_get_tag_type(entry, &tag) == -1)
+			err(1, "%s: acl_get_tag_type() failed", filename);
+		if (tag == ACL_MASK)
+			have_mask++;
+	}
+
+	if (acl_delete_entry_np(acl_new, entry_number) == -1) {
+		carried_error++;
+		warn("%s: acl_delete_entry_np() failed", filename);
 	}
 
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
+
 	if (carried_error)
 		return (-1);
 
@@ -91,18 +146,14 @@ remove_acl(acl_t acl, acl_t *prev_acl)
  * remove default entries
  */
 int
-remove_default(acl_t *prev_acl)
+remove_default(acl_t *prev_acl, const char *filename)
 {
 
-	if (prev_acl[1]) {
-		acl_free(prev_acl[1]);
-		prev_acl[1] = acl_init(ACL_MAX_ENTRIES);
-		if (prev_acl[1] == NULL)
-			err(1, "acl_init() failed");
-	} else {
-		warn("cannot remove default ACL");
-		return (-1);
-	}
+	acl_free(*prev_acl);
+	*prev_acl = acl_init(ACL_MAX_ENTRIES);
+	if (*prev_acl == NULL)
+		err(1, "%s: acl_init() failed", filename);
+
 	return (0);
 }
 
@@ -110,71 +161,14 @@ remove_default(acl_t *prev_acl)
  * remove extended entries
  */
 void
-remove_ext(acl_t *prev_acl)
+remove_ext(acl_t *prev_acl, const char *filename)
 {
-	acl_t acl_new, acl_old;
-	acl_entry_t entry, entry_new;
-	acl_permset_t perm;
-	acl_tag_t tag;
-	int entry_id, have_mask_entry;
-
-	if (acl_type == ACL_TYPE_ACCESS)
-		acl_old = acl_dup(prev_acl[ACCESS_ACL]);
-	else
-		acl_old = acl_dup(prev_acl[DEFAULT_ACL]);
-	if (acl_old == NULL)
-		err(1, "acl_dup() failed");
+	acl_t acl_new;
 
-	have_mask_entry = 0;
-	acl_new = acl_init(ACL_MAX_ENTRIES);
+	acl_new = acl_strip_np(*prev_acl, !n_flag);
 	if (acl_new == NULL)
-		err(1, "acl_init() failed");
-	tag = ACL_UNDEFINED_TAG;
-
-	/* only save the default user/group/other entries */
-	entry_id = ACL_FIRST_ENTRY;
-	while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
-		entry_id = ACL_NEXT_ENTRY;
-
-		if (acl_get_tag_type(entry, &tag) == -1)
-			err(1, "acl_get_tag_type() failed");
-
-		switch(tag) {
-		case ACL_USER_OBJ:
-		case ACL_GROUP_OBJ:
-		case ACL_OTHER:
-			if (acl_get_tag_type(entry, &tag) == -1)
-				err(1, "acl_get_tag_type() failed");
-			if (acl_get_permset(entry, &perm) == -1)
-				err(1, "acl_get_permset() failed");
-			if (acl_create_entry(&acl_new, &entry_new) == -1)
-				err(1, "acl_create_entry() failed");
-			if (acl_set_tag_type(entry_new, tag) == -1)
-				err(1, "acl_set_tag_type() failed");
-			if (acl_set_permset(entry_new, perm) == -1)
-				err(1, "acl_get_permset() failed");
-			if (acl_copy_entry(entry_new, entry) == -1)
-				err(1, "acl_copy_entry() failed");
-			break;
-		case ACL_MASK:
-			have_mask_entry = 1;
-			break;
-		default:
-			break;
-		}
-	}
-	if (have_mask_entry && n_flag == 0) {
-		if (acl_calc_mask(&acl_new) == -1)
-			err(1, "acl_calc_mask() failed");
-	} else {
-		have_mask = 1;
-	}
+		err(1, "%s: acl_strip_np() failed", filename);
 
-	if (acl_type == ACL_TYPE_ACCESS) {
-		acl_free(prev_acl[ACCESS_ACL]);
-		prev_acl[ACCESS_ACL] = acl_new;
-	} else {
-		acl_free(prev_acl[DEFAULT_ACL]);
-		prev_acl[DEFAULT_ACL] = acl_new;
-	}
+	acl_free(*prev_acl);
+	*prev_acl = acl_new;
 }

Modified: head/bin/setfacl/setfacl.1
==============================================================================
--- head/bin/setfacl/setfacl.1	Mon Sep  7 16:18:16 2009	(r196935)
+++ head/bin/setfacl/setfacl.1	Mon Sep  7 16:19:32 2009	(r196936)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 7, 2001
+.Dd September 5, 2009
 .Dt SETFACL 1
 .Os
 .Sh NAME
@@ -34,9 +34,10 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl bdhkn
+.Op Fl a Ar position entries
 .Op Fl m Ar entries
 .Op Fl M Ar file
-.Op Fl x Ar entries
+.Op Fl x Ar entries | position
 .Op Fl X Ar file
 .Op Ar
 .Sh DESCRIPTION
@@ -50,9 +51,19 @@ the file names are taken from the standa
 .Pp
 The following options are available:
 .Bl -tag -width indent
+.It Fl a Ar position entries
+Modify the ACL on the specified files by inserting new
+ACL entries
+specified in
+.Ar entries ,
+starting at position
+.Ar position ,
+counting from zero.
+This option is only applicable to NFSv4 ACLs.
 .It Fl b
-Remove all ACL entries except for the three required entries.
-If the ACL contains a
+Remove all ACL entries except for the three required entries
+(POSIX.1e ACLs) or six "canonical" entries (NFSv4 ACLs).
+If the POSIX.1e ACL contains a
 .Dq Li mask
 entry, the permissions of the
 .Dq Li group
@@ -66,7 +77,7 @@ entries of the current ACL.
 The operations apply to the default ACL entries instead of
 access ACL entries.
 Currently only directories may have
-default ACL's.
+default ACL's.  This option is not applicable to NFSv4 ACLs.
 .It Fl h
 If the target of the operation is a symbolic link, perform the operation
 on the symbolic link itself, rather than following the link.
@@ -77,7 +88,7 @@ is not considered an error if the specif
 any default ACL entries.
 An error will be reported if any of
 the specified files cannot have a default entry (i.e.\&
-non-directories).
+non-directories).  This option is not applicable to NFSv4 ACLs.
 .It Fl m Ar entries
 Modify the ACL entries on the specified files by adding new
 entries and modifying existing ACL entries with the ACL entries
@@ -95,11 +106,15 @@ is
 the input is taken from stdin.
 .It Fl n
 Do not recalculate the permissions associated with the ACL
-mask entry.
-.It Fl x Ar entries
-Remove the ACL entries specified in
+mask entry.  This option is not applicable to NFSv4 ACLs.
+.It Fl x Ar entries | position
+If
 .Ar entries
+is specified, remove the ACL entries specified there
 from the access or default ACL of the specified files.
+Otherwise, remove entry at index
+.Ar position ,
+counting from zero.
 .It Fl X Ar file
 Remove the ACL entries specified in the file
 .Ar file
@@ -108,8 +123,8 @@ from the access or default ACL of the sp
 .Pp
 The above options are evaluated in the order specified
 on the command-line.
-.Sh ACL ENTRIES
-An ACL entry contains three colon-separated fields:
+.Sh POSIX.1e ACL ENTRIES
+A POSIX.1E ACL entry contains three colon-separated fields:
 an ACL tag, an ACL qualifier, and discretionary access
 permissions:
 .Bl -tag -width indent
@@ -223,7 +238,7 @@ previously specified; whitespace is igno
 .Ql #
 is ignored (comments).
 .Pp
-When ACL entries are evaluated, the access check algorithm checks
+When POSIX.1e ACL entries are evaluated, the access check algorithm checks
 the ACL entries in the following order: file owner,
 .Dq Li user
 ACL entries, file owning group,
@@ -243,13 +258,135 @@ ACL entries for user, group, other and m
 For more details see the examples below.
 Default ACLs can be created by using
 .Fl d .
+.Sh NFSv4 ACL ENTRIES
+An NFSv4 ACL entry contains four or five colon-separated fields: an ACL tag,
+an ACL qualifier (only for
+.Dq Li user
+and
+.Dq Li group
+tags), discretionary access permissions, ACL inheritance flags, and ACL type:
+.Bl -tag -width indent
+.It Ar "ACL tag"
+The ACL tag specifies the ACL entry type and consists of
+one of the following:
+.Dq Li user
+or
+.Ql u
+specifying the access
+granted to the specified user;
+.Dq Li group
+or
+.Ql g
+specifying the access granted to the specified group;
+.Dq Li owner@
+specifying the access granted to the owner of the file;
+.Dq Li group@
+specifying the access granted to the file owning group;
+.Dq Li everyone@
+specifying everyone.  Note that
+.Dq Li everyone@
+is not the same as traditional Unix
+.Dq Li other
+- it means,
+literally, everyone, including file owner and owning group.
+.It Ar "ACL qualifier"
+The ACL qualifier field describes the user or group associated with
+the ACL entry.
+It may consist of one of the following: uid or
+user name, or gid or group name.  In entries whose tag type is
+one of 
+.Dq Li owner@ ,
+.Dq Li group@ ,
+or
+.Dq Li everyone@ ,
+this field is ommited altogether, including the trailing comma.
+.It Ar "access permissions"
+Access permissions may be specified in either short or long form.
+Short and long forms may not be mixed.
+Permissions in long form are separated by the
+.Ql /
+character; in short form, they are concatenated together.
+Valid permissions are:
+.Bl -tag -width ".Dv short"
+.It Short
+Long
+.It r
+read_data
+.It w
+write_data
+.It x
+execute
+.It p
+append_data
+.It d
+delete_child
+.It D
+delete
+.It a
+read_attributes
+.It A
+write_attributes
+.It R
+read_xattr
+.It W
+write_xattr
+.It c
+read_acl
+.It C
+write_acl
+.It o
+write_owner
+.It S
+synchronize
+.El
+.It Ar "ACL inheritance flags"
+Inheritance flags may be specified in either short or long form.
+Short and long forms may not be mixed.
+Access flags in long form are separated by the
+.Ql /
+character; in short form, they are concatenated together.
+Valid inheritance flags are:
+.Bl -tag -width ".Dv short"
+.It Short
+Long
+.It f
+file_inherit
+.It d
+dir_inherit
+.It i
+inherit_only
+.It n
+no_propagate
+.El
+.Pp
+Inheritance flags may be only set on directories.
+.It Ar "ACL type"
+The ACL type field is either
+.Dq Li allow
+or
+.Dq Li deny .
+.El
+.Pp
+ACL entries applied from a file using the
+.Fl M
+or
+.Fl X
+options shall be of the following form: one ACL entry per line, as
+previously specified; whitespace is ignored; any text after a
+.Ql #
+is ignored (comments).
+.Pp
+NFSv4 ACL entries are evaluated in their visible order.
+.Pp
+Multiple ACL entries specified on the command line are
+separated by commas.
 .Sh EXIT STATUS
 .Ex -std
 .Sh EXAMPLES
 .Dl setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx dir
 .Dl setfacl -d -m g:admins:rwx dir
 .Pp
-The first command sets the mandatory elements of the default ACL.
+The first command sets the mandatory elements of the POSIX.1e default ACL.
 The second command specifies that users in group admins can have read, write, and execute
 permissions for directory named "dir".
 It should be noted that any files or directories created underneath "dir" will
@@ -259,9 +396,13 @@ inherit these default ACLs upon creation
 .Pp
 Sets read, write, and execute permissions for the
 .Pa file
-owner's ACL entry and read and write permissions for group mail on
+owner's POSIX.1e ACL entry and read and write permissions for group mail on
 .Pa file .
 .Pp
+.Dl setfacl -m owner@:rwxp::allow,g:mail:rwp::allow file
+.Pp
+Semantically equal to the example above, but for NFSv4 ACL.
+.Pp
 .Dl setfacl -M file1 file2
 .Pp
 Sets/updates the ACL entries contained in
@@ -271,10 +412,15 @@ on
 .Pp
 .Dl setfacl -x g:mail:rw file
 .Pp
-Remove the group mail ACL entry containing read/write permissions
+Remove the group mail POSIX.1e ACL entry containing read/write permissions
 from
 .Pa file .
 .Pp
+.Dl setfacl -x0 file
+.Pp
+Remove the first entry from the NFSv4 ACL from
+.Pa file .
+.Pp
 .Dl setfacl -bn file
 .Pp
 Remove all

Modified: head/bin/setfacl/setfacl.c
==============================================================================
--- head/bin/setfacl/setfacl.c	Mon Sep  7 16:18:16 2009	(r196935)
+++ head/bin/setfacl/setfacl.c	Mon Sep  7 16:19:32 2009	(r196936)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 
 #include <err.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -41,9 +42,8 @@ __FBSDID("$FreeBSD$");
 
 #include "setfacl.h"
 
-static void   add_filename(const char *filename);
-static acl_t *get_file_acls(const char *filename);
-static void   usage(void);
+static void	add_filename(const char *filename);
+static void	usage(void);
 
 static void
 add_filename(const char *filename)
@@ -59,57 +59,28 @@ add_filename(const char *filename)
 	TAILQ_INSERT_TAIL(&filelist, file, next);
 }
 
-static acl_t *
-get_file_acls(const char *filename)
-{
-	acl_t *acl;
-	struct stat sb;
-
-	if (stat(filename, &sb) == -1) {
-		warn("stat() of %s failed", filename);
-		return (NULL);
-	}
-
-	acl = zmalloc(sizeof(acl_t) * 2);
-	if (h_flag)
-		acl[ACCESS_ACL] = acl_get_link_np(filename, ACL_TYPE_ACCESS);
-	else
-		acl[ACCESS_ACL] = acl_get_file(filename, ACL_TYPE_ACCESS);
-	if (acl[ACCESS_ACL] == NULL)
-		err(1, "acl_get_file() failed");
-	if (S_ISDIR(sb.st_mode)) {
-		if (h_flag)
-			acl[DEFAULT_ACL] = acl_get_link_np(filename,
-			    ACL_TYPE_DEFAULT);
-		else
-			acl[DEFAULT_ACL] = acl_get_file(filename,
-			    ACL_TYPE_DEFAULT);
-		if (acl[DEFAULT_ACL] == NULL)
-			err(1, "acl_get_file() failed");
-	} else
-		acl[DEFAULT_ACL] = NULL;
-
-	return (acl);
-}
-
 static void
 usage(void)
 {
 
-	fprintf(stderr, "usage: setfacl [-bdhkn] [-m entries] [-M file] "
-	    "[-x entries] [-X file] [file ...]\n");
+	fprintf(stderr, "usage: setfacl [-bdhkn] [-a position entries] "
+	    "[-m entries] [-M file] [-x entries] [-X file] [file ...]\n");
 	exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
-	acl_t *acl, final_acl;
+	acl_t acl;
+	acl_type_t acl_type;
 	char filename[PATH_MAX];
-	int local_error, carried_error, ch, i;
+	int local_error, carried_error, ch, i, entry_number, ret;
+	int h_flag;
 	struct sf_file *file;
 	struct sf_entry *entry;
 	const char *fn_dup;
+	char *end;
+	struct stat sb;
 
 	acl_type = ACL_TYPE_ACCESS;
 	carried_error = local_error = 0;
@@ -118,13 +89,13 @@ main(int argc, char *argv[])
 	TAILQ_INIT(&entrylist);
 	TAILQ_INIT(&filelist);
 
-	while ((ch = getopt(argc, argv, "M:X:bdhkm:nx:")) != -1)
+	while ((ch = getopt(argc, argv, "M:X:a:bdhkm:nx:")) != -1)
 		switch(ch) {
 		case 'M':
 			entry = zmalloc(sizeof(struct sf_entry));
 			entry->acl = get_acl_from_file(optarg);
 			if (entry->acl == NULL)
-				err(1, "get_acl_from_file() failed");
+				err(1, "%s: get_acl_from_file() failed", optarg);
 			entry->op = OP_MERGE_ACL;
 			TAILQ_INSERT_TAIL(&entrylist, entry, next);
 			break;
@@ -134,6 +105,25 @@ main(int argc, char *argv[])
 			entry->op = OP_REMOVE_ACL;
 			TAILQ_INSERT_TAIL(&entrylist, entry, next);
 			break;
+		case 'a':
+			entry = zmalloc(sizeof(struct sf_entry));
+
+			entry_number = strtol(optarg, &end, 10);
+			if (end - optarg != (int)strlen(optarg))
+				errx(1, "%s: invalid entry number", optarg);
+			if (entry_number < 0)
+				errx(1, "%s: entry number cannot be less than zero", optarg);
+			entry->entry_number = entry_number;
+
+			if (argv[optind] == NULL)
+				errx(1, "missing ACL");
+			entry->acl = acl_from_text(argv[optind]);
+			if (entry->acl == NULL)
+				err(1, "%s", argv[optind]);
+			optind++;
+			entry->op = OP_ADD_ACL;
+			TAILQ_INSERT_TAIL(&entrylist, entry, next);
+			break;
 		case 'b':
 			entry = zmalloc(sizeof(struct sf_entry));
 			entry->op = OP_REMOVE_EXT;
@@ -163,10 +153,18 @@ main(int argc, char *argv[])
 			break;
 		case 'x':
 			entry = zmalloc(sizeof(struct sf_entry));
-			entry->acl = acl_from_text(optarg);
-			if (entry->acl == NULL)
-				err(1, "%s", optarg);
-			entry->op = OP_REMOVE_ACL;
+			entry_number = strtol(optarg, &end, 10);
+			if (end - optarg == (int)strlen(optarg)) {
+				if (entry_number < 0)
+					errx(1, "%s: entry number cannot be less than zero", optarg);
+				entry->entry_number = entry_number;
+				entry->op = OP_REMOVE_BY_NUMBER;
+			} else {
+				entry->acl = acl_from_text(optarg);
+				if (entry->acl == NULL)
+					err(1, "%s", optarg);
+				entry->op = OP_REMOVE_ACL;
+			}
 			TAILQ_INSERT_TAIL(&entrylist, entry, next);
 			break;
 		default:
@@ -199,16 +197,51 @@ main(int argc, char *argv[])
 
 	/* cycle through each file */
 	TAILQ_FOREACH(file, &filelist, next) {
-		/* get our initial access and default ACL's */
-		acl = get_file_acls(file->filename);
-		if (acl == NULL)
+		local_error = 0;
+
+		if (stat(file->filename, &sb) == -1) {
+			warn("%s: stat() failed", file->filename);
 			continue;
-		if ((acl_type == ACL_TYPE_DEFAULT) && !acl[1]) {
-			warnx("Default ACL not valid for %s", file->filename);
+		}
+
+		if (acl_type == ACL_TYPE_DEFAULT && S_ISDIR(sb.st_mode) == 0) {
+			warnx("%s: default ACL may only be set on a directory",
+			    file->filename);
 			continue;
 		}
 
-		local_error = 0;
+		if (h_flag)
+			ret = lpathconf(file->filename, _PC_ACL_NFS4);
+		else
+			ret = pathconf(file->filename, _PC_ACL_NFS4);
+		if (ret > 0) {
+			if (acl_type == ACL_TYPE_DEFAULT) {
+				warnx("%s: there are no default entries "
+			           "in NFSv4 ACLs", file->filename);
+				continue;
+			}
+			acl_type = ACL_TYPE_NFS4;
+		} else if (ret == 0) {
+			if (acl_type == ACL_TYPE_NFS4)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list