diff options
Diffstat (limited to 'framework/src/audit/auparse/interpret.c')
-rw-r--r-- | framework/src/audit/auparse/interpret.c | 2651 |
1 files changed, 2651 insertions, 0 deletions
diff --git a/framework/src/audit/auparse/interpret.c b/framework/src/audit/auparse/interpret.c new file mode 100644 index 00000000..e8f82f92 --- /dev/null +++ b/framework/src/audit/auparse/interpret.c @@ -0,0 +1,2651 @@ +/* +* interpret.c - Lookup values to something more readable +* Copyright (c) 2007-09,2011-15 Red Hat Inc., Durham, North Carolina. +* All Rights Reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* Authors: +* Steve Grubb <sgrubb@redhat.com> +*/ + +#include "config.h" +#include "nvlist.h" +#include "nvpair.h" +#include "libaudit.h" +#include "internal.h" +#include "interpret.h" +#include "auparse-idata.h" +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <sys/stat.h> +#include <linux/net.h> +#include <netdb.h> +#include <sys/un.h> +#include <linux/ax25.h> +#include <linux/atm.h> +#include <linux/x25.h> +#include <linux/if.h> // FIXME: remove when ipx.h is fixed +#include <linux/ipx.h> +#include <linux/capability.h> +#include <sys/personality.h> +#include <sys/prctl.h> +#include <sched.h> +#include "auparse-defs.h" +#include "gen_tables.h" + +#if !HAVE_DECL_ADDR_NO_RANDOMIZE +# define ADDR_NO_RANDOMIZE 0x0040000 +#endif + +/* 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 +#define DIPC 25 + +#include "captabs.h" +#include "clone-flagtabs.h" +#include "epoll_ctls.h" +#include "famtabs.h" +#include "fcntl-cmdtabs.h" +#include "flagtabs.h" +#include "ipctabs.h" +#include "ipccmdtabs.h" +#include "mmaptabs.h" +#include "mounttabs.h" +#include "open-flagtabs.h" +#include "persontabs.h" +#include "prottabs.h" +#include "ptracetabs.h" +#include "recvtabs.h" +#include "rlimittabs.h" +#include "seektabs.h" +#include "socktabs.h" +#include "socktypetabs.h" +#include "signaltabs.h" +#include "clocktabs.h" +#include "typetabs.h" +#include "nfprototabs.h" +#include "icmptypetabs.h" +#include "seccomptabs.h" +#include "accesstabs.h" +#include "prctl_opttabs.h" +#include "schedtabs.h" +#include "shm_modetabs.h" +#include "sockoptnametabs.h" +#include "sockleveltabs.h" +#include "ipoptnametabs.h" +#include "ip6optnametabs.h" +#include "tcpoptnametabs.h" +#include "pktoptnametabs.h" +#include "umounttabs.h" +#include "ioctlreqtabs.h" + +typedef enum { AVC_UNSET, AVC_DENIED, AVC_GRANTED } avc_t; +typedef enum { S_UNSET=-1, S_FAILED, S_SUCCESS } success_t; + +static const char *print_signals(const char *val, unsigned int base); +static auparse_esc_t escape_mode = AUPARSE_ESC_TTY; + +/* + * This function will take a pointer to a 2 byte Ascii character buffer and + * return the actual hex value. + */ +static unsigned char x2c(const 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; +} + +// Check if any characters need tty escaping. Returns how many found. +static unsigned int need_tty_escape(const unsigned char *s, unsigned int len) +{ + unsigned int i = 0, cnt = 0; + while (i < len) { + if (s[i] < 32) + cnt++; + i++; + } + return cnt; +} + +// TTY escaping s string into dest. +static void tty_escape(const char *s, char *dest, unsigned int len) +{ + unsigned int i = 0, j = 0; + while (i < len) { + if ((unsigned char)s[i] < 32) { + dest[j++] = ('\\'); + dest[j++] = ('0' + ((s[i] & 0300) >> 6)); + dest[j++] = ('0' + ((s[i] & 0070) >> 3)); + dest[j++] = ('0' + (s[i] & 0007)); + } else + dest[j++] = s[i]; + i++; + } +} + +static const char sh_set[] = "\"'`$\\"; +static unsigned int need_shell_escape(const char *s, unsigned int len) +{ + unsigned int i = 0, cnt = 0; + while (i < len) { + if (s[i] < 32) + cnt++; + else if (strchr(sh_set, s[i])) + cnt++; + i++; + } + return cnt; +} + +static void shell_escape(const char *s, char *dest, unsigned int len) +{ + unsigned int i = 0, j = 0; + while (i < len) { + if ((unsigned char)s[i] < 32) { + dest[j++] = ('\\'); + dest[j++] = ('0' + ((s[i] & 0300) >> 6)); + dest[j++] = ('0' + ((s[i] & 0070) >> 3)); + dest[j++] = ('0' + (s[i] & 0007)); + } else if (strchr(sh_set, s[i])) { + dest[j++] = ('\\'); + dest[j++] = s[i]; + } else + dest[j++] = s[i]; + i++; + } +} + +static const char quote_set[] = ";'\"`#$&*?[]<>{}\\"; +static unsigned int need_shell_quote_escape(const unsigned char *s, unsigned int len) +{ + unsigned int i = 0, cnt = 0; + while (i < len) { + if (s[i] < 32) + cnt++; + else if (strchr(quote_set, s[i])) + cnt++; + i++; + } + return cnt; +} + +static void shell_quote_escape(const char *s, char *dest, unsigned int len) +{ + unsigned int i = 0, j = 0; + while (i < len) { + if ((unsigned char)s[i] < 32) { + dest[j++] = ('\\'); + dest[j++] = ('0' + ((s[i] & 0300) >> 6)); + dest[j++] = ('0' + ((s[i] & 0070) >> 3)); + dest[j++] = ('0' + (s[i] & 0007)); + } else if (strchr(quote_set, s[i])) { + dest[j++] = ('\\'); + dest[j++] = s[i]; + } else + dest[j++] = s[i]; + i++; + } +} + +/* This should return the count of what needs escaping */ +static unsigned int need_escaping(const char *s, unsigned int len) +{ + switch (escape_mode) + { + case AUPARSE_ESC_RAW: + break; + case AUPARSE_ESC_TTY: + return need_tty_escape(s, len); + case AUPARSE_ESC_SHELL: + return need_shell_escape(s, len); + case AUPARSE_ESC_SHELL_QUOTE: + return need_shell_quote_escape(s, len);; + } + return 0; +} + +static void escape(const char *s, char *dest, unsigned int len) +{ + switch (escape_mode) + { + case AUPARSE_ESC_RAW: + return; + case AUPARSE_ESC_TTY: + return tty_escape(s, dest, len); + case AUPARSE_ESC_SHELL: + return shell_escape(s, dest, len); + case AUPARSE_ESC_SHELL_QUOTE: + return shell_quote_escape(s, dest, len); + } +} + +int set_escape_mode(auparse_esc_t mode) +{ + if (mode < 0 || mode > AUPARSE_ESC_SHELL_QUOTE) + return 1; + escape_mode = mode; + return 0; +} +hidden_def(set_escape_mode) + +static int is_hex_string(const char *str) +{ + while (*str) { + if (!isxdigit(*str)) + return 0; + str++; + } + return 1; +} + +/* returns a freshly malloc'ed and converted buffer */ +char *au_unescape(char *buf) +{ + int len, i; + char saved, *str, *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++; + } + saved = *ptr; + *ptr = 0; + str = strdup(buf); + *ptr = saved; + + /* See if its '(null)' from the kernel */ + 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; + } + ptr = str; + for (i=0; i<len; i+=2) { + *ptr = x2c((unsigned char *)&str[i]); + ptr++; + } + *ptr = 0; + return str; +} + +static const char *success[3]= { "unset", "no", "yes" }; +static 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; + } +} + +static nvpair uid_nvl; +static int uid_list_created=0; +static const char *aulookup_uid(uid_t uid, char *buf, size_t size) +{ + char *name = NULL; + int rc; + + if (uid == -1) { + snprintf(buf, size, "unset"); + return buf; + } + + // Check the cache first + if (uid_list_created == 0) { + nvpair_create(&uid_nvl); + nvpair_clear(&uid_nvl); + uid_list_created = 1; + } + rc = nvpair_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) { + nvpnode nv; + nv.name = strdup(pw->pw_name); + nv.val = uid; + nvpair_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; + + nvpair_clear(&uid_nvl); + uid_list_created = 0; +} + +static nvpair gid_nvl; +static int gid_list_created=0; +static const char *aulookup_gid(gid_t gid, char *buf, size_t size) +{ + char *name = NULL; + int rc; + + if (gid == -1) { + snprintf(buf, size, "unset"); + return buf; + } + + // Check the cache first + if (gid_list_created == 0) { + nvpair_create(&gid_nvl); + nvpair_clear(&gid_nvl); + gid_list_created = 1; + } + rc = nvpair_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) { + nvpnode nv; + nv.name = strdup(gr->gr_name); + nv.val = gid; + nvpair_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; + + nvpair_clear(&gid_nvl); + gid_list_created = 0; +} + +static const char *print_uid(const char *val, unsigned int base) +{ + int uid; + char name[64]; + + errno = 0; + uid = strtoul(val, NULL, base); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + return strdup(aulookup_uid(uid, name, sizeof(name))); +} + +static const char *print_gid(const char *val, unsigned int base) +{ + int gid; + char name[64]; + + errno = 0; + gid = strtoul(val, NULL, base); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + return strdup(aulookup_gid(gid, name, sizeof(name))); +} + +static const char *print_arch(const char *val, unsigned int machine) +{ + const char *ptr; + char *out; + + if (machine > MACH_AARCH64) { + unsigned int ival; + + errno = 0; + ival = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s) ", val) < 0) + out = NULL; + return out; + } + machine = audit_elf_to_machine(ival); + } + if ((int)machine < 0) { + if (asprintf(&out, "unknown elf type(%s)", val) < 0) + out = NULL; + return out; + } + ptr = audit_machine_to_name(machine); + if (ptr) + return strdup(ptr); + else { + if (asprintf(&out, "unknown machine type(%d)", machine) < 0) + out = NULL; + return out; + } +} + +static const char *print_ipccall(const char *val, unsigned int base) +{ + int a0; + char *out; + const char *func = NULL; + + errno = 0; + a0 = strtol(val, NULL, base); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + func = ipc_i2s(a0); + if (func) + return strdup(func); + else { + if (asprintf(&out, "unknown ipccall(%s)", val) < 0) + out = NULL; + return out; + } +} + +static const char *print_socketcall(const char *val, unsigned int base) +{ + int a0; + char *out; + const char *func = NULL; + + errno = 0; + a0 = strtol(val, NULL, base); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + func = sock_i2s(a0); + if (func) + return strdup(func); + else { + if (asprintf(&out, "unknown socketcall(%s)", val) < 0) + out = NULL; + return out; + } +} + +static const char *print_syscall(const idata *id) +{ + const char *sys; + char *out; + int machine = id->machine, syscall = id->syscall; + unsigned long long a0 = id->a0; + + if (machine < 0) + machine = audit_detect_machine(); + if (machine < 0) { + out = strdup(id->val); + return out; + } + sys = audit_syscall_to_name(syscall, machine); + if (sys) { + const char *func = NULL; + if (strcmp(sys, "socketcall") == 0) { + if ((int)a0 == a0) + func = sock_i2s(a0); + } else if (strcmp(sys, "ipc") == 0) + if ((int)a0 == a0) + func = ipc_i2s(a0); + if (func) { + if (asprintf(&out, "%s(%s)", sys, func) < 0) + out = NULL; + } else + return strdup(sys); + } else { + if (asprintf(&out, "unknown syscall(%d)", syscall) < 0) + out = NULL; + } + + return out; +} + +static const char *print_exit(const char *val) +{ + long long ival; + char *out; + + errno = 0; + ival = strtoll(val, NULL, 10); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + if (ival < 0) { + if (asprintf(&out, "%lld(%s)", ival, strerror(-ival)) < 0) + out = NULL; + return out; + } + return strdup(val); +} + +static const char *print_escaped(const char *val) +{ + const char *out; + + if (*val == '"') { + char *term; + val++; + term = strchr(val, '"'); + if (term == NULL) + return strdup(" "); + *term = 0; + out = strdup(val); + *term = '"'; + return out; +// FIXME: working here...was trying to detect (null) and handle that +// differently. The other 2 should have " around the file names. +/* } else if (*val == '(') { + char *term; + val++; + term = strchr(val, ' '); + if (term == NULL) + return; + *term = 0; + printf("%s ", val); */ + } else if (val[0] == '0' && val[1] == '0') + out = au_unescape((char *)&val[2]); // Abstract name af_unix + else + out = au_unescape((char *)val); + if (out) + return out; + return strdup(val); // Something is wrong with string, just send as is +} + +static const char *print_proctitle(const char *val) +{ + char *out = (char *)print_escaped(val); + if (*val != '"') { + size_t len = strlen(val) / 2; + const char *end = out + len; + char *ptr = out; + while ((ptr = rawmemchr(ptr, '\0'))) { + if (ptr >= end) + break; + *ptr = ' '; + ptr++; + } + } + return out; +} + +static const char *print_perm(const char *val) +{ + int ival, printed=0; + char buf[32]; + + errno = 0; + ival = strtol(val, NULL, 10); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + buf[0] = 0; + + /* The kernel treats nothing (0x00) as everything (0x0F) */ + if (ival == 0) + ival = 0x0F; + if (ival & AUDIT_PERM_READ) { + strcat(buf, "read"); + printed = 1; + } + if (ival & AUDIT_PERM_WRITE) { + if (printed) + strcat(buf, ",write"); + else + strcat(buf, "write"); + printed = 1; + } + if (ival & AUDIT_PERM_EXEC) { + if (printed) + strcat(buf, ",exec"); + else + strcat(buf, "exec"); + printed = 1; + } + if (ival & AUDIT_PERM_ATTR) { + if (printed) + strcat(buf, ",attr"); + else + strcat(buf, "attr"); + } + return strdup(buf); +} + +static const char *print_mode(const char *val, unsigned int base) +{ + unsigned int ival; + char *out, buf[48]; + const char *name; + + errno = 0; + ival = strtoul(val, NULL, base); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + // detect the file type + name = audit_ftype_to_name(ival & S_IFMT); + if (name != NULL) + strcpy(buf, name); + else { + unsigned first_ifmt_bit; + + // The lowest-valued "1" bit in S_IFMT + first_ifmt_bit = S_IFMT & ~(S_IFMT - 1); + sprintf(buf, "%03o", (ival & S_IFMT) / first_ifmt_bit); + } + + // check on special bits + if (S_ISUID & ival) + strcat(buf, ",suid"); + if (S_ISGID & ival) + strcat(buf, ",sgid"); + if (S_ISVTX & ival) + strcat(buf, ",sticky"); + + // and the read, write, execute flags in octal + if (asprintf(&out, "%s,%03o", buf, + (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) + out = NULL; + return out; +} + +static const char *print_mode_short_int(unsigned int ival) +{ + char *out, buf[48]; + + // check on special bits + buf[0] = 0; + if (S_ISUID & ival) + strcat(buf, "suid"); + if (S_ISGID & ival) { + if (buf[0]) + strcat(buf, ","); + strcat(buf, "sgid"); + } + if (S_ISVTX & ival) { + if (buf[0]) + strcat(buf, ","); + strcat(buf, "sticky"); + } + + // and the read, write, execute flags in octal + if (buf[0] == 0) { + if (asprintf(&out, "0%03o", + (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) + out = NULL; + } else + if (asprintf(&out, "%s,0%03o", buf, + (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) + out = NULL; + return out; +} + +static const char *print_mode_short(const char *val, int base) +{ + unsigned int ival; + char *out; + + errno = 0; + ival = strtoul(val, NULL, base); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + return print_mode_short_int(ival); +} + +static const char *print_socket_domain(const char *val) +{ + int i; + char *out; + const char *str; + + errno = 0; + i = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + str = fam_i2s(i); + if (str == NULL) { + if (asprintf(&out, "unknown family(0x%s)", val) < 0) + out = NULL; + return out; + } else + return strdup(str); +} + +static const char *print_socket_type(const char *val) +{ + unsigned int type; + char *out; + const char *str; + + errno = 0; + type = 0xFF & strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + str = sock_type_i2s(type); + if (str == NULL) { + if (asprintf(&out, "unknown type(%s)", val) < 0) + out = NULL; + return out; + } else + return strdup(str); +} + +static const char *print_socket_proto(const char *val) +{ + unsigned int proto; + char *out; + struct protoent *p; + + errno = 0; + proto = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + p = getprotobynumber(proto); + if (p == NULL) { + if (asprintf(&out, "unknown proto(%s)", val) < 0) + out = NULL; + return out; + } else + return strdup(p->p_name); +} + +static const char *print_sockaddr(const char *val) +{ + int slen, rc = 0; + const struct sockaddr *saddr; + char name[NI_MAXHOST], serv[NI_MAXSERV]; + const char *host; + char *out = NULL; + const char *str; + + slen = strlen(val)/2; + host = au_unescape((char *)val); + if (host == NULL) { + if (asprintf(&out, "malformed host(%s)", val) < 0) + out = NULL; + return out; + } + saddr = (struct sockaddr *)host; + + + str = fam_i2s(saddr->sa_family); + if (str == NULL) { + if (asprintf(&out, "unknown family(%d)", saddr->sa_family) < 0) + out = NULL; + free((char *)host); + return out; + } + + // Now print address for some families + switch (saddr->sa_family) { + case AF_LOCAL: + { + const struct sockaddr_un *un = + (struct sockaddr_un *)saddr; + if (un->sun_path[0]) + rc = asprintf(&out, "%s %s", str, + un->sun_path); + else // abstract name + rc = asprintf(&out, "%s %.108s", str, + &un->sun_path[1]); + } + break; + case AF_INET: + if (slen < sizeof(struct sockaddr_in)) { + rc = asprintf(&out, "%s sockaddr len too short", + str); + break; + } + slen = sizeof(struct sockaddr_in); + if (getnameinfo(saddr, slen, name, NI_MAXHOST, serv, + NI_MAXSERV, NI_NUMERICHOST | + NI_NUMERICSERV) == 0 ) { + rc = asprintf(&out, "%s host:%s serv:%s", str, + name, serv); + } else + rc = asprintf(&out, "%s (error resolving addr)", + str); + break; + case AF_AX25: + { + const struct sockaddr_ax25 *x = + (struct sockaddr_ax25 *)saddr; + rc = asprintf(&out, "%s call:%c%c%c%c%c%c%c", + str, + x->sax25_call.ax25_call[0], + x->sax25_call.ax25_call[1], + x->sax25_call.ax25_call[2], + x->sax25_call.ax25_call[3], + x->sax25_call.ax25_call[4], + x->sax25_call.ax25_call[5], + x->sax25_call.ax25_call[6]); + } + break; + case AF_IPX: + { + const struct sockaddr_ipx *ip = + (struct sockaddr_ipx *)saddr; + rc = asprintf(&out, "%s port:%d net:%u", str, + ip->sipx_port, ip->sipx_network); + } + break; + case AF_ATMPVC: + { + const struct sockaddr_atmpvc* at = + (struct sockaddr_atmpvc *)saddr; + rc = asprintf(&out, "%s int:%d", str, + at->sap_addr.itf); + } + break; + case AF_X25: + { + const struct sockaddr_x25* x = + (struct sockaddr_x25 *)saddr; + rc = asprintf(&out, "%s addr:%.15s", str, + x->sx25_addr.x25_addr); + } + break; + case AF_INET6: + if (slen < sizeof(struct sockaddr_in6)) { + rc = asprintf(&out, + "%s sockaddr6 len too short", + str); + break; + } + slen = sizeof(struct sockaddr_in6); + if (getnameinfo(saddr, slen, name, NI_MAXHOST, serv, + NI_MAXSERV, NI_NUMERICHOST | + NI_NUMERICSERV) == 0 ) { + rc = asprintf(&out, "%s host:%s serv:%s", str, + name, serv); + } else + rc = asprintf(&out, "%s (error resolving addr)", + str); + break; + case AF_NETLINK: + { + const struct sockaddr_nl *n = + (struct sockaddr_nl *)saddr; + rc = asprintf(&out, "%s pid:%u", str, + n->nl_pid); + } + break; + } + if (rc < 0) + out = NULL; + free((char *)host); + return out; +} + +/* This is only used in the RHEL4 kernel */ +static const char *print_flags(const char *val) +{ + int flags, cnt = 0; + size_t i; + char *out, buf[80]; + + errno = 0; + flags = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + if (flags == 0) { + if (asprintf(&out, "none") < 0) + out = NULL; + return out; + } + buf[0] = 0; + for (i=0; i<FLAG_NUM_ENTRIES; i++) { + if (flag_table[i].value & flags) { + if (!cnt) { + strcat(buf, + flag_strings + flag_table[i].offset); + cnt++; + } else { + strcat(buf, ","); + strcat(buf, + flag_strings + flag_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_promiscuous(const char *val) +{ + int ival; + + errno = 0; + ival = strtol(val, NULL, 10); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + if (ival == 0) + return strdup("no"); + else + return strdup("yes"); +} + +static const char *print_capabilities(const char *val, int base) +{ + int cap; + char *out; + const char *s; + + errno = 0; + cap = strtoul(val, NULL, base); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = cap_i2s(cap); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown capability(%s%s)", + base == 16 ? "0x" : "", val) < 0) + out = NULL; + return out; +} + +static const char *print_cap_bitmap(const char *val) +{ +#define MASK(x) (1U << (x)) + unsigned long long temp; + __u32 caps[2]; + int i, found=0; + char *p, buf[600]; // 17 per cap * 33 + + errno = 0; + temp = strtoull(val, NULL, 16); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + caps[0] = temp & 0x00000000FFFFFFFFLL; + caps[1] = (temp & 0xFFFFFFFF00000000LL) >> 32; + p = buf; + for (i=0; i <= CAP_LAST_CAP; i++) { + if (MASK(i%32) & caps[i/32]) { + const char *s; + if (found) + p = stpcpy(p, ","); + s = cap_i2s(i); + if (s != NULL) + p = stpcpy(p, s); + found = 1; + } + } + if (found == 0) + return strdup("none"); + return strdup(buf); +} + +static const char *print_success(const char *val) +{ + int res; + + if (isdigit(*val)) { + errno = 0; + res = strtoul(val, NULL, 10); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + return strdup(aulookup_success(res)); + } else + return strdup(val); +} + +static const char *print_open_flags(const char *val) +{ + size_t i; + unsigned int flags; + int cnt = 0; + char *out, buf[178]; + + errno = 0; + flags = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + buf[0] = 0; + if ((flags & O_ACCMODE) == 0) { + // Handle O_RDONLY specially + strcat(buf, "O_RDONLY"); + cnt++; + } + for (i=0; i<OPEN_FLAG_NUM_ENTRIES; i++) { + if (open_flag_table[i].value & flags) { + if (!cnt) { + strcat(buf, + open_flag_strings + open_flag_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + open_flag_strings + open_flag_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_clone_flags(const char *val) +{ + unsigned int flags, i, clone_sig; + int cnt = 0; + char *out, buf[362]; // added 10 for signal name + + errno = 0; + flags = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + buf[0] = 0; + for (i=0; i<CLONE_FLAG_NUM_ENTRIES; i++) { + if (clone_flag_table[i].value & flags) { + if (!cnt) { + strcat(buf, + clone_flag_strings + clone_flag_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + clone_flag_strings + clone_flag_table[i].offset); + } + } + } + clone_sig = flags & 0xFF; + if (clone_sig && (clone_sig < 32)) { + const char *s = signal_i2s(clone_sig); + if (s != NULL) { + if (buf[0] != 0) + strcat(buf, "|"); + strcat(buf, s); + } + } + + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%x", flags); + return strdup(buf); +} + +static const char *print_fcntl_cmd(const char *val) +{ + char *out; + const char *s; + int cmd; + + errno = 0; + cmd = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = fcntl_i2s(cmd); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown fcntl command(%d)", cmd) < 0) + out = NULL; + return out; +} + +static const char *print_epoll_ctl(const char *val) +{ + char *out; + const char *s; + int cmd; + + errno = 0; + cmd = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = epoll_ctl_i2s(cmd); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown epoll_ctl operation (%d)", cmd) < 0) + out = NULL; + return out; +} + +static const char *print_clock_id(const char *val) +{ + int i; + char *out; + + errno = 0; + i = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + else if (i < 7) { + const char *s = clock_i2s(i); + if (s != NULL) + return strdup(s); + } + if (asprintf(&out, "unknown clk_id (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_prot(const char *val, unsigned int is_mmap) +{ + unsigned int prot, i; + int cnt = 0, limit; + char buf[144]; + char *out; + + errno = 0; + prot = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + buf[0] = 0; + if ((prot & 0x07) == 0) { + // Handle PROT_NONE specially + strcat(buf, "PROT_NONE"); + return strdup(buf); + } + if (is_mmap) + limit = 4; + else + limit = 3; + for (i=0; i<limit; i++) { + if (prot_table[i].value & prot) { + if (!cnt) { + strcat(buf, + prot_strings + prot_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + prot_strings + prot_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_mmap(const char *val) +{ + unsigned int maps, i; + int cnt = 0; + char buf[176]; + char *out; + + errno = 0; + maps = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + buf[0] = 0; + if ((maps & 0x0F) == 0) { + // Handle MAP_FILE specially + strcat(buf, "MAP_FILE"); + cnt++; + } + for (i=0; i<MMAP_NUM_ENTRIES; i++) { + if (mmap_table[i].value & maps) { + if (!cnt) { + strcat(buf, + mmap_strings + mmap_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + mmap_strings + mmap_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_personality(const char *val) +{ + int pers, pers2; + char *out; + const char *s; + + errno = 0; + pers = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + pers2 = pers & ~ADDR_NO_RANDOMIZE; + s = person_i2s(pers2); + if (s != NULL) { + if (pers & ADDR_NO_RANDOMIZE) { + if (asprintf(&out, "%s|~ADDR_NO_RANDOMIZE", s) < 0) + out = NULL; + return out; + } else + return strdup(s); + } + if (asprintf(&out, "unknown personality (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_ptrace(const char *val) +{ + int trace; + char *out; + const char *s; + + errno = 0; + trace = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = ptrace_i2s(trace); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown ptrace (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_prctl_opt(const char *val) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = prctl_opt_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown prctl option (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_mount(const char *val) +{ + unsigned int mounts, i; + int cnt = 0; + char buf[334]; + char *out; + + errno = 0; + mounts = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + buf[0] = 0; + for (i=0; i<MOUNT_NUM_ENTRIES; i++) { + if (mount_table[i].value & mounts) { + if (!cnt) { + strcat(buf, + mount_strings + mount_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + mount_strings + mount_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_rlimit(const char *val) +{ + int i; + char *out; + + errno = 0; + i = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + else if (i < 17) { + const char *s = rlimit_i2s(i); + if (s != NULL) + return strdup(s); + } + if (asprintf(&out, "unknown rlimit (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_recv(const char *val) +{ + unsigned int rec, i; + int cnt = 0; + char buf[234]; + char *out; + + errno = 0; + rec = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + buf[0] = 0; + for (i=0; i<RECV_NUM_ENTRIES; i++) { + if (recv_table[i].value & rec) { + if (!cnt) { + strcat(buf, + recv_strings + recv_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + recv_strings + recv_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_access(const char *val) +{ + unsigned long mode; + char buf[16]; + unsigned int i, cnt = 0; + + errno = 0; + mode = strtoul(val, NULL, 16); + if (errno) { + char *out; + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + if ((mode & 0xF) == 0) + return strdup("F_OK"); + buf[0] = 0; + for (i=0; i<3; i++) { + if (access_table[i].value & mode) { + if (!cnt) { + strcat(buf, + access_strings + access_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + access_strings + access_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static char *print_dirfd(const char *val) +{ + char *out; + + if (strcmp(val, "-100") == 0) { + if (asprintf(&out, "AT_FDCWD") < 0) + out = NULL; + } else { + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + } + return out; +} + +#ifndef SCHED_RESET_ON_FORK +#define SCHED_RESET_ON_FORK 0x40000000 +#endif +static const char *print_sched(const char *val) +{ + unsigned int pol; + char *out; + const char *s; + + errno = 0; + pol = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = sched_i2s(pol & 0x0F); + if (s != NULL) { + char buf[48]; + + strcpy(buf, s); + if (pol & SCHED_RESET_ON_FORK ) + strcat(buf, "|SCHED_RESET_ON_FORK"); + return strdup(buf); + } + if (asprintf(&out, "unknown scheduler policy (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_sock_opt_level(const char *val) +{ + int lvl; + char *out; + + errno = 0; + lvl = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + if (lvl == SOL_SOCKET) + return strdup("SOL_SOCKET"); + else { + struct protoent *p = getprotobynumber(lvl); + if (p == NULL) { + const char *s = socklevel_i2s(lvl); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown sockopt level (0x%s)", val) < 0) + out = NULL; + } else + return strdup(p->p_name); + } + + return out; +} + +static const char *print_sock_opt_name(const char *val, int machine) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + // PPC's tables are different + if ((machine == MACH_PPC64 || machine == MACH_PPC) && + opt >= 16 && opt <= 21) + opt+=100; + + s = sockoptname_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown sockopt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_ip_opt_name(const char *val) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = ipoptname_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown ipopt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_ip6_opt_name(const char *val) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = ip6optname_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown ip6opt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_tcp_opt_name(const char *val) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = tcpoptname_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown tcpopt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_udp_opt_name(const char *val) +{ + int opt; + char *out; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + if (opt == 1) + out = strdup("UDP_CORK"); + else if (opt == 100) + out = strdup("UDP_ENCAP"); + else if (asprintf(&out, "unknown udpopt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_pkt_opt_name(const char *val) +{ + int opt; + char *out; + const char *s; + + errno = 0; + opt = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = pktoptname_i2s(opt); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown pktopt name (0x%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_shmflags(const char *val) +{ + unsigned int flags, partial, i; + int cnt = 0; + char *out, buf[32]; + + errno = 0; + flags = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + partial = flags & 00003000; + buf[0] = 0; + for (i=0; i<IPCCMD_NUM_ENTRIES; i++) { + if (ipccmd_table[i].value & partial) { + if (!cnt) { + strcat(buf, + ipccmd_strings + ipccmd_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + ipccmd_strings + ipccmd_table[i].offset); + } + } + } + + partial = flags & 00014000; + for (i=0; i<SHM_MODE_NUM_ENTRIES; i++) { + if (shm_mode_table[i].value & partial) { + if (!cnt) { + strcat(buf, + shm_mode_strings + shm_mode_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + shm_mode_strings + shm_mode_table[i].offset); + } + } + } + + partial = flags & 000777; + const char *tmode = print_mode_short_int(partial); + if (tmode) { + if (buf[0] != 0) + strcat(buf, "|"); + strcat(buf, tmode); + free((void *)tmode); + } + + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%x", flags); + return strdup(buf); +} + +static const char *print_seek(const char *val) +{ + unsigned int whence; + char *out; + const char *str; + + errno = 0; + whence = 0xFF & strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + str = seek_i2s(whence); + if (str == NULL) { + if (asprintf(&out, "unknown whence(%s)", val) < 0) + out = NULL; + return out; + } else + return strdup(str); +} + +static const char *print_umount(const char *val) +{ + unsigned int flags, i; + int cnt = 0; + char buf[64]; + char *out; + + errno = 0; + flags = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + buf[0] = 0; + for (i=0; i<UMOUNT_NUM_ENTRIES; i++) { + if (umount_table[i].value & flags) { + if (!cnt) { + strcat(buf, + umount_strings + umount_table[i].offset); + cnt++; + } else { + strcat(buf, "|"); + strcat(buf, + umount_strings + umount_table[i].offset); + } + } + } + if (buf[0] == 0) + snprintf(buf, sizeof(buf), "0x%s", val); + return strdup(buf); +} + +static const char *print_ioctl_req(const char *val) +{ + int req; + char *out; + const char *r; + + errno = 0; + req = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + r = ioctlreq_i2s(req); + if (r != NULL) + return strdup(r); + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + return out; +} + +static const char *print_a0(const char *val, const idata *id) +{ + char *out; + int machine = id->machine, syscall = id->syscall; + const char *sys = audit_syscall_to_name(syscall, machine); + if (sys) { + if (*sys == 'r') { + if (strcmp(sys, "rt_sigaction") == 0) + return print_signals(val, 16); + else if (strcmp(sys, "renameat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "readlinkat") == 0) + return print_dirfd(val); + } else if (*sys == 'c') { + if (strcmp(sys, "clone") == 0) + return print_clone_flags(val); + else if (strcmp(sys, "clock_settime") == 0) + return print_clock_id(val); + } else if (*sys == 'p') { + if (strcmp(sys, "personality") == 0) + return print_personality(val); + else if (strcmp(sys, "ptrace") == 0) + return print_ptrace(val); + else if (strcmp(sys, "prctl") == 0) + return print_prctl_opt(val); + } else if (*sys == 'm') { + if (strcmp(sys, "mkdirat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "mknodat") == 0) + return print_dirfd(val); + } else if (*sys == 'f') { + if (strcmp(sys, "fchownat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "futimesat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "fchmodat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "faccessat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "futimensat") == 0) + return print_dirfd(val); + } else if (*sys == 'u') { + if (strcmp(sys, "unshare") == 0) + return print_clone_flags(val); + else if (strcmp(sys, "unlinkat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "utimensat") == 0) + return print_dirfd(val); + } else if (strcmp(sys+1, "etrlimit") == 0) + return print_rlimit(val); + else if (*sys == 's') { + if (strcmp(sys, "setuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setreuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setresuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setfsuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setgid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "setregid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "setresgid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "socket") == 0) + return print_socket_domain(val); + else if (strcmp(sys, "setfsgid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "socketcall") == 0) + return print_socketcall(val, 16); + } + else if (strcmp(sys, "linkat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "newfstatat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "openat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "ipccall") == 0) + return print_ipccall(val, 16); + } + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + return out; +} + +static const char *print_a1(const char *val, const idata *id) +{ + char *out; + int machine = id->machine, syscall = id->syscall; + const char *sys = audit_syscall_to_name(syscall, machine); + if (sys) { + if (*sys == 'f') { + if (strcmp(sys, "fchmod") == 0) + return print_mode_short(val, 16); + else if (strncmp(sys, "fcntl", 5) == 0) + return print_fcntl_cmd(val); + } else if (*sys == 'c') { + if (strcmp(sys, "chmod") == 0) + return print_mode_short(val, 16); + else if (strstr(sys, "chown")) + return print_uid(val, 16); + else if (strcmp(sys, "creat") == 0) + return print_mode_short(val, 16); + } + if (strcmp(sys+1, "etsockopt") == 0) + return print_sock_opt_level(val); + else if (*sys == 's') { + if (strcmp(sys, "setreuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setresuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setregid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "setresgid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "socket") == 0) + return print_socket_type(val); + else if (strcmp(sys, "setns") == 0) + return print_clone_flags(val); + else if (strcmp(sys, "sched_setscheduler") == 0) + return print_sched(val); + } else if (*sys == 'm') { + if (strcmp(sys, "mkdir") == 0) + return print_mode_short(val, 16); + else if (strcmp(sys, "mknod") == 0) + return print_mode(val, 16); + else if (strcmp(sys, "mq_open") == 0) + return print_open_flags(val); + } + else if (strcmp(sys, "open") == 0) + return print_open_flags(val); + else if (strcmp(sys, "access") == 0) + return print_access(val); + else if (strcmp(sys, "epoll_ctl") == 0) + return print_epoll_ctl(val); + else if (strcmp(sys, "kill") == 0) + return print_signals(val, 16); + else if (strcmp(sys, "prctl") == 0) { + if (id->a0 == PR_CAPBSET_READ || + id->a0 == PR_CAPBSET_DROP) + return print_capabilities(val, 16); + else if (id->a0 == PR_SET_PDEATHSIG) + return print_signals(val, 16); + } + else if (strcmp(sys, "tkill") == 0) + return print_signals(val, 16); + else if (strcmp(sys, "umount2") == 0) + return print_umount(val); + else if (strcmp(sys, "ioctl") == 0) + return print_ioctl_req(val); + } + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + return out; +} + +static const char *print_a2(const char *val, const idata *id) +{ + char *out; + int machine = id->machine, syscall = id->syscall; + const char *sys = audit_syscall_to_name(syscall, machine); + if (sys) { + if (strncmp(sys, "fcntl", 5) == 0) { + int ival; + + errno = 0; + ival = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", + val) < 0) + out = NULL; + return out; + } + switch (id->a1) + { + case F_SETOWN: + return print_uid(val, 16); + case F_SETFD: + if (ival == FD_CLOEXEC) + return strdup("FD_CLOEXEC"); + /* Fall thru okay. */ + case F_SETFL: + case F_SETLEASE: + case F_GETLEASE: + case F_NOTIFY: + break; + } + } else if (strcmp(sys+1, "etsockopt") == 0) { + if (id->a1 == IPPROTO_IP) + return print_ip_opt_name(val); + else if (id->a1 == SOL_SOCKET) + return print_sock_opt_name(val, machine); + else if (id->a1 == IPPROTO_TCP) + return print_tcp_opt_name(val); + else if (id->a1 == IPPROTO_UDP) + return print_udp_opt_name(val); + else if (id->a1 == IPPROTO_IPV6) + return print_ip6_opt_name(val); + else if (id->a1 == SOL_PACKET) + return print_pkt_opt_name(val); + else + goto normal; + } else if (*sys == 'o') { + if (strcmp(sys, "openat") == 0) + return print_open_flags(val); + if ((strcmp(sys, "open") == 0) && (id->a1 & O_CREAT)) + return print_mode_short(val, 16); + } else if (*sys == 'f') { + if (strcmp(sys, "fchmodat") == 0) + return print_mode_short(val, 16); + else if (strcmp(sys, "faccessat") == 0) + return print_access(val); + } else if (*sys == 's') { + if (strcmp(sys, "setresuid") == 0) + return print_uid(val, 16); + else if (strcmp(sys, "setresgid") == 0) + return print_gid(val, 16); + else if (strcmp(sys, "socket") == 0) + return print_socket_proto(val); + else if (strcmp(sys, "sendmsg") == 0) + return print_recv(val); + else if (strcmp(sys, "shmget") == 0) + return print_shmflags(val); + } else if (*sys == 'm') { + if (strcmp(sys, "mmap") == 0) + return print_prot(val, 1); + else if (strcmp(sys, "mkdirat") == 0) + return print_mode_short(val, 16); + else if (strcmp(sys, "mknodat") == 0) + return print_mode_short(val, 16); + else if (strcmp(sys, "mprotect") == 0) + return print_prot(val, 0); + else if ((strcmp(sys, "mq_open") == 0) && + (id->a1 & O_CREAT)) + return print_mode_short(val, 16); + } else if (*sys == 'r') { + if (strcmp(sys, "recvmsg") == 0) + return print_recv(val); + else if (strcmp(sys, "readlinkat") == 0) + return print_dirfd(val); + } else if (*sys == 'l') { + if (strcmp(sys, "linkat") == 0) + return print_dirfd(val); + else if (strcmp(sys, "lseek") == 0) + return print_seek(val); + } + else if (strstr(sys, "chown")) + return print_gid(val, 16); + else if (strcmp(sys, "tgkill") == 0) + return print_signals(val, 16); + } +normal: + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + return out; +} + +static const char *print_a3(const char *val, const idata *id) +{ + char *out; + int machine = id->machine, syscall = id->syscall; + const char *sys = audit_syscall_to_name(syscall, machine); + if (sys) { + if (*sys == 'm') { + if (strcmp(sys, "mmap") == 0) + return print_mmap(val); + else if (strcmp(sys, "mount") == 0) + return print_mount(val); + } else if (*sys == 'r') { + if (strcmp(sys, "recv") == 0) + return print_recv(val); + else if (strcmp(sys, "recvfrom") == 0) + return print_recv(val); + else if (strcmp(sys, "recvmmsg") == 0) + return print_recv(val); + } else if (*sys == 's') { + if (strcmp(sys, "send") == 0) + return print_recv(val); + else if (strcmp(sys, "sendto") == 0) + return print_recv(val); + else if (strcmp(sys, "sendmmsg") == 0) + return print_recv(val); + } + } + if (asprintf(&out, "0x%s", val) < 0) + out = NULL; + return out; +} + +static const char *print_signals(const char *val, unsigned int base) +{ + int i; + char *out; + + errno = 0; + i = strtoul(val, NULL, base); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + else if (i < 32) { + const char *s = signal_i2s(i); + if (s != NULL) + return strdup(s); + } + if (asprintf(&out, "unknown signal (%s%s)", + base == 16 ? "0x" : "", val) < 0) + out = NULL; + return out; +} + +static const char *print_nfproto(const char *val) +{ + int proto; + char *out; + const char *s; + + errno = 0; + proto = strtoul(val, NULL, 10); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = nfproto_i2s(proto); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown netfilter protocol (%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_icmptype(const char *val) +{ + int icmptype; + char *out; + const char *s; + + errno = 0; + icmptype = strtoul(val, NULL, 10); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + + s = icmptype_i2s(icmptype); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown icmp type (%s)", val) < 0) + out = NULL; + return out; +} + +static const char *print_protocol(const char *val) +{ + int i; + char *out; + + errno = 0; + i = strtoul(val, NULL, 10); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + } else { + struct protoent *p = getprotobynumber(i); + if (p) + out = strdup(p->p_name); + else + out = strdup("undefined protocol"); + } + return out; +} + +static const char *print_addr(const char *val) +{ + char *out = strdup(val); + return out; +} + +static const char *print_list(const char *val) +{ + int i; + char *out; + + errno = 0; + i = strtoul(val, NULL, 10); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + } else + out = strdup(audit_flag_to_name(i)); + return out; +} + +struct string_buf { + char *buf; /* NULL if was ever out of memory */ + size_t allocated; + size_t pos; +}; + +/* Append c to buf. */ +static void append_char(struct string_buf *buf, char c) +{ + if (buf->buf == NULL) + return; + if (buf->pos == buf->allocated) { + char *p; + + buf->allocated *= 2; + p = realloc(buf->buf, buf->allocated); + if (p == NULL) { + free(buf->buf); + buf->buf = NULL; + return; + } + buf->buf = p; + } + buf->buf[buf->pos] = c; + buf->pos++; +} + +/* Represent c as a character within a quoted string, and append it to buf. */ +static void tty_append_printable_char(struct string_buf *buf, unsigned char c) +{ + if (c < 0x20 || c > 0x7E) { + append_char(buf, '\\'); + append_char(buf, '0' + ((c >> 6) & 07)); + append_char(buf, '0' + ((c >> 3) & 07)); + append_char(buf, '0' + (c & 07)); + } else { + if (c == '\\' || c == '"') + append_char(buf, '\\'); + append_char(buf, 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 "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(nk, '\0'); + nk_len = p - nk; + if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) { + *input += nk_len; + return p + 1; + } + nk = strchr(p + 1, '\0') + 1; + } while (*nk != '\0'); + return NULL; +} + +static const char *print_tty_data(const char *raw_data) +{ + struct string_buf buf; + int in_printable; + unsigned char *data, *data_pos, *data_end; + + if (!is_hex_string(raw_data)) + return strdup(raw_data); + data = au_unescape((char *)raw_data); + if (data == NULL) + return NULL; + data_end = data + strlen(raw_data) / 2; + + buf.allocated = 10; + buf.buf = malloc(buf.allocated); /* NULL handled in append_char() */ + buf.pos = 0; + in_printable = 0; + data_pos = data; + 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) { + append_char(&buf, '"'); + in_printable = 0; + } + if (buf.pos != 0) + append_char(&buf, ','); + append_char(&buf, '<'); + while (*desc != '\0') { + append_char(&buf, *desc); + desc++; + } + append_char(&buf, '>'); + } else { + if (in_printable == 0) { + if (buf.pos != 0) + append_char(&buf, ','); + append_char(&buf, '"'); + in_printable = 1; + } + tty_append_printable_char(&buf, *data_pos); + data_pos++; + } + } + if (in_printable != 0) + append_char(&buf, '"'); + append_char(&buf, '\0'); + free(data); + return buf.buf; +} + +static const char *print_session(const char *val) +{ + if (strcmp(val, "4294967295") == 0) + return strdup("unset"); + else + return strdup(val); +} + +#define SECCOMP_RET_ACTION 0x7fff0000U +static const char *print_seccomp_code(const char *val) +{ + unsigned long code; + char *out; + const char *s; + + errno = 0; + code = strtoul(val, NULL, 16); + if (errno) { + if (asprintf(&out, "conversion error(%s)", val) < 0) + out = NULL; + return out; + } + s = seccomp_i2s(code & SECCOMP_RET_ACTION); + if (s != NULL) + return strdup(s); + if (asprintf(&out, "unknown seccomp code (%s)", val) < 0) + out = NULL; + return out; +} + +int lookup_type(const char *name) +{ + int i; + + if (type_s2i(name, &i) != 0) + return i; + return AUPARSE_TYPE_UNCLASSIFIED; +} + +const char *interpret(const rnode *r) +{ + const nvlist *nv = &r->nv; + int type; + idata id; + nvnode *n; + const char *out; + + id.machine = r->machine; + id.syscall = r->syscall; + id.a0 = r->a0; + id.a1 = r->a1; + id.name = nvlist_get_cur_name(nv); + id.val = nvlist_get_cur_val(nv); + type = auparse_interp_adjust_type(r->type, id.name, id.val); + + out = auparse_do_interpretation(type, &id); + n = nvlist_get_cur(nv); + n->interp_val = (char *)out; + + return out; +} + +/* + * rtype: the record type + * name: the current field name + * value: the current field value + * Returns: field's internal type is returned + */ +int auparse_interp_adjust_type(int rtype, const char *name, const char *val) +{ + int type; + + /* This set of statements overrides or corrects the detection. + * In almost all cases its a double use of a field. */ + if (rtype == AUDIT_EXECVE && *name == 'a' && strcmp(name, "argc") && + !strstr(name, "_len")) + type = AUPARSE_TYPE_ESCAPED; + else if (rtype == AUDIT_AVC && strcmp(name, "saddr") == 0) + type = AUPARSE_TYPE_UNCLASSIFIED; + else if (rtype == AUDIT_USER_TTY && strcmp(name, "msg") == 0) + type = AUPARSE_TYPE_ESCAPED; + else if (rtype == AUDIT_NETFILTER_PKT && strcmp(name, "saddr") == 0) + type = AUPARSE_TYPE_ADDR; + else if (strcmp(name, "acct") == 0) { + if (val[0] == '"') + type = AUPARSE_TYPE_ESCAPED; + else if (is_hex_string(val)) + type = AUPARSE_TYPE_ESCAPED; + else + type = AUPARSE_TYPE_UNCLASSIFIED; + } else if (rtype == AUDIT_PATH && *name =='f' && + strcmp(name, "flags") == 0) + type = AUPARSE_TYPE_FLAGS; + else if (rtype == AUDIT_MQ_OPEN && strcmp(name, "mode") == 0) + type = AUPARSE_TYPE_MODE_SHORT; + else if (rtype == AUDIT_CRYPTO_KEY_USER && strcmp(name, "fp") == 0) + type = AUPARSE_TYPE_UNCLASSIFIED; + else if ((strcmp(name, "id") == 0) && + (rtype == AUDIT_ADD_GROUP || rtype == AUDIT_GRP_MGMT || + rtype == AUDIT_DEL_GROUP)) + type = AUPARSE_TYPE_GID; + else + type = lookup_type(name); + + return type; +} +hidden_def(auparse_interp_adjust_type) + +const char *auparse_do_interpretation(int type, const idata *id) +{ + const char *out; + switch(type) { + case AUPARSE_TYPE_UID: + out = print_uid(id->val, 10); + break; + case AUPARSE_TYPE_GID: + out = print_gid(id->val, 10); + break; + case AUPARSE_TYPE_SYSCALL: + out = print_syscall(id); + break; + case AUPARSE_TYPE_ARCH: + out = print_arch(id->val, id->machine); + break; + case AUPARSE_TYPE_EXIT: + out = print_exit(id->val); + break; + case AUPARSE_TYPE_ESCAPED: + out = print_escaped(id->val); + break; + case AUPARSE_TYPE_PERM: + out = print_perm(id->val); + break; + case AUPARSE_TYPE_MODE: + out = print_mode(id->val,8); + break; + case AUPARSE_TYPE_MODE_SHORT: + out = print_mode_short(id->val,8); + break; + case AUPARSE_TYPE_SOCKADDR: + out = print_sockaddr(id->val); + break; + case AUPARSE_TYPE_FLAGS: + out = print_flags(id->val); + break; + case AUPARSE_TYPE_PROMISC: + out = print_promiscuous(id->val); + break; + case AUPARSE_TYPE_CAPABILITY: + out = print_capabilities(id->val, 10); + break; + case AUPARSE_TYPE_SUCCESS: + out = print_success(id->val); + break; + case AUPARSE_TYPE_A0: + out = print_a0(id->val, id); + break; + case AUPARSE_TYPE_A1: + out = print_a1(id->val, id); + break; + case AUPARSE_TYPE_A2: + out = print_a2(id->val, id); + break; + case AUPARSE_TYPE_A3: + out = print_a3(id->val, id); + break; + case AUPARSE_TYPE_SIGNAL: + out = print_signals(id->val, 10); + break; + case AUPARSE_TYPE_LIST: + out = print_list(id->val); + break; + case AUPARSE_TYPE_TTY_DATA: + out = print_tty_data(id->val); + break; + case AUPARSE_TYPE_SESSION: + out = print_session(id->val); + break; + case AUPARSE_TYPE_CAP_BITMAP: + out = print_cap_bitmap(id->val); + break; + case AUPARSE_TYPE_NFPROTO: + out = print_nfproto(id->val); + break; + case AUPARSE_TYPE_ICMPTYPE: + out = print_icmptype(id->val); + break; + case AUPARSE_TYPE_PROTOCOL: + out = print_protocol(id->val); + break; + case AUPARSE_TYPE_ADDR: + out = print_addr(id->val); + break; + case AUPARSE_TYPE_PERSONALITY: + out = print_personality(id->val); + break; + case AUPARSE_TYPE_SECCOMP: + out = print_seccomp_code(id->val); + break; + case AUPARSE_TYPE_OFLAG: + out = print_open_flags(id->val); + break; + case AUPARSE_TYPE_MMAP: + out = print_mmap(id->val); + break; + case AUPARSE_TYPE_PROCTITLE: + out = print_proctitle(id->val); + break; + case AUPARSE_TYPE_MAC_LABEL: + case AUPARSE_TYPE_UNCLASSIFIED: + default: + out = strdup(id->val); + break; + } + + if (escape_mode != AUPARSE_ESC_RAW) { + unsigned int len = strlen(out); + unsigned int cnt = need_escaping(out, len); + if (cnt) { + char *dest = malloc(len + 1 + (3*cnt)); + if (dest) + escape(out, dest, len); + free((void *)out); + out = dest; + } + } + return out; +} +hidden_def(auparse_do_interpretation) + |