All,

Please find attached a patch against the latest svn repository for your
review.

This patch

a. Fixes a bug where if print_recv() is passed a zero value, no output
is generated
b. When print_clone_flags() cannot interpret the passed flags, will
print the flags as a hex value, rather than a decimal.
c. Fixes a bug in that the last value printed on a line has a space
appended.
d. Parses the op key value for CONFIG_CHANGE as a string.
e. Introduces a new option to ausearch, --einterpret that, like the
--interpret option, generates human readable output, but has the
additional feature of making the output easier to parse. See ausearch
manual for sub-options.


Regards
Burn Alting

diff -Npru trunk_0/auparse/interpret.c trunk_burn2/auparse/interpret.c
--- trunk_0/auparse/interpret.c	2013-05-11 14:49:41.000000000 +1000
+++ trunk_burn2/auparse/interpret.c	2013-05-12 11:51:46.355642475 +1000
@@ -970,7 +970,7 @@ static const char *print_clone_flags(con
 	}
 
 	if (buf[0] == 0)
-		snprintf(buf, sizeof(buf), "%d", flags);
+		snprintf(buf, sizeof(buf), "0x%x", flags);
 	return strdup(buf);
 }
 
@@ -1270,6 +1270,8 @@ static const char *print_recv(const char
 			}
                 }
         }
+	if (buf[0] == 0)
+		snprintf(buf, sizeof(buf), "0x%x", rec);
 	return strdup(buf);
 }
 
@@ -2085,7 +2087,10 @@ int interp_adjust_type(int rtype, const
 	} else if (rtype == AUDIT_PATH && *name =='f' &&
 			strcmp(name, "flags") == 0)
 		type = AUPARSE_TYPE_FLAGS;
-	 else
+	else if (rtype == AUDIT_CONFIG_CHANGE && *name == 'o' &&
+			(strcmp(name, "op") == 0) && val[0] == '"')
+		type = AUPARSE_TYPE_ESCAPED;
+	else
 		type = lookup_type(name);
 
 	return type;
diff -Npru trunk_0/docs/ausearch.8 trunk_burn2/docs/ausearch.8
--- trunk_0/docs/ausearch.8	2013-05-11 14:49:41.000000000 +1000
+++ trunk_burn2/docs/ausearch.8	2013-05-11 16:03:57.008872889 +1000
@@ -24,6 +24,44 @@ Search for an event based on the given \
 .BR \-e,\  \-\-exit \ \fIexit-code-or-errno\fP
 Search for an event based on the given syscall \fIexit code or errno\fP.
 .TP
