aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/audit/src/ausearch-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/src/ausearch-lookup.c')
-rw-r--r--framework/src/audit/src/ausearch-lookup.c500
1 files changed, 500 insertions, 0 deletions
diff --git a/framework/src/audit/src/ausearch-lookup.c b/framework/src/audit/src/ausearch-lookup.c
new file mode 100644
index 00000000..10a219a5
--- /dev/null
+++ b/framework/src/audit/src/ausearch-lookup.c
@@ -0,0 +1,500 @@
+/*
+* ausearch-lookup.c - Lookup values to something more readable
+* Copyright (c) 2005-06,2011-12,2015 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 <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <linux/net.h>
+#include "ausearch-lookup.h"
+#include "ausearch-options.h"
+#include "ausearch-nvpair.h"
+
+/* This is the name/value pair used by search tables */
+struct nv_pair {
+ int value;
+ const char *name;
+};
+
+
+/* The machine based on elf type */
+static int machine = 0;
+static const char *Q = "?";
+static const char *results[3]= { "unset", "denied", "granted" };
+static const char *success[3]= { "unset", "no", "yes" };
+static const char *aulookup_socketcall(long sc);
+static const char *aulookup_ipccall(long ic);
+
+const char *aulookup_result(avc_t result)
+{
+ return results[result];
+}
+
+const char *aulookup_success(int s)
+{
+ switch (s)
+ {
+ default:
+ return success[0];
+ break;
+ case S_FAILED:
+ return success[1];
+ break;
+ case S_SUCCESS:
+ return success[2];
+ break;
+ }
+}
+
+const char *aulookup_syscall(llist *l, char *buf, size_t size)
+{
+ const char *sys;
+
+ if (report_format <= RPT_DEFAULT) {
+ snprintf(buf, size, "%d", l->s.syscall);
+ return buf;
+ }
+ machine = audit_elf_to_machine(l->s.arch);
+ if (machine < 0)
+ return Q;
+ sys = audit_syscall_to_name(l->s.syscall, machine);
+ if (sys) {
+ const char *func = NULL;
+ if (strcmp(sys, "socketcall") == 0) {
+ if (list_find_item(l, AUDIT_SYSCALL))
+ func = aulookup_socketcall((long)l->cur->a0);
+ } else if (strcmp(sys, "ipc") == 0) {
+ if(list_find_item(l, AUDIT_SYSCALL))
+ func = aulookup_ipccall((long)l->cur->a0);
+ }
+ if (func) {
+ snprintf(buf, size, "%s(%s)", sys, func);
+ return buf;
+ }
+ return sys;
+ }
+ snprintf(buf, size, "%d", l->s.syscall);
+ return buf;
+}
+
+// See include/linux/net.h
+static struct nv_pair socktab[] = {
+ {SYS_SOCKET, "socket"},
+ {SYS_BIND, "bind"},
+ {SYS_CONNECT, "connect"},
+ {SYS_LISTEN, "listen"},
+ {SYS_ACCEPT, "accept"},
+ {SYS_GETSOCKNAME, "getsockname"},
+ {SYS_GETPEERNAME, "getpeername"},
+ {SYS_SOCKETPAIR, "socketpair"},
+ {SYS_SEND, "send"},
+ {SYS_RECV, "recv"},
+ {SYS_SENDTO, "sendto"},
+ {SYS_RECVFROM, "recvfrom"},
+ {SYS_SHUTDOWN, "shutdown"},
+ {SYS_SETSOCKOPT, "setsockopt"},
+ {SYS_GETSOCKOPT, "getsockopt"},
+ {SYS_SENDMSG, "sendmsg"},
+ {SYS_RECVMSG, "recvmsg"},
+ {SYS_ACCEPT4, "accept4"},
+ {19, "recvmmsg"},
+ {20, "sendmmsg"}
+};
+#define SOCK_NAMES (sizeof(socktab)/sizeof(socktab[0]))
+
+static const char *aulookup_socketcall(long sc)
+{
+ int i;
+
+ for (i = 0; i < SOCK_NAMES; i++)
+ if (socktab[i].value == sc)
+ return socktab[i].name;
+
+ return NULL;
+}
+
+/* This is from asm/ipc.h. Copying it for now as some platforms
+ * have broken headers. */
+#define SEMOP 1
+#define SEMGET 2
+#define SEMCTL 3
+#define SEMTIMEDOP 4
+#define MSGSND 11
+#define MSGRCV 12
+#define MSGGET 13
+#define MSGCTL 14
+#define SHMAT 21
+#define SHMDT 22
+#define SHMGET 23
+#define SHMCTL 24
+
+/*
+ * This table maps ipc calls to their text name
+ */
+static struct nv_pair ipctab[] = {
+ {SEMOP, "semop"},
+ {SEMGET, "semget"},
+ {SEMCTL, "semctl"},
+ {SEMTIMEDOP, "semtimedop"},
+ {MSGSND, "msgsnd"},
+ {MSGRCV, "msgrcv"},
+ {MSGGET, "msgget"},
+ {MSGCTL, "msgctl"},
+ {SHMAT, "shmat"},
+ {SHMDT, "shmdt"},
+ {SHMGET, "shmget"},
+ {SHMCTL, "shmctl"}
+};
+#define IPC_NAMES (sizeof(ipctab)/sizeof(ipctab[0]))
+
+static const char *aulookup_ipccall(long ic)
+{
+ int i;
+
+ for (i = 0; i < IPC_NAMES; i++)
+ if (ipctab[i].value == ic)
+ return ipctab[i].name;
+
+ return NULL;
+}
+
+static nvlist uid_nvl;
+static int uid_list_created=0;
+const char *aulookup_uid(uid_t uid, char *buf, size_t size)
+{
+ char *name = NULL;
+ int rc;
+
+ if (report_format <= RPT_DEFAULT) {
+ snprintf(buf, size, "%d", uid);
+ return buf;
+ }
+ if (uid == -1) {
+ snprintf(buf, size, "unset");
+ return buf;
+ }
+
+ // Check the cache first
+ if (uid_list_created == 0) {
+ nvlist_create(&uid_nvl);
+ nvlist_clear(&uid_nvl);
+ uid_list_created = 1;
+ }
+ rc = nvlist_find_val(&uid_nvl, uid);
+ if (rc) {
+ name = uid_nvl.cur->name;
+ } else {
+ // Add it to cache
+ struct passwd *pw;
+ pw = getpwuid(uid);
+ if (pw) {
+ nvnode nv;
+ nv.name = strdup(pw->pw_name);
+ nv.val = uid;
+ nvlist_append(&uid_nvl, &nv);
+ name = uid_nvl.cur->name;
+ }
+ }
+ if (name != NULL)
+ snprintf(buf, size, "%s", name);
+ else
+ snprintf(buf, size, "unknown(%d)", uid);
+ return buf;
+}
+
+void aulookup_destroy_uid_list(void)
+{
+ if (uid_list_created == 0)
+ return;
+
+ nvlist_clear(&uid_nvl);
+ uid_list_created = 0;
+}
+
+static nvlist gid_nvl;
+static int gid_list_created=0;
+const char *aulookup_gid(gid_t gid, char *buf, size_t size)
+{
+ char *name = NULL;
+ int rc;
+
+ if (report_format <= RPT_DEFAULT) {
+ snprintf(buf, size, "%d", gid);
+ return buf;
+ }
+ if (gid == -1) {
+ snprintf(buf, size, "unset");
+ return buf;
+ }
+
+ // Check the cache first
+ if (gid_list_created == 0) {
+ nvlist_create(&gid_nvl);
+ nvlist_clear(&gid_nvl);
+ gid_list_created = 1;
+ }
+ rc = nvlist_find_val(&gid_nvl, gid);
+ if (rc) {
+ name = gid_nvl.cur->name;
+ } else {
+ // Add it to cache
+ struct group *gr;
+ gr = getgrgid(gid);
+ if (gr) {
+ nvnode nv;
+ nv.name = strdup(gr->gr_name);
+ nv.val = gid;
+ nvlist_append(&gid_nvl, &nv);
+ name = gid_nvl.cur->name;
+ }
+ }
+ if (name != NULL)
+ snprintf(buf, size, "%s", name);
+ else
+ snprintf(buf, size, "unknown(%d)", gid);
+ return buf;
+}
+
+void aulookup_destroy_gid_list(void)
+{
+ if (gid_list_created == 0)
+ return;
+
+ nvlist_clear(&gid_nvl);
+ gid_list_created = 0;
+}
+
+int is_hex_string(const char *str)
+{
+ int c=0;
+ while (*str) {
+ if (!isxdigit(*str))
+ return 0;
+ str++;
+ c++;
+ }
+ return 1;
+}
+/*
+ * This function will take a pointer to a 2 byte Ascii character buffer and
+ * return the actual hex value.
+ */
+static unsigned char x2c(unsigned char *buf)
+{
+ static const char AsciiArray[17] = "0123456789ABCDEF";
+ char *ptr;
+ unsigned char total=0;
+
+ ptr = strchr(AsciiArray, (char)toupper(buf[0]));
+ if (ptr)
+ total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4);
+ ptr = strchr(AsciiArray, (char)toupper(buf[1]));
+ if (ptr)
+ total += (unsigned char)((ptr-AsciiArray) & 0x0F);
+
+ return total;
+}
+
+/* returns a freshly malloc'ed and converted buffer */
+char *unescape(const char *buf)
+{
+ int len, i;
+ char *str, *strptr;
+ const char *ptr = buf;
+
+ /* Find the end of the name */
+ if (*ptr == '(') {
+ ptr = strchr(ptr, ')');
+ if (ptr == NULL)
+ return NULL;
+ else
+ ptr++;
+ } else {
+ while (isxdigit(*ptr))
+ ptr++;
+ }
+ str = strndup(buf, ptr - buf);
+
+ if (*buf == '(')
+ return str;
+
+ /* We can get away with this since the buffer is 2 times
+ * bigger than what we are putting there.
+ */
+ len = strlen(str);
+ if (len < 2) {
+ free(str);
+ return NULL;
+ }
+ strptr = str;
+ for (i=0; i<len; i+=2) {
+ *strptr = x2c((unsigned char *)&str[i]);
+ strptr++;
+ }
+ *strptr = 0;
+ return str;
+}
+
+int need_sanitize(const unsigned char *s, unsigned int len)
+{
+ unsigned int i = 0;
+ while (i < len) {
+ if (s[i] < 32)
+ return 1;
+ i++;
+ }
+ return 0;
+}
+
+void sanitize(const char *s, unsigned int len)
+{
+ unsigned int i = 0;
+ while (i < len) {
+ if ((unsigned char)s[i] < 32) {
+ putchar('\\');
+ putchar('0' + ((s[i] & 0300) >> 6));
+ putchar('0' + ((s[i] & 0070) >> 3));
+ putchar('0' + (s[i] & 0007));
+ } else
+ putchar(s[i]);
+ i++;
+ }
+}
+
+void safe_print_string_n(const char *s, unsigned int len, int ret)
+{
+ if (need_sanitize(s, len)) {
+ sanitize(s, len);
+ if (ret)
+ putchar('\n');
+ } else if (ret)
+ puts(s);
+ else
+ printf("%s", s);
+}
+
+void safe_print_string(const char *s, int ret)
+{
+ safe_print_string_n(s, strlen(s), ret);
+}
+
+/* Represent c as a character within a quoted string, and append it to buf. */
+static void tty_printable_char(unsigned char c)
+{
+ if (c < 0x20 || c > 0x7E) {
+ putchar('\\');
+ putchar('0' + ((c >> 6) & 07));
+ putchar('0' + ((c >> 3) & 07));
+ putchar('0' + (c & 07));
+ } else {
+ if (c == '\\' || c == '"')
+ putchar('\\');
+ putchar(c);
+ }
+}
+
+/* Search for a name of a sequence of TTY bytes.
+ * If found, return the name and advance *INPUT.
+ * Return NULL otherwise.
+ */
+static const char *tty_find_named_key(unsigned char **input, size_t input_len)
+{
+ /* NUL-terminated list of (sequence, NUL, name, NUL) entries.
+ First match wins, even if a longer match were possible later */
+ static const unsigned char named_keys[] =
+#define E(SEQ, NAME) SEQ "\0" NAME "\0"
+#include "auparse/tty_named_keys.h"
+#undef E
+ "\0";
+
+ unsigned char *src;
+ const unsigned char *nk;
+
+ src = *input;
+ if (*src >= ' ' && (*src < 0x7F || *src >= 0xA0))
+ return NULL; /* Fast path */
+ nk = named_keys;
+ do {
+ const unsigned char *p;
+ size_t nk_len;
+
+ p = strchr((const char *)nk, '\0');
+ nk_len = p - nk;
+ if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) {
+ *input += nk_len;
+ return (const char *)(p + 1);
+ }
+ nk = strchr((const char *)p + 1, '\0') + 1;
+ } while (*nk != '\0');
+ return NULL;
+}
+
+void print_tty_data(const char *val)
+{
+ int need_comma, in_printable = 0;
+ unsigned char *data, *data_pos, *data_end;
+
+ if (!is_hex_string(val)) {
+ printf("%s", val);
+ return;
+ }
+
+ if ((data = unescape((char *)val)) == NULL) {
+ printf("conversion error(%s)", val);
+ return;
+ }
+
+ data_end = data + strlen(val) / 2;
+ data_pos = data;
+ need_comma = 0;
+ while (data_pos < data_end) {
+ /* FIXME: Unicode */
+ const char *desc;
+
+ desc = tty_find_named_key(&data_pos, data_end - data_pos);
+ if (desc != NULL) {
+ if (in_printable != 0) {
+ putchar('"');
+ in_printable = 0;
+ }
+ if (need_comma != 0)
+ putchar(',');
+ printf("<%s>", desc);
+ } else {
+ if (in_printable == 0) {
+ if (need_comma != 0)
+ putchar(',');
+ putchar('"');
+ in_printable = 1;
+ }
+ tty_printable_char(*data_pos);
+ data_pos++;
+ }
+ need_comma = 1;
+ }
+ if (in_printable != 0)
+ putchar('"');
+ free(data);
+}
+