aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/audit/src/ausearch-report.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/src/ausearch-report.c')
-rw-r--r--framework/src/audit/src/ausearch-report.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/framework/src/audit/src/ausearch-report.c b/framework/src/audit/src/ausearch-report.c
new file mode 100644
index 00000000..a4f1e15d
--- /dev/null
+++ b/framework/src/audit/src/ausearch-report.c
@@ -0,0 +1,362 @@
+/*
+* ausearch-report.c - Format and output events
+* Copyright (c) 2005-09,2011-13 Red Hat Inc., Durham, North Carolina.
+* All Rights Reserved.
+*
+* This software may be freely redistributed and/or modified under the
+* terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; see the file COPYING. If not, write to the
+* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+* Authors:
+* Steve Grubb <sgrubb@redhat.com>
+*/
+
+#include "config.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libaudit.h"
+#include "ausearch-options.h"
+#include "ausearch-parse.h"
+#include "ausearch-lookup.h"
+#include "auparse-idata.h"
+#include "auparse-defs.h"
+
+/* Local functions */
+static void output_raw(llist *l);
+static void output_default(llist *l);
+static void output_interpreted(llist *l);
+static void output_interpreted_node(const lnode *n, const event *e);
+static void interpret(char *name, char *val, int comma, int rtype);
+
+/* The machine based on elf type */
+static unsigned long machine = -1;
+static int cur_syscall = -1;
+
+/* The first syscall argument */
+static unsigned long long a0, a1;
+
+/* This function branches to the correct output format */
+void output_record(llist *l)
+{
+ switch (report_format) {
+ case RPT_RAW:
+ output_raw(l);
+ break;
+ case RPT_DEFAULT:
+ output_default(l);
+ break;
+ case RPT_INTERP:
+ output_interpreted(l);
+ break;
+ case RPT_PRETTY:
+ break;
+ default:
+ fprintf(stderr, "Report format error");
+ exit(1);
+ }
+}
+
+/* This function will output the record as is */
+static void output_raw(llist *l)
+{
+ const lnode *n;
+
+ list_first(l);
+ n = list_get_cur(l);
+ if (!n) {
+ fprintf(stderr, "Error - no elements in record.");
+ return;
+ }
+ do {
+ puts(n->message);
+ } while ((n=list_next(l)));
+}
+
+/*
+ * This function will take the linked list and format it for output. No
+ * interpretation is performed. The output order is lifo for everything.
+ */
+static void output_default(llist *l)
+{
+ const lnode *n;
+
+ list_last(l);
+ n = list_get_cur(l);
+ printf("----\ntime->%s", ctime(&l->e.sec));
+ if (!n) {
+ fprintf(stderr, "Error - no elements in record.");
+ return;
+ }
+ if (n->type >= AUDIT_DAEMON_START && n->type < AUDIT_SYSCALL)
+ puts(n->message); // No injection possible
+ else {
+ do {
+ safe_print_string_n(n->message, n->mlen, 1);
+ } while ((n=list_prev(l)));
+ }
+}
+
+/*
+ * 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.
+ */
+static void output_interpreted(llist *l)
+{
+ const lnode *n;
+
+ list_last(l);
+ n = list_get_cur(l);
+ printf("----\n");
+ if (!n) {
+ fprintf(stderr, "Error - no elements in record.");
+ return;
+ }
+ if (n->type >= AUDIT_DAEMON_START && n->type < AUDIT_SYSCALL)
+ output_interpreted_node(n, &(l->e));
+ else {
+ do {
+ output_interpreted_node(n, &(l->e));
+ } while ((n=list_prev(l)));
+ }
+}
+
+/*
+ * This function will cycle through a single record and lookup each field's
+ * value that it finds.
+ */
+static void output_interpreted_node(const lnode *n, const event *e)
+{
+ char *ptr, *str = n->message;
+ int found, comma = 0;
+ int num = n->type;
+ struct tm *btm;
+ char tmp[32];
+
+ // Reset these because each record could be different
+ machine = -1;
+ cur_syscall = -1;
+
+ /* Check and see if we start with a node
+ * If we do, and there is a space in the line
+ * move the pointer to the first character past
+ * the space
+ */
+ if (e->node) {
+ if ((ptr=strchr(str, ' ')) != NULL) {
+ str = ptr+1;
+ }
+ }
+
+ // First locate time stamp.
+ ptr = strchr(str, '(');
+ if (ptr == NULL) {
+ fprintf(stderr, "can't find time stamp\n");
+ return;
+ }
+
+ *ptr++ = 0; /* move to the start of the timestamp */
+
+ // print everything up to it.
+ if (num >= 0) {
+ const char * bptr;
+ bptr = audit_msg_type_to_name(num);
+ if (bptr) {
+ if (e->node)
+ printf("node=%s ", e->node);
+ printf("type=%s msg=audit(", bptr);
+ goto no_print;
+ }
+ }
+ if (e->node)
+ printf("node=%s ", e->node);
+ printf("%s(", str);
+no_print:
+
+ str = strchr(ptr, ')');
+ if(str == NULL)
+ return;
+ *str++ = 0;
+ btm = localtime(&e->sec);
+ strftime(tmp, sizeof(tmp), "%x %T", btm);
+ printf("%s", tmp);
+ printf(".%03d:%lu) ", e->milli, e->serial);
+
+ if (n->type == AUDIT_SYSCALL) {
+ a0 = n->a0;
+ a1 = n->a1;
+ }
+
+ // for each item.
+ found = 0;
+ while (str && *str && (ptr = strchr(str, '='))) {
+ char *name, *val;
+ comma = 0;
+ found = 1;
+
+ // look back to last space - this is name
+ name = ptr;
+ while (*name != ' ' && name > str)
+ --name;
+ *ptr++ = 0;
+
+ // print everything up to the '='
+ printf("%s=", str);
+
+ // 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) {
+ str = ptr;
+ continue;
+ }
+
+ // In the above case, after msg= we need to trim the ' from uid
+ if (*name == '\'')
+ name++;
+
+ // 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)) {
+ // Value side has commas and another field exists
+ // Known: LABEL_LEVEL_CHANGE banners=none,none
+ // Known: ROLL_ASSIGN new-role=r,r
+ // Known: any MAC LABEL can potentially have commas
+ int ftype = auparse_interp_adjust_type(n->type,
+ name, val);
+ if (ftype == AUPARSE_TYPE_MAC_LABEL) {
+ str = val;
+ *str++ = 0;
+ } else {
+ *str++ = 0;
+ comma = 1;
+ }
+ } else if (str && (val == NULL)) {
+ // Goes all the way to the end. Done parsing
+ // Known: MCS context in PATH rec obj=u:r:t:s0:c2,c7
+ int ftype = auparse_interp_adjust_type(n->type,
+ name, ptr);
+ if (ftype == AUPARSE_TYPE_MAC_LABEL)
+ str = NULL;
+ else {
+ *str++ = 0;
+ comma = 1;
+ }
+ } else if (val) {
+ // There is another field, point to next (normal path)
+ str = val;
+ *str++ = 0;
+ }
+ }
+ // val points to begin & str 1 past end
+ val = ptr;
+
+ // print interpreted string
+ interpret(name, val, comma, n->type);
+ }
+ // If nothing found, just print out as is
+ if (!found && ptr == NULL && str)
+ safe_print_string(str, 1);
+
+ // If last field had comma, output the rest
+ else if (comma)
+ safe_print_string(str, 1);
+ printf("\n");
+}
+
+static void interpret(char *name, char *val, int comma, int rtype)
+{
+ int type;
+ idata id;
+
+ while (*name == ' '||*name == '(')
+ name++;
+
+ if (*name == 'a' && strcmp(name, "acct") == 0) {
+ // Remove trailing punctuation
+ int len = strlen(val);
+ if (val[len-1] == ':')
+ val[len-1] = 0;
+ }
+ type = auparse_interp_adjust_type(rtype, name, val);
+
+ if (rtype == AUDIT_SYSCALL || rtype == AUDIT_SECCOMP) {
+ if (machine == (unsigned long)-1)
+ machine = audit_detect_machine();
+ if (*name == 'a' && strcmp(name, "arch") == 0) {
+ unsigned long ival;
+ errno = 0;
+ ival = strtoul(val, NULL, 16);
+ if (errno) {
+ printf("arch conversion error(%s) ", val);
+ return;
+ }
+ machine = audit_elf_to_machine(ival);
+ }
+ if (cur_syscall < 0 && *name == 's' &&
+ strcmp(name, "syscall") == 0) {
+ unsigned long ival;
+ errno = 0;
+ ival = strtoul(val, NULL, 10);
+ if (errno) {
+ printf("syscall conversion error(%s) ", val);
+ return;
+ }
+ cur_syscall = ival;
+ }
+ id.syscall = cur_syscall;
+ } else
+ id.syscall = 0;
+ id.machine = machine;
+ id.a0 = a0;
+ id.a1 = a1;
+ id.name = name;
+ id.val = val;
+
+ char *out = auparse_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 (count == 0)
+ printf("%s ", out);
+ else
+ printf(" key=%s ", ptr);
+ } else if (type == AUPARSE_TYPE_TTY_DATA)
+ printf("%s", out);
+ else
+ printf("%s ", out);
+
+ free(out);
+}
+