+.BR \-\-einterpret \ \fIenhanced-interpretation-option-list\fP
+Provide an enhanced form of intepreting numeric entities into text. The enhancements are driven by \fIenhanced-interpretation-option-list\fP, which is a
+comma separated list of enhancement options. These are
+.RS
+.TP 12
+.B enhancedstr
+When interpreting strings, escape all double quote characters (\fI"\fP) with a backslash (\fI\\\fP). Further, all non printing characters are printed as their escaped ('\fI\\\fP'-prefixed) octal values. Non printing values are those outside the range of 0x20 (space) thru 0x7E (tilda).
+.TP
+.B ogid
+As well as printing the group name matching a group id, also print the group id. This is to aid de-conflicting inadvertent group attribution across an enterprise environment. The printed output is of the form \fIgroupname(gid)\fP.
+.TP
+.B otime
+Do NOT interpret the event time and leave it in it's form found in the audit.log files. That is the number of seconds and milliseconds since the epoch. This effectively maintains the event time should your processed events be passed to another system outside of your local timezone.
+
+.TP
+.BR \-\-einterpret \ \fIenhanced-interpretation-option-list\fP
+Provide an enhanced form of intepreting numeric entities into text. The enhancements are driven by \fIenhanced-interpretation-option-list\fP, which is a
+comma separated list of enhancement options. These are
+.RS
+.TP 12
+.B enhancedstr
+When interpreting strings, escape all double quote characters (\fI"\fP) with a backslash (\fI\\\fP). Further, all non printing characters are printed as their escaped ('\fI\\\fP'-prefixed) octal values. Non printing values are those outside the range of 0x20 (space) thru 0x7E (tilda).
+.TP
+.B ogid
+As well as printing the group name matching a group id, also print the group id. This is to aid de-conflicting inadvertent group attribution across an enterprise environment. The printed output is of the form \fIgroupname(gid)\fP.
+.TP
+.B otime
+Do NOT interpret the event time and leave it in it's form found in the audit.log files. That is the number of seconds and milliseconds since the epoch. This effectively maintains the event time should your processed events be passed to another system outside of your local timezone.
+uid
+As well as printing the user name matching a user id, also print the user id.This is to aid de-conflicting inadvertent user attribution across an enterprise environment. The printed output is of the form \fIusername(uid)\fP.
+.TP
+.B qvalues
+To aid subsequent parsing of the interpreted values, this option ensures the values are surrounded by double quotes (\fI"\fP).
+.TP
+.B rfc3339
+Output the event time value in RFC3339 format.
+.RE
+.TP
 .BR \-f ,\  \-\-file \ \fIfile-name\fP
 Search for an event based on the given \fIfilename\fP.
 .TP
diff -Npru trunk_0/src/ausearch.c trunk_burn2/src/ausearch.c
--- trunk_0/src/ausearch.c	2013-05-11 14:49:40.000000000 +1000
+++ trunk_burn2/src/ausearch.c	2013-05-12 09:52:30.014768972 +1000
@@ -98,6 +98,10 @@ int main(int argc, char *argv[])
 		rc = process_stdin();
 	else
 		rc = process_logs();
+	if (enhanced_interpret & ENHANCED_ESTRING) {
+		extern void	FreeEnhancedBuffer();
+		FreeEnhancedBuffer();
+	}
 	lol_clear(&lo);
 	ilist_clear(event_type);
 	free(event_type);
diff -Npru trunk_0/src/ausearch-common.h trunk_burn2/src/ausearch-common.h
--- trunk_0/src/ausearch-common.h	2013-05-11 14:49:40.000000000 +1000
+++ trunk_burn2/src/ausearch-common.h	2013-05-11 16:05:58.807498388 +1000
@@ -56,5 +56,17 @@ extern failed_t event_failed;
 extern conf_act_t event_conf_act;
 extern success_t event_success;
 
+/*
+ * Enhanced reporting options.
+ */
+#define	ENHANCED_QVALUES	0x001	/* surround values in quotes */
+#define	ENHANCED_ESTRING	0x002	/* enhance the string output */
+#define	ENHANCED_OTIME		0x004	/* message header time in orginal form */
+#define	ENHANCED_OUID		0x008	/* include orginal uid in output */
+#define	ENHANCED_OGID		0x010	/* include orginal gid in output */
+#define	ENHANCED_RFC3339TIME	0x020	/* message header time in RFC339 form */
+
+extern unsigned	enhanced_interpret;
+
 #endif
 
diff -Npru trunk_0/src/ausearch-options.c trunk_burn2/src/ausearch-options.c
--- trunk_0/src/ausearch-options.c	2013-05-11 14:49:40.000000000 +1000
+++ trunk_burn2/src/ausearch-options.c	2013-05-11 16:10:32.808650742 +1000
@@ -40,6 +40,7 @@
 /* Global vars that will be accessed by the main program */
 char *user_file = NULL;
 int force_logs = 0;
+unsigned enhanced_interpret = 0x0;	/* enhanced interpretation flags */
 
 /* Global vars that will be accessed by the match model */
 unsigned int event_id = -1;
@@ -81,7 +82,7 @@ S_HOSTNAME, S_INTERP, S_INFILE, S_MESSAG
 S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID,
 S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT,
 S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT,
-S_LINEBUFFERED, S_UUID, S_VMNAME};
+S_LINEBUFFERED, S_UUID, S_VMNAME, S_EINTERP};
 
 static struct nv_pair optiontab[] = {
 	{ S_EVENT, "-a" },
@@ -90,6 +91,7 @@ static struct nv_pair optiontab[] = {
 	{ S_COMM, "--comm" },
 	{ S_EXIT, "-e" },
 	{ S_EXIT, "--exit" },
+	{ S_EINTERP, "--einterpret" },
 	{ S_FILENAME, "-f" },
 	{ S_FILENAME, "--file" },
 	{ S_ALL_GID, "-ga" },
@@ -171,12 +173,67 @@ static int audit_lookup_option(const cha
         return -1;
 }
 
+/*
+ * Enhanced Interpreted reporting options
+ */
+static struct nv_pair eoptstab[] = {
+	{ ENHANCED_QVALUES, "qvalues" },
+	{ ENHANCED_ESTRING, "enhancedstr" },
+	{ ENHANCED_OTIME, "otime" },
+	{ ENHANCED_OUID, "ouid" },
+	{ ENHANCED_OGID, "ogid" },
+	{ ENHANCED_RFC3339TIME, "rfc3339" }
+};
+#define EOPTION_CNT (sizeof(eoptstab)/sizeof(eoptstab[0]))
+
+/*
+ * Parse a comma separated list of options
+ * Rtns:
+ * 0		memory or parse failure
+ * unsigned	flag word
+ */
+static unsigned parse_enhanced_options(const char *eopts)
+{
+	unsigned	ev = 0;
+	char		* es, * les;
+        int		i;
+
+	/*
+ 	 * Since we are strtok'ing, dup first
+ 	 */
+	if ((les = strdup(eopts)) == NULL)
+		return 0;
+	es = strtok(les, ",");
+	if (es == NULL) {
+		(void)free(les);
+		return 0;
+	}
+
+	do {
+        	for (i = 0; i < EOPTION_CNT; i++) {
+               		if (strcmp(eoptstab[i].name, es) == 0) {
+				ev |= eoptstab[i].value;	/* OR in the flag */
+				break;	/* out of the for loop */
+			}
+		}
+		if (i == EOPTION_CNT) {
+			fprintf(stderr, "Invalid enhanced option - %s\n", es);
+			(void)free(les);
+			return 0;
+		}
+	} while ((es = strtok(NULL, ",")));
+
+	(void)free(les);
+        return ev;
+}
+
 static void usage(void)
 {
 	printf("usage: ausearch [options]\n"
 	"\t-a,--event <Audit event id>\tsearch based on audit event id\n"
 	"\t-c,--comm  <Comm name>\t\tsearch based on command line name\n"
 	"\t-e,--exit  <Exit code or errno>\tsearch based on syscall exit code\n"
+	"\t--einterpret <optionlist>\tInterpret results to be human readable and more parsable\n"
 	"\t-f,--file  <File name>\t\tsearch based on file name\n"
 	"\t-ga,--gid-all <all Group id>\tsearch based on All group ids\n"
 	"\t-ge,--gid-effective <effective Group id>  search based on Effective\n\t\t\t\t\tgroup id\n"
@@ -1099,6 +1156,34 @@ int check_params(int count, char *vars[]
 		case S_LINEBUFFERED:
 			line_buffered = 1;
 			break;
+		case S_EINTERP:
+			if (!optarg) {
+				fprintf(stderr, 
+					"Argument is required for %s\n",
+					vars[c]);
+				retval = -1;
+				break;
+			}
+			if (report_format == RPT_DEFAULT)
+				report_format = RPT_INTERP;
+			else {
+				fprintf(stderr, 
+					"Conflicting output format %s\n",
+					vars[c]);
+        	                retval = -1;
+			}
+			/*
+ 			 * Options are
+ 			 *  qvalues	- quote values
+ 			 *  enhancedstr	- enhance string output
+ 			 *  otime       - time to be in original form
+ 			 *  ...
+ 			 *  see parse_enhanced_options()
+ 			 */
+			if ((enhanced_interpret = parse_enhanced_options(optarg)) == 0)
+				retval = -1;
+			c++;	/* we have processed optarg, so move along */
+			break;
 		default:
 			fprintf(stderr, "%s is an unsupported option\n", 
 				vars[c]);
diff -Npru trunk_0/src/ausearch-report.c trunk_burn2/src/ausearch-report.c
--- trunk_0/src/ausearch-report.c	2013-05-11 14:49:40.000000000 +1000
+++ trunk_burn2/src/ausearch-report.c	2013-05-12 12:12:07.549262673 +1000
@@ -140,7 +140,7 @@ static void output_interpreted(llist *l)
 static void output_interpreted_node(const lnode *n)
 {
 	char *ptr, *str = n->message, *node = NULL;
-	int found;
+	int found, skip_emit;
 
 	// Reset these because each record could be different
 	machine = -1;
@@ -166,7 +166,7 @@ static void output_interpreted_node(cons
 		int milli,num = n->type;
 		unsigned long serial;
 		struct tm *btm;
-		char tmp[32];
+		char tmp[64];
 		const char *bptr;
 
 		*ptr++ = 0;
@@ -204,32 +204,67 @@ static void output_interpreted_node(cons
 no_print:
 
 		// output formatted time.
-		str = strchr(ptr, '.');
-		if (str == NULL)
-			return;
-		*str++ = 0;
-		errno = 0;
-		t = strtoul(ptr, NULL, 10);
-		if (errno)
-			return;
-		ptr = strchr(str, ':');
-		if (ptr == NULL)
-			return;
-		*ptr++ = 0;
-		milli = strtoul(str, NULL, 10);
-		if (errno)
-			return;
-		str = strchr(ptr, ')');
-		if(str == NULL)
-			return;
-		*str++ = 0;
-		serial = strtoul(ptr, NULL, 10);
-		if (errno)
-			return;
-		btm = localtime(&t);
-		strftime(tmp, sizeof(tmp), "%x %T", btm);
-		printf("%s", tmp);
-		printf(".%03d:%lu) ", milli, serial);
+		if (enhanced_interpret & ENHANCED_OTIME) {
+			/*
+ 			 * This option does NOT interpret the event time.
+ 			 *
+			 * We should be at the first digit of the time
+			 * as per
+			 * 	1365317376.919:75194): ....
+			 * so check for a closing ')' and print up to there
+			 * moving str to one char past it.
+			 */
+			str = strchr(ptr, ')');
+			if (str == NULL)
+				return;
+			*str++ = 0;
+			printf("%s)", ptr);
+		} else {
+			str = strchr(ptr, '.');
+			if (str == NULL)
+				return;
+			*str++ = 0;
+			errno = 0;
+			t = strtoul(ptr, NULL, 10);
+			if (errno)
+				return;
+			ptr = strchr(str, ':');
+			if (ptr == NULL)
+				return;
+			*ptr++ = 0;
+			milli = strtoul(str, NULL, 10);
+			if (errno)
+				return;
+			str = strchr(ptr, ')');
+			if(str == NULL)
+				return;
+			*str++ = 0;
+			serial = strtoul(ptr, NULL, 10);
+			if (errno)
+				return;
+			btm = localtime(&t);
+
+			if (enhanced_interpret & ENHANCED_RFC3339TIME) {
+				char	sign, tbuf[32];
+				long	abs_offset = timezone;
+				if (timezone < 0) {
+					sign = '+';
+					abs_offset = -timezone;
+				} else {
+					sign = '-';
+				}
+				abs_offset /= 60; 
+
+				strftime(tmp, sizeof(tmp), "%FT%T.%%03d%%c%%02d:%%02d", btm);
+				snprintf(tbuf, sizeof(tbuf), tmp, milli, sign, abs_offset / 60,
+					abs_offset % 60);
+				printf("%s:%lu) ", tbuf, serial);
+			} else {
+				strftime(tmp, sizeof(tmp), "%x %T", btm);
+				printf("%s", tmp);
+				printf(".%03d:%lu) ", milli, serial);
+			}
+		}
 	}
 
 	if (n->type == AUDIT_SYSCALL) { 
@@ -239,12 +274,21 @@ no_print:
 
 	// for each item.
 	found = 0;
+	skip_emit = 0;
 	while (str && *str && (ptr = strchr(str, '='))) {
 		char *name, *val;
 		int comma = 0;
+
+		/*
+		 * Emit a space between successive key value pairs, if allowed
+		 */
+		if (found && skip_emit == 0)
+			putchar(' ');
+
 		found = 1;
+		skip_emit = 0;
 
-		// look back to last space - this is name
+		// look back to last space - this is name (the key)
 		name = ptr;
 		while (*name != ' ' && name > str)
 			--name;
@@ -257,6 +301,11 @@ no_print:
 		// skip the msg= piece since the real stuff is the uid=
 		if (strcmp(name, "msg") == 0) {
 			str = ptr;
+			/*
+ 			 * don't print a space before the next key as
+			 * we already have one in front of msg=
+			 */
+			skip_emit = 1;
 			continue;
 		}
 
@@ -266,6 +315,13 @@ no_print:
 
 		// get string after = to the next space or end - this is value
 		if (*ptr == '\'' || *ptr == '"') {
+			/*
+ 			 * If the value starts with a single or double quote
+ 			 * look for the next one and if found, move past it
+ 			 * then terminate the 'value' string.
+ 			 * This assumes nothing important exists after the
+ 			 * trailing single or doube quote
+ 			 */
 			str = strchr(ptr+1, *ptr);
 			if (str) {
 				str++;
@@ -276,17 +332,28 @@ no_print:
 			str = strchr(ptr, ',');
 			val = strchr(ptr, ' ');
 			if (str && val && (str < val)) {
+				/*
+				 * If we have a comma an a space in that order,
+				 * replace the comma with a null and note we are
+				 * in "list mode"
+				 */
 				*str++ = 0;
 				comma = 1;
 			} else if (str && (val == NULL)) {
+				/*
+ 				 * If we have a comma and no space, replace
+ 				 * the comma with a null and note we are in
+				 * in "list mode"
+				 */
 				*str++ = 0;
 				comma = 1;
 			} else if (val) {
+				/* if we have a space, replace it will null */
 				str = val;
 				*str++ = 0;
 			}
 		}
-		// val points to begin & str 1 past end
+		// val points to beginning and str 1 character past end
 		val = ptr;
 		
 		// print interpreted string
@@ -298,12 +365,158 @@ no_print:
 	printf("\n");
 }
 
+/*
+ * Simple buffering scheme.
+ *
+ * We allocate the initial buffer with a size of WORKING_SZ and
+ * if we need more space, we add in increments of WORKING_INC until
+ * we reach a maximum at which we will not add more space
+ */
+#define	WORKING_SZ	64 * 1024
+#define	WORKING_INC	8 * 1024
+#define	WORKING_MAX	128 * 1024
+
+typedef struct SimpleBuffer	SimpleBuffer_t;
+struct SimpleBuffer {
+	char	* buf;		/* the buffer */
+	int	pos;		/* 'current' pointer into buf */
+	int	alloc;		/* current allocated size of buffer */
+};
+/*
+ * Allocate a simple buffer of the given size
+ * Rtns
+ * 	NULL	- no memory or size greater than maximum allowed
+ * 	ptr	- pointer to allocated simple buffer
+ */
+static SimpleBuffer_t * AllocSimpleBuffer(int sz) {
+	SimpleBuffer_t * b;
+
+	if (sz > WORKING_MAX)
+		return NULL;
+	if ((b = (SimpleBuffer_t *)calloc(1, sizeof(SimpleBuffer_t))) == NULL) {
+		return NULL;
+	}
+	if ((b->buf = (char *)malloc(sz)) == NULL) {
+		(void)free(b);
+		return NULL;
+	}
+	b->pos = 0;
+	b->alloc = sz;
+	return b;
+}
+/*
+ * Free a simple buffer
+ */
+static void FreeSimpleBuffer(SimpleBuffer_t * b) {
+
+	if (b == NULL)
+		return;
+	if (b->buf) 
+		(void)free(b->buf);
+	b->buf = NULL;
+	(void)free(b);
+}
+/*
+ * Add the given character to the simple buffer
+ * Rtns
+ * 	1 - buffer is at maximum
+ * 	2 - no memory to increase buffer
+ * 	0 - added char successfully
+ */
+static int addcharSimpleBuffer(SimpleBuffer_t * b, char ch) {
+
+	if (b == NULL || b->buf == NULL)
+		return 0;
+	if (b->pos == b->alloc) {
+		char	* nbuf;
+		b->alloc += WORKING_INC;
+		if (b->alloc > WORKING_MAX) {
+			b->alloc -= WORKING_INC;
+			return 1;
+		}
+		if ((nbuf = realloc(b->buf, b->alloc)) == NULL) {
+			b->alloc -= WORKING_INC;
+			return 2;
+		}
+		b->buf = nbuf;
+	}
+	b->buf[b->pos++] = ch;
+	return 0;
+}
+
+/*
+ * We use a 'local global' buffer, so we dont waste time
+ * allocating/deallocation memory in multiple invocations of
+ * enhance_escaped(). We will free it when we no longer need it.
+ */
+static SimpleBuffer_t	* s_sbuf = NULL;
+
+/*
+ * Free our working buffer ... should be called on exit
+ */
+void FreeEnhancedBuffer()
+{
+	FreeSimpleBuffer(s_sbuf);
+	s_sbuf = NULL;
+}
+
+/*
+ * Turn the given string, val, into an 'enhanced string' where
+ *  - embedded double quotes are escaped with a '\'
+ *  - characters outside the range 0x20 (space) thru 0x7E (~) are
+ *    printed in octal prefixed with a '\' 
+ * Rtns:
+ *	NULL	- Null argument or no memory
+ *	char *	- Enhanced string
+ */
+static char * enhance_escaped(const char * val)
+{
+	char	ch;
+
+	if (val == 0 || *val == '\0')
+		return NULL;
+
+	/*
+ 	 * Allocate our 'static' buffer, if we havent done so yet.
+ 	 */
+	if (s_sbuf == NULL) {
+		if ((s_sbuf = AllocSimpleBuffer(WORKING_SZ)) == NULL) {
+			return NULL;
+		}
+	}
+	s_sbuf->pos = 0;	/* position the currrent character pointer */
+
+	while ((ch = *val++) != '\0') {
+		if (ch < 0x20 || ch > 0x7E) {
+			if (addcharSimpleBuffer(s_sbuf, '\\'))
+				return NULL;
+			if (addcharSimpleBuffer(s_sbuf, '0' + ((ch >> 6) & 07)))
+				return NULL;
+			if (addcharSimpleBuffer(s_sbuf, '0' + ((ch >> 3) & 07)))
+				return NULL;
+			if (addcharSimpleBuffer(s_sbuf, '0' + (ch & 07)))
+				return NULL;
+		} else {
+			if (ch == '"') {
+				if (addcharSimpleBuffer(s_sbuf, '\\'))
+					return NULL;
+			}
+			if (addcharSimpleBuffer(s_sbuf, ch))
+				return NULL;
+		}
+	}
+	s_sbuf->buf[s_sbuf->pos] = '\0';	/* keep the buffer terminated */
+	return s_sbuf->buf;
+}
+
 extern int interp_adjust_type(int rtype, const char *name, const char *val);
 extern char *do_interpretation(int type, const idata *id);
 static void interpret(char *name, char *val, int comma, int rtype)
 {
 	int type;
 	idata id;
+	int postfix_squote = 0;
+	int need_comma = 0;
 
 	while (*name == ' '||*name == '(')
 		name++;
@@ -324,7 +537,7 @@ static void interpret(char *name, char *
 			errno = 0;
 			ival = strtoul(val, NULL, 16);
 			if (errno) {
-				printf("arch conversion error(%s) ", val);
+				printf("arch conversion error(%s)", val);
 				return;
 			}
 			machine = audit_elf_to_machine(ival);
@@ -335,7 +548,7 @@ static void interpret(char *name, char *
 			errno = 0;
 			ival = strtoul(val, NULL, 10);
 			if (errno) {
-				printf("syscall conversion error(%s) ", val);
+				printf("syscall conversion error(%s)", val);
 				return;
 			}
 			cur_syscall = ival;
@@ -349,29 +562,83 @@ static void interpret(char *name, char *
 	id.name = name;
 	id.val = val;
 
-	char *out = do_interpretation(type, &id);
-	if (type == AUPARSE_TYPE_UNCLASSIFIED)
-		printf("%s%c", val, comma ? ',' : ' ');
-	else if (name[0] == 'k' && strcmp(name, "key") == 0) {
-		char *str, *ptr = out;
-		int count = 0;
-		while ((str = strchr(ptr, AUDIT_KEY_SEPARATOR))) {
-			*str = 0;
-			if (count == 0) {
-				printf("%s", ptr);
-				count++;
-			} else
-				printf(" key=%s", ptr);
-			ptr = str+1;
+
+	if (enhanced_interpret & ENHANCED_QVALUES) {
+		putchar('"');
+
+		/*
+		 * We need to check if the value has a terminating
+		 * single quote without a leading single quote. This
+		 * occurs with msg='... res=success' type events which result
+		 * in name = "res" and val = "success'".
+		 * Since we don't want to see 
+		 * 	.... res="success'"
+		 * in enhanced_qvalues mode, we temporarily strip it and
+		 * at after printing the value
+		 */
+		int len = strlen(val);
+		if (val[0] != '\'' && val[len-1] == '\'') {
+			val[len-1] = 0;
+			postfix_squote = 1;
 		}
-		if (count == 0)
-			printf("%s ", out);
-		else
-			printf(" key=%s ", ptr);
-	} else if (type == AUPARSE_TYPE_TTY_DATA)
+	}
+	char *out = do_interpretation(type, &id);
+
+	switch (type) {
+	case AUPARSE_TYPE_UNCLASSIFIED:
+		if (comma) 
+			need_comma++;
+		printf("%s", val);
+		break;
+	case AUPARSE_TYPE_TTY_DATA:
 		printf("%s", out);
-	else
-		printf("%s ", out);
+		break;
+	case AUPARSE_TYPE_UID:
+		if (enhanced_interpret && ENHANCED_OUID)
+			printf("%s(%s)", out, val);
+		else
+			printf("%s", out);
+		break;
+	case AUPARSE_TYPE_GID:
+		if (enhanced_interpret && ENHANCED_OGID)
+			printf("%s(%s)", out, val);
+		else
+			printf("%s", out);
+		break;
+	case AUPARSE_TYPE_ESCAPED:
+		if (out && (enhanced_interpret & ENHANCED_ESTRING))
+			printf("%s", enhance_escaped(out));
+		else
+			printf("%s", out);
+		break;
+	default:
+		if (name[0] == 'k' && strcmp(name, "key") == 0) {
+			char *str, *ptr = out;
+			int count = 0;
+			while ((str = strchr(ptr, AUDIT_KEY_SEPARATOR))) {
+				*str = 0;
+				if (count == 0) {
+					printf("%s", ptr);
+					count++;
+				} else
+					printf(" key=%s", ptr);
+				ptr = str+1;
+			}
+			if (count == 0)
+				printf("%s", out);
+			else
+				printf(" key=%s", ptr);
+		} else
+			printf("%s", out);
+		break;
+	}
+
+	if (enhanced_interpret & ENHANCED_QVALUES)
+		putchar('"');
+	if (need_comma)
+		putchar(',');
+	if (postfix_squote)
+		putchar('\'');
+
 	free(out);
 }
-
--
Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit

Reply via email to