changeset 5344:2d3435ff5f3d

6431736 c2audit needs to add support for auditing ZFS/NFS ACLs
author tz204579
date Fri, 26 Oct 2007 13:06:58 -0700
parents a0b027e2a7c7
children 44060de1d838
files usr/src/cmd/auditreduce/token.c usr/src/cmd/praudit/format.c usr/src/cmd/praudit/praudit.h usr/src/cmd/praudit/token.c usr/src/cmd/praudit/toktable.c usr/src/cmd/praudit/toktable.h usr/src/lib/auditd_plugins/syslog/systoken.c usr/src/lib/libbsm/adt_record.dtd.1 usr/src/lib/libbsm/adt_record.xsl.1 usr/src/lib/libbsm/common/adrm.c usr/src/lib/libbsm/common/libbsm.h usr/src/lib/libbsm/common/mapfile-vers usr/src/lib/libsec/common/acltext.c usr/src/lib/libsec/common/aclutils.h usr/src/uts/common/c2/audit_event.c usr/src/uts/common/c2/audit_record.h usr/src/uts/common/c2/audit_token.c
diffstat 17 files changed, 640 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/auditreduce/token.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/auditreduce/token.c	Fri Oct 26 13:06:58 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -177,7 +177,7 @@
 	adrm_u_short(adr, (ushort_t *)&magic_number, 1);
 	if (magic_number != AUT_TRAILER_MAGIC) {
 		(void) fprintf(stderr, "%s\n",
-			gettext("auditreduce: Bad trailer token"));
+		    gettext("auditreduce: Bad trailer token"));
 		return (-2);
 	}
 	adrm_u_int32(adr, &bytes, 1);
@@ -265,9 +265,9 @@
 	adrm_char(adr, &errnum, 1);
 	adrm_u_int32(adr, &value, 1);
 	if ((flags & M_SORF) &&
-		((global_class & mask.am_success) && (errnum == 0)) ||
-		((global_class & mask.am_failure) && (errnum != 0))) {
-			checkflags |= M_SORF;
+	    ((global_class & mask.am_success) && (errnum == 0)) ||
+	    ((global_class & mask.am_failure) && (errnum != 0))) {
+		checkflags |= M_SORF;
 	}
 	return (-1);
 }
@@ -288,9 +288,9 @@
 	adrm_char(adr, &errnum, 1);
 	adrm_u_int64(adr, &value, 1);
 	if ((flags & M_SORF) &&
-		((global_class & mask.am_success) && (errnum == 0)) ||
-		((global_class & mask.am_failure) && (errnum != 0))) {
-			checkflags |= M_SORF;
+	    ((global_class & mask.am_success) && (errnum == 0)) ||
+	    ((global_class & mask.am_failure) && (errnum != 0))) {
+		checkflags |= M_SORF;
 	}
 	return (-1);
 }
@@ -515,6 +515,13 @@
 	return (-1);
 }
 
