All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joshua Roys <joshua.roys@gtri.gatech.edu>
To: "linux-audit@redhat.com" <linux-audit@redhat.com>
Subject: [RFC] New ausearch output option & audit viewing in Spacewalk
Date: Mon, 8 Jun 2009 12:46:37 -0400	[thread overview]
Message-ID: <4A2D406D.1080105@gtri.gatech.edu> (raw)

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

Hello all.

As part of developing an audit viewing "plugin"[1] to Spacewalk[2], I 
wrote a small program to use libauparse to output (easily) 
machine-parsable audit logs.  I think this functionality would be nice 
to have in ausearch, and as such, wrote a patch for it.

As well as reviewing this patch, I would like your feedback concerning 
the Spacewalk audit plugin.  Any questions or constructive criticism is 
welcome.

Thanks,

Joshua Roys

[1]
https://www.redhat.com/archives/spacewalk-devel/2009-May/msg00121.html
http://www.stl.gtri.gatech.edu/jroys/
[2]
http://www.redhat.com/spacewalk/

[-- Attachment #2: audit-machineinterp.patch --]
[-- Type: text/plain, Size: 8522 bytes --]

diff --git a/src/ausearch-common.h b/src/ausearch-common.h
index 179e127..2abd039 100644
--- a/src/ausearch-common.h
+++ b/src/ausearch-common.h
@@ -44,7 +44,8 @@ extern int event_exit, event_exit_is_set;
 typedef enum { F_BOTH, F_FAILED, F_SUCCESS } failed_t;
 typedef enum { C_NEITHER, C_ADD, C_DEL } conf_act_t;
 typedef enum { S_UNSET=-1, S_FAILED, S_SUCCESS } success_t;
-typedef enum { RPT_RAW, RPT_DEFAULT, RPT_INTERP, RPT_PRETTY } report_t;
+typedef enum { RPT_RAW, RPT_DEFAULT, RPT_INTERP, RPT_PRETTY, RPT_MACHINEINTERP
+} report_t;
 
 extern failed_t event_failed;
 extern conf_act_t event_conf_act;
diff --git a/src/ausearch-options.c b/src/ausearch-options.c
index 1f64b49..9edd59f 100644
--- a/src/ausearch-options.c
+++ b/src/ausearch-options.c
@@ -74,7 +74,7 @@ S_HOSTNAME, S_INTERP, S_INFILE, S_MESSAGE_TYPE, S_PID, S_SYSCALL, S_OSUCCESS,
 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_LINEBUFFERED, S_MACHINEINTERP };
 
 static struct nv_pair optiontab[] = {
 	{ S_EVENT, "-a" },
@@ -97,6 +97,7 @@ static struct nv_pair optiontab[] = {
 	{ S_HOSTNAME, "--host" },
 	{ S_INTERP, "-i" },
 	{ S_INTERP, "--interpret" },
+	{ S_MACHINEINTERP, "-I" },
 	{ S_INFILE, "-if" },
 	{ S_INFILE, "--input" },
 	{ S_IN_LOGS, "--input-logs" },
@@ -173,6 +174,7 @@ static void usage(void)
 	"\t-h,--help\t\t\thelp\n"
 	"\t-hn,--host <Host Name>\t\tsearch based on remote host name\n"
 	"\t-i,--interpret\t\t\tInterpret results to be human readable\n"
+	"\t-I\t\t\t\tInterpret results to be machine readable\n"
 	"\t-if,--input <Input File name>\tuse this file instead of current logs\n"
 	"\t--input-logs\t\t\tUse the logs even if stdin is a pipe\n"
 	"\t--just-one\t\t\tEmit just one event\n"
@@ -474,6 +476,22 @@ int check_params(int count, char *vars[])
         	                retval = -1;
 			}
 			break;
+		case S_MACHINEINTERP:
+			if (report_format == RPT_DEFAULT)
+				report_format = RPT_MACHINEINTERP;
+			else {
+				fprintf(stderr, 
+					"Conflicting output format %s\n",
+					vars[c]);
+        	                retval = -1;
+			}
+			if (optarg) {
+				fprintf(stderr, 
+					"Argument is NOT required for %s\n",
+					vars[c]);
+        	                retval = -1;
+			}
+			break;
 		case S_INFILE:
 			if (!optarg) {
 				fprintf(stderr, 
diff --git a/src/ausearch-report.c b/src/ausearch-report.c
index 6bb5c1a..e88b2e2 100644
--- a/src/ausearch-report.c
+++ b/src/ausearch-report.c
@@ -59,6 +59,8 @@ extern char *unescape(char *buf);
 /* Local functions */
 static void output_raw(llist *l);
 static void output_default(llist *l);
+static void output_machineinterp(llist *l);
+static void output_machineinterp_node(const lnode *n);
 static void output_interpreted(llist *l);
 static void output_interpreted_node(const lnode *n);
 static void interpret(char *name, char *val, int comma, int rtype);
@@ -84,6 +86,9 @@ void output_record(llist *l)
 			break;
 		case RPT_PRETTY:
 			break;
+		case RPT_MACHINEINTERP:
+			output_machineinterp(l);
+			break;
 		default:
 			fprintf(stderr, "Report format error");
 			exit(1);
@@ -131,6 +136,233 @@ static void output_default(llist *l)
 }
 
 /*
+ * This function will take the linked list and format it for output such that
+ * the output is both interpreted and yet easily machine-parsable (perl, etc).
+ */
+static void output_machineinterp(llist *l)
+{
+	const lnode *n;
+
+	list_last(l);
+	n = list_get_cur(l);
+	if (!n) {
+		fprintf(stderr, "Error - no elements in record.");
+		return;
+	}
+	if (n->type >= AUDIT_DAEMON_START && n->type < AUDIT_SYSCALL) 
+		output_machineinterp_node(n);
+	else {
+		do {
+			output_machineinterp_node(n);
+			printf("----\n");
+		} while ((n=list_prev(l)));
+	}
+}
+
+/*
+ * This function will cycle through a message and lookup each type that 
+ * it finds. 
+ */
+static void output_machineinterp_node(const lnode *n)
+{
+	char *ptr, *str = n->message, *node = NULL;
+
+	/* Check and see if we start with a node */
+	if (str[0] == 'n') {
+		ptr=strchr(str, ' ');
+		if (ptr) {
+			*ptr = 0;
+			node = str;
+			str = ptr+1;
+		}
+	}
+
+	// First locate time stamp.
+	ptr = strchr(str, '(');
+	if (ptr == NULL) {
+		fprintf(stderr, "can't find time stamp\n");
+		return;
+	} else {
+		time_t t;
+		int milli,num = n->type;
+		unsigned long serial;
+		char *eptr;
+		const char *bptr;
+
+		*ptr++ = 0;
+		if (num == -1) {
+			// see if we are older and wiser now.
+			bptr = strchr(str, '[');
+			if (bptr && bptr < ptr) {
+				bptr++;
+				eptr = strchr(bptr, ']');
+				if (eptr) {
+					*eptr = 0;
+					errno = 0;
+					num = strtoul(bptr, NULL, 10);
+					*eptr = ']';
+					if (errno) 
+						num = -1;
+				}
+			}
+		}
+
+		// print everything up to it.
+		if (num >= 0) {
+			bptr = audit_msg_type_to_name(num);
+			if (bptr) {
+				if (node)
+					printf("node=%s\n", node);
+				printf("type=%s\n", bptr);
+				goto no_print;
+			}
+		} 
+		if (node)
+			printf("node=%s\n", node);
+		eptr = strchr(str, ' ');
+		if (eptr)
+			*eptr = 0;
+		printf("%s\n", str);
+no_print:
+
+		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;
+		printf("serial=%lu\n", serial);
+		printf("seconds=%u\n", t);
+		printf("milli=%i\n", milli);
+		str = strchr(str, ':');
+		if (str) {
+			str++;
+			if (*str == ' ')
+				str++;
+		}
+	}
+
+	if (n->type == AUDIT_SYSCALL) 
+		a0 = n->a0;
+
+	// for each item.
+	while (str && *str && (ptr = strchr(str, '='))) {
+		char *name, *val;
+		int comma = 0;
+
+		// look back to last space - this is name
+		name = ptr;
+		while (*name != ' ' && name > str)
+			--name;
+		*ptr++ = 0;
+		if (*name == ' ')
+			name++;
+
+		// Some user messages have msg='uid=500   in this case
+		// skip the msg= piece since the real stuff is the uid=
+		if (strcmp(name, "msg") == 0) {
+			// msg='text... (more text)'
+			// kill the )' on the end
+			str = strrchr(ptr+1, ')');
+			if (str && str[1] == '\'' && str[2] == 0)
+				*str = 0;
+			str = ptr+1;
+			continue;
+		}
+
+		// handle avc: ... messages
+		if (strncmp(str, "avc: ", 5) == 0) {
+			char *seresult, *seperms;
+
+			// since we know there is 'avc: ', skip it
+			// and all following spaces
+			seresult = str + 5;
+			while (*seresult == ' ')
+				seresult++;
+
+			// find the { seperms } section
+			seperms = strchr(seresult, '{');
+			if (!seperms)
+				return;
+
+			// go backward from there killing all trailing spaces
+			str = seperms - 1;
+			while (*str == ' ')
+				*str-- = 0;
+			seperms++;
+
+			// find the end of the seperms
+			str = strchr(seperms, '}');
+			if (!str)
+				return;
+			*str-- = 0;
+
+			// kill spaces on both sides of seperms
+			while (*str == ' ')
+				str--;
+			while (*seperms == ' ')
+				seperms++;
+
+			printf("seresult=%s\n", seresult);
+			printf("seperms=%s\n", seperms);
+
+			str = name;
+		}
+
+		while (*str == '(' || *str == ' ')
+			str++;
+
+		// print everything up to the '='
+		printf("%s=", str);
+
+		// get string after = to the next space or end - this is value
+		if (*ptr == '\'' || *ptr == '"') {
+			str = strchr(ptr+1, *ptr);
+			if (str) {
+				str++;
+				if (*str)
+					*str++ = 0;
+			}
+		} else {
+			str = strchr(ptr, ',');
+			val = strchr(ptr, ' ');
+			if (str && val && (str < val)) {
+				*str++ = 0;
+				comma = 1;
+			} else if (str && (val == NULL)) {
+				*str++ = 0;
+				comma = 1;
+			} else if (val) {
+				str = val;
+				*str++ = 0;
+			}
+		}
+		// val points to begin & str 1 past end
+		val = ptr;
+
+		// print interpreted string
+		interpret(name, val, comma, n->type);
+		printf("\n");
+	}
+}
+
+/*
  * This function will take the linked list and format it for output. 
  * Interpretation is performed to aid understanding of records. The output
  * order is lifo for everything.
@@ -978,7 +1210,8 @@ static void interpret(char *name, char *val, int comma, int rtype)
 			print_tty_data(val);
 			break;
 		default:
-			printf("%s%c", val, comma ? ',' : ' ');
+			printf("%s%c", val, comma && report_format !=
+				RPT_MACHINEINTERP ? ',' : ' ');
 	}
 }
 

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



             reply	other threads:[~2009-06-08 16:47 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-06-08 16:46 Joshua Roys [this message]
2009-06-08 17:12 ` [RFC] New ausearch output option & audit viewing in Spacewalk John Dennis
2009-06-08 17:17   ` Joshua Roys
2009-06-08 17:28 ` Steve Grubb
2009-06-08 17:35 ` Miloslav Trmac
2009-06-08 17:43 ` John Dennis
2009-06-08 18:06   ` Steve Grubb

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4A2D406D.1080105@gtri.gatech.edu \
    --to=joshua.roys@gtri.gatech.edu \
    --cc=linux-audit@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.