+/*
+ * Format of acl token:
+ *	acl token id		adr_char
+ *	acl type		adr_u_int32
+ *	acl value		adr_u_int32 (depends on type)
+ *	file mode		adr_u_int (in octal)
+ */
 int
 acl_token(adr_t *adr)
 {
@@ -531,6 +538,29 @@
 }
 
 /*
+ * Format of ace token:
+ *	ace token id		adr_char
+ *	ace who			adr_u_int32 (uid/gid)
+ *	access mask		adr_u_int32
+ *	ace flags		adr_u_int16
+ *	ace type		adr_u_int16
+ */
+int
+ace_token(adr_t *adr)
+{
+	uid_t		who;
+	uint32_t	access_mask;
+	uint16_t	flags, type;
+
+	adrm_uid(adr, &who, 1);
+	adrm_u_int32(adr, &access_mask, 1);
+	adrm_u_short(adr, &flags, 1);
+	adrm_u_short(adr, &type, 1);
+
+	return (-1);
+}
+
+/*
  * Format of attribute token: (old pre SunOS 5.7 format)
  *	attribute token id	adr_char
  * 	mode			adr_int32 (printed in octal)
@@ -1704,7 +1734,8 @@
 			is += 1;
 			if (id > 0)
 				id--;
-			while (id > 0 && s[--id] != '/');
+			while (id > 0 && s[--id] != '/')
+				;
 			id++;
 			continue;
 		}
@@ -1713,11 +1744,13 @@
 			is += 2;
 			if (id > 0)
 				id--;
-			while (id > 0 && s[--id] != '/');
+			while (id > 0 && s[--id] != '/')
+				;
 			id++;
 			continue;
 		}
-		while (is < ls && (s[id++] = s[is++]) != '/');
+		while (is < ls && (s[id++] = s[is++]) != '/')
+			;
 		is--;
 	}
 	return (s);
--- a/usr/src/cmd/praudit/format.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/praudit/format.c	Fri Oct 26 13:06:58 2007 -0700
@@ -49,6 +49,7 @@
 #include <sys/inttypes.h>
 #include <sys/mkdev.h>
 #include <sys/types.h>
+#include <aclutils.h>
 
 #include "praudit.h"
 #include "toktable.h"
@@ -2017,32 +2018,16 @@
 		return (status);
 }
 
-
-/*
- * -----------------------------------------------------------------------
- * pa_pw_uid()	: Issues pr_adr_u_int32 to reads uid from input stream
- *		pointed to by audit_adr, and displays it in either
- *		raw form or its ASCII representation, if status >= 0.
- * return codes : -1 - error
- * 		:  1 - warning, passwd entry not found
- *		:  0 - successful
- * -----------------------------------------------------------------------
- */
-int
-pa_pw_uid(pr_context_t *context, int status, int flag)
+static int
+pa_print_uid(pr_context_t *context, uid_t uid, int status, int flag)
 {
 	int	returnstat;
 	struct passwd *pw;
-	uint32_t uid;
 	uval_t	uval;
 
 	if (status < 0)
 		return (status);
 
-	if (pr_adr_u_int32(context, &uid, 1) != 0)
-		/* cannot retrieve uid */
-		return (-1);
-
 	if (!(context->format & PRF_RAWM)) {
 		/* get password file entry */
 		if ((pw = getpwuid(uid)) == NULL) {
@@ -2066,29 +2051,39 @@
 
 /*
  * -----------------------------------------------------------------------
- * pa_gr_uid()	: Issues pr_adr_u_int32 to reads group uid from input stream
- *			pointed to by audit_adr, and displays it in either
- *			raw form or its ASCII representation, if status >= 0.
+ * pa_pw_uid()	: Issues pr_adr_u_int32 to reads uid from input stream
+ *		pointed to by audit_adr, and displays it in either
+ *		raw form or its ASCII representation, if status >= 0.
  * return codes : -1 - error
  * 		:  1 - warning, passwd entry not found
  *		:  0 - successful
  * -----------------------------------------------------------------------
  */
 int
-pa_gr_uid(pr_context_t *context, int status, int flag)
+pa_pw_uid(pr_context_t *context, int status, int flag)
+{
+	uint32_t uid;
+
+	if (status < 0)
+		return (status);
+
+	if (pr_adr_u_int32(context, &uid, 1) != 0)
+		/* cannot retrieve uid */
+		return (-1);
+
+	return (pa_print_uid(context, uid, status, flag));
+}
+
+static int
+pa_print_gid(pr_context_t *context, gid_t gid, int status, int flag)
 {
 	int	returnstat;
 	struct group *gr;
-	uint32_t gid;
 	uval_t	uval;
 
 	if (status < 0)
 		return (status);
 
-	if (pr_adr_u_int32(context, &gid, 1) != 0)
-		/* cannot retrieve gid */
-		return (-1);
-
 	if (!(context->format & PRF_RAWM)) {
 		/* get group file entry */
 		if ((gr = getgrgid(gid)) == NULL) {
@@ -2112,6 +2107,32 @@
 
 /*
  * -----------------------------------------------------------------------
+ * pa_gr_uid()	: Issues pr_adr_u_int32 to reads group uid from input stream
+ *			pointed to by audit_adr, and displays it in either
+ *			raw form or its ASCII representation, if status >= 0.
+ * return codes : -1 - error
+ * 		:  1 - warning, passwd entry not found
+ *		:  0 - successful
+ * -----------------------------------------------------------------------
+ */
+int
+pa_gr_uid(pr_context_t *context, int status, int flag)
+{
+	uint32_t gid;
+
+	if (status < 0)
+		return (status);
+
+	if (pr_adr_u_int32(context, &gid, 1) != 0)
+		/* cannot retrieve gid */
+		return (-1);
+
+	return (pa_print_gid(context, gid, status, flag));
+}
+
+
+/*
+ * -----------------------------------------------------------------------
  * pa_pw_uid_gr_gid()	: Issues pr_adr_u_int32 to reads uid or group uid
  *			from input stream
  *			pointed to by audit_adr, and displays it in either
@@ -2945,3 +2966,322 @@
 
 	return (returnstat);
 }
+
+static int
+pa_ace_flags(pr_context_t *context, ace_t *ace, int status, int flag)
+{
+	int	returnstat;
+	uval_t	uval;
+
+	if (status < 0)
+		return (status);
+
+	/*
+	 * TRANSLATION_NOTE
+	 * ace->a_flags refers to access flags of ZFS/NFSv4 ACL entry.
+	 */
+	if ((returnstat = open_tag(context, TAG_ACEFLAGS)) != 0)
+		return (returnstat);
+	if (!(context->format & PRF_RAWM)) {
+		uval.uvaltype = PRA_STRING;
+		switch (ace->a_flags & ACE_TYPE_FLAGS) {
+		case ACE_OWNER:
+			uval.string_val = gettext(OWNERAT_TXT);
+			break;
+		case ACE_GROUP | ACE_IDENTIFIER_GROUP:
+			uval.string_val = gettext(GROUPAT_TXT);
+			break;
+		case ACE_IDENTIFIER_GROUP:
+			uval.string_val = gettext(GROUP_TXT);
+			break;
+		case ACE_EVERYONE:
+			uval.string_val = gettext(EVERYONEAT_TXT);
+			break;
+		case 0:
+			uval.string_val = gettext(USER_TXT);
+			break;
+		default:
+			uval.uvaltype = PRA_USHORT;
+			uval.uint32_val = ace->a_flags;
+		}
+	} else {
+		uval.uvaltype = PRA_USHORT;
+		uval.uint32_val = ace->a_flags;
+	}
+	if ((returnstat = pa_print(context, &uval, flag)) != 0)
+		return (returnstat);
+	return (close_tag(context, TAG_ACEFLAGS));
+}
+
+static int
+pa_ace_who(pr_context_t *context, ace_t *ace, int status, int flag)
+{
+	int		returnstat;
+
+	if (status < 0)
+		return (status);
+
+	/*
+	 * TRANSLATION_NOTE
+	 * ace->a_who refers to user id or group id of ZFS/NFSv4 ACL entry.
+	 */
+	if ((returnstat = open_tag(context, TAG_ACEID)) != 0)
+		return (returnstat);
+	switch (ace->a_flags & ACE_TYPE_FLAGS) {
+	case ACE_IDENTIFIER_GROUP:	/* group id */
+		returnstat = pa_print_gid(context, ace->a_who, returnstat,
+		    flag);
+		break;
+	default:			/* user id */
+		returnstat = pa_print_uid(context, ace->a_who, returnstat,
+		    flag);
+		break;
+	}
+	if (returnstat < 0)
+		return (returnstat);
+	return (close_tag(context, TAG_ACEID));
+}
+
+/*
+ * Appends what to str, (re)allocating str if necessary.
+ */
+#define	INITIAL_ALLOC	256
+static int
+strappend(char **str, char *what, size_t *alloc)
+{
+	char	*s, *newstr;
+	size_t	needed;
+
+	s = *str;
+
+	if (s == NULL) {
+		s = malloc(INITIAL_ALLOC);
+		if (s == NULL) {
+			*alloc = 0;
+			return (-1);
+		}
+		*alloc = INITIAL_ALLOC;
+		s[0] = '\0';
+		*str = s;
+	}
+
+	needed = strlen(s) + strlen(what) + 1;
+	if (*alloc < needed) {
+		newstr = realloc(s, needed);
+		if (newstr == NULL)
+			return (-1);
+		s = newstr;
+		*alloc = needed;
+		*str = s;
+	}
+	(void) strlcat(s, what, *alloc);
+
+	return (0);
+}
+
+static int
+pa_ace_access_mask(pr_context_t *context, ace_t *ace, int status, int flag)
+{
+	int	returnstat, i;
+	uval_t	uval;
+	char	*permstr = NULL;
+	size_t	permstr_alloc = 0;
+
+	if (status < 0)
+		return (status);
+
+	/*
+	 * TRANSLATION_NOTE
+	 * ace->a_access_mask refers to access mask of ZFS/NFSv4 ACL entry.
+	 */
+	if ((returnstat = open_tag(context, TAG_ACEMASK)) != 0)
+		return (returnstat);
+	if (context->format & PRF_SHORTM &&
+	    ((permstr = malloc(15)) != NULL)) {
+		for (i = 0; i < 14; i++)
+			permstr[i] = '-';
+
+		if (ace->a_access_mask & ACE_READ_DATA)
+			permstr[0] = 'r';
+		if (ace->a_access_mask & ACE_WRITE_DATA)
+			permstr[1] = 'w';
+		if (ace->a_access_mask & ACE_EXECUTE)
+			permstr[2] = 'x';
+		if (ace->a_access_mask & ACE_APPEND_DATA)
+			permstr[3] = 'p';
+		if (ace->a_access_mask & ACE_DELETE)
+			permstr[4] = 'd';
+		if (ace->a_access_mask & ACE_DELETE_CHILD)
+			permstr[5] = 'D';
+		if (ace->a_access_mask & ACE_READ_ATTRIBUTES)
+			permstr[6] = 'a';
+		if (ace->a_access_mask & ACE_WRITE_ATTRIBUTES)
+			permstr[7] = 'A';
+		if (ace->a_access_mask & ACE_READ_NAMED_ATTRS)
+			permstr[8] = 'R';
+		if (ace->a_access_mask & ACE_WRITE_NAMED_ATTRS)
+			permstr[9] = 'W';
+		if (ace->a_access_mask & ACE_READ_ACL)
+			permstr[10] = 'c';
+		if (ace->a_access_mask & ACE_WRITE_ACL)
+			permstr[11] = 'C';
+		if (ace->a_access_mask & ACE_WRITE_OWNER)
+			permstr[12] = 'o';
+		if (ace->a_access_mask & ACE_SYNCHRONIZE)
+			permstr[13] = 's';
+		permstr[14] = '\0';
+		uval.uvaltype = PRA_STRING;
+		uval.string_val = permstr;
+	} else if (!(context->format & PRF_RAWM)) {
+
+		/*
+		 * Note this differs from acltext.c:ace_perm_txt()
+		 * because we don't know if the acl belongs to a file
+		 * or directory. ace mask value are the same
+		 * nonetheless, see sys/acl.h
+		 */
+		if (ace->a_access_mask & ACE_LIST_DIRECTORY) {
+			returnstat = strappend(&permstr, gettext(READ_DIR_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_ADD_FILE) {
+			returnstat = strappend(&permstr, gettext(ADD_FILE_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_ADD_SUBDIRECTORY) {
+			returnstat = strappend(&permstr, gettext(ADD_DIR_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_READ_NAMED_ATTRS) {
+			returnstat = strappend(&permstr,
+			    gettext(READ_XATTR_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_WRITE_NAMED_ATTRS) {
+			returnstat = strappend(&permstr,
+			    gettext(WRITE_XATTR_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_EXECUTE) {
+			returnstat = strappend(&permstr,
+			    gettext(EXECUTE_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_DELETE_CHILD) {
+			returnstat = strappend(&permstr,
+			    gettext(DELETE_CHILD_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_READ_ATTRIBUTES) {
+			returnstat = strappend(&permstr,
+			    gettext(READ_ATTRIBUTES_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_WRITE_ATTRIBUTES) {
+			returnstat = strappend(&permstr,
+			    gettext(WRITE_ATTRIBUTES_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_DELETE) {
+			returnstat = strappend(&permstr, gettext(DELETE_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_READ_ACL) {
+			returnstat = strappend(&permstr, gettext(READ_ACL_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_WRITE_ACL) {
+			returnstat = strappend(&permstr, gettext(WRITE_ACL_TXT),
+			    &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_WRITE_OWNER) {
+			returnstat = strappend(&permstr,
+			    gettext(WRITE_OWNER_TXT), &permstr_alloc);
+		}
+		if (ace->a_access_mask & ACE_SYNCHRONIZE) {
+			returnstat = strappend(&permstr,
+			    gettext(SYNCHRONIZE_TXT), &permstr_alloc);
+		}
+		if (permstr[strlen(permstr) - 1] == '/')
+			permstr[strlen(permstr) - 1] = '\0';
+		uval.uvaltype = PRA_STRING;
+		uval.string_val = permstr;
+	}
+	if ((permstr == NULL) || (returnstat != 0) ||
+	    (context->format & PRF_RAWM)) {
+		uval.uvaltype = PRA_UINT32;
+		uval.uint32_val = ace->a_access_mask;
+	}
+	returnstat = pa_print(context, &uval, flag);
+
+	if (permstr != NULL)
+		free(permstr);
+	if (returnstat != 0)
+		return (returnstat);
+	return (close_tag(context, TAG_ACEMASK));
+}
+
+static int
+pa_ace_type(pr_context_t *context, ace_t *ace, int status, int flag)
+{
+	int	returnstat;
+	uval_t	uval;
+
+	if (status < 0)
+		return (status);
+
+	/*
+	 * TRANSLATION_NOTE
+	 * ace->a_type refers to access type of ZFS/NFSv4 ACL entry.
+	 */
+	if ((returnstat = open_tag(context, TAG_ACETYPE)) != 0)
+		return (returnstat);
+	if (!(context->format & PRF_RAWM)) {
+		uval.uvaltype = PRA_STRING;
+		switch (ace->a_type) {
+		case ACE_ACCESS_ALLOWED_ACE_TYPE:
+			uval.string_val = gettext(ALLOW_TXT);
+			break;
+		case ACE_ACCESS_DENIED_ACE_TYPE:
+			uval.string_val = gettext(DENY_TXT);
+			break;
+		case ACE_SYSTEM_AUDIT_ACE_TYPE:
+			uval.string_val = gettext(AUDIT_TXT);
+			break;
+		case ACE_SYSTEM_ALARM_ACE_TYPE:
+			uval.string_val = gettext(ALARM_TXT);
+			break;
+		default:
+			uval.string_val = gettext(UNKNOWN_TXT);
+		}
+	} else {
+		uval.uvaltype = PRA_USHORT;
+		uval.uint32_val = ace->a_type;
+	}
+	if ((returnstat = pa_print(context, &uval, flag)) != 0)
+		return (returnstat);
+	return (close_tag(context, TAG_ACETYPE));
+}
+
+int
+pa_ace(pr_context_t *context, int status, int flag)
+{
+	int		returnstat;
+	ace_t		ace;
+
+	if (status < 0)
+		return (status);
+
+	if ((returnstat = pr_adr_u_int32(context, &ace.a_who, 1)) != 0)
+		return (returnstat);
+	if ((returnstat = pr_adr_u_int32(context, &ace.a_access_mask, 1)) != 0)
+		return (returnstat);
+	if ((returnstat = pr_adr_u_short(context, &ace.a_flags, 1)) != 0)
+		return (returnstat);
+	if ((returnstat = pr_adr_u_short(context, &ace.a_type, 1)) != 0)
+		return (returnstat);
+
+	if ((returnstat = pa_ace_flags(context, &ace, returnstat, 0)) != 0)
+		return (returnstat);
+	/* pa_ace_who can returns 1 if uid/gid is not found */
+	if ((returnstat = pa_ace_who(context, &ace, returnstat, 0)) < 0)
+		return (returnstat);
+	if ((returnstat = pa_ace_access_mask(context, &ace,
+	    returnstat, 0)) != 0)
+		return (returnstat);
+	return (pa_ace_type(context, &ace, returnstat, flag));
+}
--- a/usr/src/cmd/praudit/praudit.h	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/praudit/praudit.h	Fri Oct 26 13:06:58 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -209,6 +208,7 @@
 extern int	pa_pw_uid(pr_context_t *context, int status, int flag);
 extern int	pa_gr_uid(pr_context_t *context, int status, int flag);
 extern int	pa_pw_uid_gr_gid(pr_context_t *context, int status, int flag);
+extern int	pa_ace(pr_context_t *context, int status, int flag);
 extern int	pa_hostname(pr_context_t *context, int status, int flag);
 extern int	pa_hostname_ex(pr_context_t *context, int status, int flag);
 extern int	pa_hostname_so(pr_context_t *context, int status, int flag);
--- a/usr/src/cmd/praudit/token.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/praudit/token.c	Fri Oct 26 13:06:58 2007 -0700
@@ -462,7 +462,7 @@
 		case AUR_CHAR:
 			if (pr_adr_char(context, &c1, 1) == 0)
 				(void) convert_char_to_string(how_to_print,
-					c1, p);
+				    c1, p);
 			else {
 				free(p);
 				return (-1);
@@ -471,7 +471,7 @@
 		case AUR_SHORT:
 			if (pr_adr_short(context, &c2, 1) == 0)
 				(void) convert_short_to_string(how_to_print,
-					c2, p);
+				    c2, p);
 			else {
 				free(p);
 				return (-1);
@@ -480,7 +480,7 @@
 		case AUR_INT32:
 			if (pr_adr_int32(context, &c3, 1) == 0)
 				(void) convert_int32_to_string(how_to_print,
-					c3, p);
+				    c3, p);
 			else {
 				free(p);
 				return (-1);
@@ -489,7 +489,7 @@
 		case AUR_INT64:
 			if (pr_adr_int64(context, &c4, 1) == 0)
 				(void) convert_int64_to_string(how_to_print,
-					c4, p);
+				    c4, p);
 			else {
 				free(p);
 				return (-1);
@@ -716,7 +716,8 @@
 			is += 1;
 			if (id > 0)
 				id--;
-			while (id > 0 && s[--id] != '/');
+			while (id > 0 && s[--id] != '/')
+				;
 			id++;
 			continue;
 		}
@@ -725,11 +726,13 @@
 			is += 2;
 			if (id > 0)
 				id--;
-			while (id > 0 && s[--id] != '/');
+			while (id > 0 && s[--id] != '/')
+				;
 			id++;
 			continue;
 		}
-		while (is < ls && (s[id++] = s[is++]) != '/');
+		while (is < ls && (s[id++] = s[is++]) != '/')
+			;
 		is--;
 	}
 	return (s);
@@ -1712,6 +1715,26 @@
 
 /*
  * -----------------------------------------------------------------------
+ * ace_token()	: Process ZFS/NFSv4 access control list term
+ * return codes	: -1 - error
+ *		:  0 - successful
+ *
+ * Format of ace token:
+ *	token id	adr_char
+ *	term who	adr_u_int32 (uid/gid)
+ *	term mask	adr_u_int32
+ *	term flags	adr_u_int16
+ *	term type	adr_u_int16
+ * -----------------------------------------------------------------------
+ */
+int
+ace_token(pr_context_t *context)
+{
+	return (pa_ace(context, 0, 1));
+}
+
+/*
+ * -----------------------------------------------------------------------
  * attribute_token()	: Process attribute token and display contents
  * return codes 	: -1 - error
  *			:  0 - successful
--- a/usr/src/cmd/praudit/toktable.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/praudit/toktable.c	Fri Oct 26 13:06:58 2007 -0700
@@ -115,6 +115,7 @@
 	 */
 
 	table_init(AUT_ACL, "acl", acl_token, T_ENCLOSED);
+	table_init(AUT_ACE, "acl", ace_token, T_ENCLOSED);
 	table_init(AUT_ATTR, "attribute", attribute_token, T_ENCLOSED);
 	table_init(AUT_IPC_PERM, "IPC_perm", s5_IPC_perm_token, T_ENCLOSED);
 	table_init(AUT_GROUPS, "group", group_token, T_ELEMENT);
@@ -281,6 +282,10 @@
 
 	table_init(TAG_ACLTYPE, "type", NOFUNC, T_ATTRIBUTE);
 	table_init(TAG_ACLVAL, "value", NOFUNC, T_ATTRIBUTE);
+	table_init(TAG_ACEMASK, "access_mask", NOFUNC, T_ATTRIBUTE);
+	table_init(TAG_ACEFLAGS, "flags", NOFUNC, T_ATTRIBUTE);
+	table_init(TAG_ACETYPE, "type", NOFUNC, T_ATTRIBUTE);
+	table_init(TAG_ACEID, "id", NOFUNC, T_ATTRIBUTE);
 	table_init(TAG_SOCKTYPE, "type", pa_adr_shorthex, T_ATTRIBUTE);
 	table_init(TAG_SOCKPORT, "port", pa_adr_shorthex, T_ATTRIBUTE);
 	table_init(TAG_SOCKADDR, "addr", NOFUNC, T_ATTRIBUTE);
--- a/usr/src/cmd/praudit/toktable.h	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/cmd/praudit/toktable.h	Fri Oct 26 13:06:58 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -153,6 +153,10 @@
 	TAG_IP_LOCAL,			/* with tid token, type=ip */
 	TAG_IP_REMOTE,			/* with tid token, type=ip */
 	TAG_IP_ADR,			/* with tid token, type=ip */
+	TAG_ACEMASK,			/* with ace token */
+	TAG_ACEFLAGS,			/* with ace token */
+	TAG_ACETYPE,			/* with ace token */
+	TAG_ACEID,			/* with ace token */
 	MAXTAG
 };
 
@@ -197,6 +201,7 @@
  */
 
 extern int	acl_token();
+extern int	ace_token();
 extern int	attribute_token();
 extern int	s5_IPC_perm_token();
 extern int	group_token();
--- a/usr/src/lib/auditd_plugins/syslog/systoken.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/auditd_plugins/syslog/systoken.c	Fri Oct 26 13:06:58 2007 -0700
@@ -533,10 +533,33 @@
 	return (0);
 }
 
+/*
+ * Format of acl token:
+ * 	acl token id		adr_char
+ *	type			adr_u_int32
+ *	value			adr_u_int32
+ *	mode			adr_u_int32
+ */
 int
 acl_token(parse_context_t *ctx)
 {
-	ctx->adr.adr_now += 3 * sizeof (int32_t);
+	ctx->adr.adr_now += 3 * sizeof (uint32_t);
+
+	return (0);
+}
+
+/*
+ * Format of ace token:
+ * 	ace token id		adr_char
+ *	id			adr_u_int32
+ *	access_mask		adr_u_int32
+ *	flags			adr_u_short
+ *	type			adr_u_short
+ */
+int
+ace_token(parse_context_t *ctx)
+{
+	ctx->adr.adr_now += 2 * sizeof (uint32_t) + 2 * sizeof (ushort_t);
 
 	return (0);
 }
--- a/usr/src/lib/libbsm/adt_record.dtd.1	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libbsm/adt_record.dtd.1	Fri Oct 26 13:06:58 2007 -0700
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -350,9 +350,12 @@
 <!-- acl token -->
 <!ELEMENT acl			EMPTY>
 <!ATTLIST acl
-		type		CDATA #REQUIRED
-		value		CDATA #REQUIRED
-		mode		CDATA #REQUIRED
+		type		CDATA #IMPLIED
+		value		CDATA #IMPLIED
+		mode		CDATA #IMPLIED
+		flags		CDATA #IMPLIED
+		id		CDATA #IMPLIED
+		access_mask	CDATA #IMPLIED
 >
 
 <!-- tid token -->
--- a/usr/src/lib/libbsm/adt_record.xsl.1	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libbsm/adt_record.xsl.1	Fri Oct 26 13:06:58 2007 -0700
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -354,9 +354,19 @@
 <xsl:template match="acl">
 	<BR/>
 	<I>ACL </I>
-	<I> type: </I><xsl:value-of select="@type"/>
-	<I> value: </I><xsl:value-of select="@value"/>
-	<I> mode: </I><xsl:value-of select="@mode"/>
+	<xsl:choose>
+		<xsl:when test="@mode">	<!-- old ACL entry -->
+			<I> type: </I><xsl:value-of select="@type"/>
+			<I> value: </I><xsl:value-of select="@value"/>
+			<I> mode: </I><xsl:value-of select="@mode"/>
+		</xsl:when>
+		<xsl:otherwise>
+			<I> flags: </I><xsl:value-of select="@flags"/>
+			<I> id: </I><xsl:value-of select="@id"/>
+			<I> access_mask: </I><xsl:value-of select="@access_mask"/>
+			<I> type: </I><xsl:value-of select="@type"/>
+		</xsl:otherwise>
+	</xsl:choose>
 </xsl:template>
 
 <xsl:template match="tid">
--- a/usr/src/lib/libbsm/common/adrm.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libbsm/common/adrm.c	Fri Oct 26 13:06:58 2007 -0700
@@ -86,6 +86,20 @@
 }
 
 void
+adrm_uid(adr_t *adr, uid_t *up, int count)
+{
+	int i;
+
+	for (; count-- > 0; up++) {
+		*up = 0;
+		for (i = 0; i < 4; i++) {
+			*up <<= 8;
+			*up += ((uid_t)*adr->adr_now++) & 0x000000ff;
+		}
+	}
+}
+
+void
 adrm_int64(adr_t *adr, int64_t *lp, int count)
 {
 	int i;
@@ -142,7 +156,7 @@
 	for (; count-- > 0; lp++) {
 		for (i = 0, l = *lp; i < 4; i++) {
 			*adr->adr_now++ = (char)((l & (int32_t)0xff000000) >>
-				(int)24);
+			    (int)24);
 			l <<= (int)8;
 		}
 	}
--- a/usr/src/lib/libbsm/common/libbsm.h	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libbsm/common/libbsm.h	Fri Oct 26 13:06:58 2007 -0700
@@ -129,6 +129,7 @@
 extern void	adrm_short(adr_t *, short *, int);
 extern void	adrm_int64(adr_t *, int64_t *, int);
 extern void	adrm_int32(adr_t *, int32_t *, int);
+extern void	adrm_uid(adr_t *, uid_t *, int);
 extern void	adrm_u_int32(adr_t *, uint32_t *, int);
 extern void	adrm_u_char(adr_t *, uchar_t *, int);
 extern void	adrm_u_int64(adr_t *, uint64_t *, int);
--- a/usr/src/lib/libbsm/common/mapfile-vers	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libbsm/common/mapfile-vers	Fri Oct 26 13:06:58 2007 -0700
@@ -139,6 +139,7 @@
 	adrm_u_int32;
 	adrm_u_int64;
 	adrm_u_short;
+	adrm_uid;
 	adr_short;
 	adr_start;
 	adt_alloc_event;
--- a/usr/src/lib/libsec/common/acltext.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libsec/common/acltext.c	Fri Oct 26 13:06:58 2007 -0700
@@ -234,12 +234,6 @@
 	}
 }
 
-#define	OWNERAT_TXT	"owner@"
-#define	GROUPAT_TXT	"group@"
-#define	EVERYONEAT_TXT	"everyone@"
-#define	GROUP_TXT	"group:"
-#define	USER_TXT	"user:"
-
 char *
 ace_type_txt(char *buf, char **endp, ace_t *acep, int flags)
 {
@@ -283,24 +277,6 @@
 	return (buf);
 }
 
-#define	READ_DATA_TXT	"read_data/"
-#define	WRITE_DATA_TXT	"write_data/"
-#define	EXECUTE_TXT	"execute/"
-#define	READ_XATTR_TXT	"read_xattr/"
-#define	WRITE_XATTR_TXT	"write_xattr/"
-#define	READ_ATTRIBUTES_TXT "read_attributes/"
-#define	WRITE_ATTRIBUTES_TXT "write_attributes/"
-#define	DELETE_TXT	"delete/"
-#define	DELETE_CHILD_TXT "delete_child/"
-#define	WRITE_OWNER_TXT "write_owner/"
-#define	READ_ACL_TXT	"read_acl/"
-#define	WRITE_ACL_TXT	"write_acl/"
-#define	APPEND_DATA_TXT "append_data/"
-#define	READ_DIR_TXT	"list_directory/read_data/"
-#define	ADD_DIR_TXT	"add_subdirectory/append_data/"
-#define	ADD_FILE_TXT	"add_file/write_data/"
-#define	SYNCHRONIZE_TXT "synchronize"	/* not slash on this one */
-
 char *
 ace_perm_txt(char *buf, char **endp, uint32_t mask,
     uint32_t iflags, int isdir, int flags)
@@ -473,11 +449,6 @@
 	return (buf);
 }
 
-#define	ALLOW_TXT	"allow"
-#define	DENY_TXT	"deny"
-#define	ALARM_TXT	"alarm"
-#define	AUDIT_TXT	"audit"
-#define	UNKNOWN_TXT	"unknown"
 char *
 ace_access_txt(char *buf, char **endp, int type)
 {
--- a/usr/src/lib/libsec/common/aclutils.h	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/lib/libsec/common/aclutils.h	Fri Oct 26 13:06:58 2007 -0700
@@ -62,6 +62,46 @@
 	uint32_t	perm_val;	/* numeric value being returned */
 };
 
+
+/*
+ * Textual representation of ace_t's access mask
+ */
+#define	READ_DATA_TXT	"read_data/"
+#define	WRITE_DATA_TXT	"write_data/"
+#define	EXECUTE_TXT	"execute/"
+#define	READ_XATTR_TXT	"read_xattr/"
+#define	WRITE_XATTR_TXT	"write_xattr/"
+#define	READ_ATTRIBUTES_TXT "read_attributes/"
+#define	WRITE_ATTRIBUTES_TXT "write_attributes/"
+#define	DELETE_TXT	"delete/"
+#define	DELETE_CHILD_TXT "delete_child/"
+#define	WRITE_OWNER_TXT "write_owner/"
+#define	READ_ACL_TXT	"read_acl/"
+#define	WRITE_ACL_TXT	"write_acl/"
+#define	APPEND_DATA_TXT "append_data/"
+#define	READ_DIR_TXT	"list_directory/read_data/"
+#define	ADD_DIR_TXT	"add_subdirectory/append_data/"
+#define	ADD_FILE_TXT	"add_file/write_data/"
+#define	SYNCHRONIZE_TXT "synchronize"	/* not slash on this one */
+
+/*
+ * ace_t's flags
+ */
+#define	OWNERAT_TXT	"owner@"
+#define	GROUPAT_TXT	"group@"
+#define	EVERYONEAT_TXT	"everyone@"
+#define	GROUP_TXT	"group:"
+#define	USER_TXT	"user:"
+
+/*
+ * ace_t's access types
+ */
+#define	ALLOW_TXT	"allow"
+#define	DENY_TXT	"deny"
+#define	ALARM_TXT	"alarm"
+#define	AUDIT_TXT	"audit"
+#define	UNKNOWN_TXT	"unknown"
+
 extern char *yybuf;
 extern acl_t *yyacl;
 
--- a/usr/src/uts/common/c2/audit_event.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/uts/common/c2/audit_event.c	Fri Oct 26 13:06:58 2007 -0700
@@ -5031,10 +5031,15 @@
 
 	switch (uap->cmd) {
 	case SETACL:
-		/* ok, acl(SETACL, ...) and facl(SETACL, ...)  are expected. */
+	case ACE_SETACL:
+		/*
+		 * acl(SETACL/ACE_SETACL, ...) and facl(SETACL/ACE_SETACL, ...)
+		 * are expected.
+		 */
 		break;
 	case GETACL:
 	case GETACLCNT:
+	case ACE_GETACLCNT:
 		/* do nothing for these two values. */
 		e = AUE_NULL;
 		break;
@@ -5046,6 +5051,56 @@
 	return (e);
 }
 
+static void
+au_acl(int cmd, int nentries, caddr_t bufp)
+{
+	size_t		a_size;
+	aclent_t	*aclbufp;
+	ace_t		*acebufp;
+	int		i;
+
+	switch (cmd) {
+	case GETACL:
+	case GETACLCNT:
+		break;
+	case SETACL:
+		if (nentries < 3)
+			break;
+
+		a_size = nentries * sizeof (aclent_t);
+
+		if ((aclbufp = kmem_alloc(a_size, KM_SLEEP)) == NULL)
+			break;
+		if (copyin(bufp, aclbufp, a_size)) {
+			kmem_free(aclbufp, a_size);
+			break;
+		}
+		for (i = 0; i < nentries; i++) {
+			au_uwrite(au_to_acl(aclbufp + i));
+		}
+		kmem_free(aclbufp, a_size);
+		break;
+
+	case ACE_SETACL:
+		if (nentries < 1 || nentries > MAX_ACL_ENTRIES)
+			break;
+
+		a_size = nentries * sizeof (ace_t);
+		if ((acebufp = kmem_alloc(a_size, KM_SLEEP)) == NULL)
+			break;
+		if (copyin(bufp, acebufp, a_size)) {
+			kmem_free(acebufp, a_size);
+			break;
+		}
+		for (i = 0; i < nentries; i++) {
+			au_uwrite(au_to_ace(acebufp + i));
+		}
+		kmem_free(acebufp, a_size);
+		break;
+	default:
+		break;
+	}
+}
 
 /*ARGSUSED*/
 static void
@@ -5057,36 +5112,11 @@
 		long	nentries;
 		long	aclbufp;
 	} *uap = (struct a *)ttolwp(curthread)->lwp_ap;
-	struct acl *aclbufp;
 
 	au_uwrite(au_to_arg32(2, "cmd", (uint32_t)uap->cmd));
 	au_uwrite(au_to_arg32(3, "nentries", (uint32_t)uap->nentries));
 
-	switch (uap->cmd) {
-	case GETACL:
-	case GETACLCNT:
-		break;
-	case SETACL:
-		if (uap->nentries < 3)
-			break;
-		else {
-			size_t a_size = uap->nentries * sizeof (struct acl);
-			int i;
-
-			aclbufp = kmem_alloc(a_size, KM_SLEEP);
-			if (copyin((caddr_t)(uap->aclbufp), aclbufp, a_size)) {
-				kmem_free(aclbufp, a_size);
-				break;
-			}
-			for (i = 0; i < uap->nentries; i++) {
-				au_uwrite(au_to_acl(aclbufp + i));
-			}
-			kmem_free(aclbufp, a_size);
-			break;
-		}
-	default:
-		break;
-	}
+	au_acl(uap->cmd, uap->nentries, (caddr_t)uap->aclbufp);
 }
 
 /*ARGSUSED*/
@@ -5102,7 +5132,6 @@
 	struct file  *fp;
 	struct vnode *vp;
 	struct f_audit_data *fad;
-	struct acl *aclbufp;
 	int fd;
 
 	au_uwrite(au_to_arg32(2, "cmd", (uint32_t)uap->cmd));
@@ -5127,31 +5156,7 @@
 	/* decrement file descriptor reference count */
 	releasef(fd);
 
-	switch (uap->cmd) {
-	case GETACL:
-	case GETACLCNT:
-		break;
-	case SETACL:
-		if (uap->nentries < 3)
-			break;
-		else {
-			size_t a_size = uap->nentries * sizeof (struct acl);
-			int i;
-
-			aclbufp = kmem_alloc(a_size, KM_SLEEP);
-			if (copyin((caddr_t)(uap->aclbufp), aclbufp, a_size)) {
-				kmem_free(aclbufp, a_size);
-				break;
-			}
-			for (i = 0; i < uap->nentries; i++) {
-				au_uwrite(au_to_acl(aclbufp + i));
-			}
-			kmem_free(aclbufp, a_size);
-			break;
-		}
-	default:
-		break;
-	}
+	au_acl(uap->cmd, uap->nentries, (caddr_t)uap->aclbufp);
 }
 
 /*ARGSUSED*/
--- a/usr/src/uts/common/c2/audit_record.h	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/uts/common/c2/audit_record.h	Fri Oct 26 13:06:58 2007 -0700
@@ -110,8 +110,9 @@
 #define	AUT_IPC_PERM		((char)0x32)
 #define	AUT_LABEL		((char)0x33)
 #define	AUT_GROUPS		((char)0x34)
+#define	AUT_ACE			((char)0x35)
 /*
- * 0x35, 0x36, 0x37 unused
+ * 0x36, 0x37 unused
  */
 #define	AUT_PRIV		((char)0x38)
 #define	AUT_UPRIV		((char)0x39)
@@ -265,6 +266,7 @@
 #define	au_toss_token(tok)	(au_free_rec((au_buff_t *)(tok)))
 
 token_t *au_to_acl();
+token_t *au_to_ace();
 token_t *au_to_attr(struct vattr *);
 token_t *au_to_data(char, char, char, char *);
 token_t *au_to_header(int, au_event_t, au_emod_t);
--- a/usr/src/uts/common/c2/audit_token.c	Fri Oct 26 12:46:04 2007 -0700
+++ b/usr/src/uts/common/c2/audit_token.c	Fri Oct 26 13:06:58 2007 -0700
@@ -895,6 +895,27 @@
 	return (m);
 }
 
+token_t *
+au_to_ace(ace_t *acep)
+{
+	token_t *m;				/* local au_membuf */
+	adr_t adr;				/* adr memory stream header */
+	char data_header = AUT_ACE;		/* header for this token */
+
+	m = au_getclr();
+
+	adr_start(&adr, memtod(m, char *));
+	adr_char(&adr, &data_header, 1);
+
+	adr_uint32(&adr, &(acep->a_who), 1);
+	adr_uint32(&adr, &(acep->a_access_mask), 1);
+	adr_ushort(&adr, &(acep->a_flags), 1);
+	adr_ushort(&adr, &(acep->a_type), 1);
+
+	m->len = adr_count(&adr);
+	return (m);
+}
+
 /*
  * au_to_ipc_perm
  * returns: