/* * ausearch-parse.c - Extract interesting fields and check for match * Copyright (c) 2005-06 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 <errno.h> #include <stdlib.h> #include <ctype.h> #include <sys/socket.h> #include <sys/un.h> #include <netdb.h> #include "libaudit.h" #include "ausearch-options.h" #include "ausearch-parse.h" #define NAME_OFFSET 36 static int parse_syscall(lnode *n, search_items *s); static int parse_dir(const lnode *n, search_items *s); static int common_path_parser(search_items *s, char *path); static int avc_parse_path(const lnode *n, search_items *s); static int parse_path(const lnode *n, search_items *s); static int parse_user(const lnode *n, search_items *s); static int parse_login(const lnode *n, search_items *s); static int parse_daemon(const lnode *n, search_items *s); static int parse_sockaddr(const lnode *n, search_items *s); static int parse_avc(const lnode *n, search_items *s); static int parse_kernel_anom(const lnode *n, search_items *s); static int parse_simple_message(const lnode *n, search_items *s); /* * 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(char *buf) { int len, i; char saved, *ptr = buf, *str; /* 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; 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 int audit_avc_init(search_items *s) { if (s->avc == NULL) { //create s->avc = malloc(sizeof(alist)); if (s->avc == NULL) return -1; alist_create(s->avc); } return 0; } /* * This function will take the list and extract the searchable fields from it. * It returns 0 on success and 1 on failure. */ int extract_search_items(llist *l) { int ret = 0; lnode *n; search_items *s = &l->s; list_first(l); n = list_get_cur(l); if (n) { do { char *ptr, *str, *term; // get type str = strstr(n->message, "type="); if (str == NULL) return -1; ptr = str+5; term = strchr(ptr, ' '); if (term == NULL) return -2; *term = 0; n->type = audit_name_to_msg_type(ptr); *term = ' '; if (n->type < 0) { /* fprintf(stderr, "Error converting type:%s\n", ptr); return 3; */ // If we don't know, don't extract. return 0; } switch (n->type) { case AUDIT_SYSCALL: ret = parse_syscall(n, s); break; case AUDIT_CWD: ret = parse_dir(n, s); break; case AUDIT_AVC_PATH: ret = avc_parse_path(n, s); break; case AUDIT_PATH: ret = parse_path(n, s); break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2: ret = parse_user(n, s); break; case AUDIT_SOCKADDR: ret = parse_sockaddr(n, s); break; case AUDIT_LOGIN: ret = parse_login(n, s); break; case AUDIT_DAEMON_START: case AUDIT_DAEMON_END: case AUDIT_DAEMON_ABORT: case AUDIT_DAEMON_CONFIG: case AUDIT_DAEMON_ROTATE: ret = parse_daemon(n, s); break; case AUDIT_CONFIG_CHANGE: ret = parse_simple_message(n, s); break; case AUDIT_AVC: ret = parse_avc(n, s); break; case AUDIT_FIRST_KERN_ANOM_MSG...AUDIT_LAST_KERN_ANOM_MSG: ret = parse_kernel_anom(n, s); break; case AUDIT_MAC_POLICY_LOAD...AUDIT_MAC_IPSEC_DELSPD: ret = parse_simple_message(n, s); break; case AUDIT_KERNEL: case AUDIT_IPC: case AUDIT_SELINUX_ERR: // Nothing to parse break; default: break; } // if (ret) printf("type:%d ret:%d\n", n->type, ret); } while ((n=list_next(l)) && ret==0); } return ret; } static int parse_syscall(lnode *n, search_items *s) { char *ptr, *str, *term; term = n->message; if (report_format > RPT_DEFAULT) { // get arch str = strstr(term, "arch="); if (str == NULL) return 1; ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 2; *term = 0; errno = 0; s->arch = (int)strtoul(ptr, NULL, 16); if (errno) return 3; *term = ' '; } // get syscall str = strstr(term, "syscall="); if (str == NULL) return 4; ptr = str + 8; term = strchr(ptr, ' '); if (term == NULL) return 5; *term = 0; errno = 0; s->syscall = (int)strtoul(ptr, NULL, 10); if (errno) return 6; // get success *term = ' '; str = strstr(term, "success="); if (str) { // exit_group does not set success !?! ptr = str + 8; term = strchr(ptr, ' '); if (term == NULL) return 7; *term = 0; if (strcmp(ptr, "yes") == 0) s->success = S_SUCCESS; else s->success = S_FAILED; *term = ' '; } // get a0 str = strstr(term, "a0="); if (str == NULL) return 8; ptr = str + 3; term = strchr(ptr, ' '); if (term == NULL) return 9; *term = 0; errno = 0; // 64 bit dump on 32 bit machine looks bad here - need long long n->a0 = strtoull(ptr, NULL, 16); // Hex if (errno) return 10; // ppid *term = ' '; str = strstr(term, "ppid="); if (str != NULL) { // ppid is an optional field ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 11; *term = 0; errno = 0; s->ppid = strtoul(ptr, NULL, 10); if (errno) return 12; *term = ' '; } // pid str = strstr(term, "pid="); if (str == NULL) return 13; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 14; *term = 0; errno = 0; s->pid = strtoul(ptr, NULL, 10); if (errno) return 15; // loginuid *term = ' '; str = strstr(term, "auid="); if (str == NULL) { str = strstr(term, "loginuid="); if (str == NULL) return 16; ptr = str + 9; } else ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 17; *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 18; // uid *term = ' '; str = strstr(term, "uid="); if (str == NULL) return 19; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 20; *term = 0; errno = 0; s->uid = strtoul(ptr, NULL, 10); if (errno) return 21; // gid *term = ' '; str = strstr(term, "gid="); if (str == NULL) return 22; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 23; *term = 0; errno = 0; s->gid = strtoul(ptr, NULL, 10); if (errno) return 24; // euid *term = ' '; str = strstr(term, "euid="); if (str == NULL) return 25; ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 26; *term = 0; errno = 0; s->euid = strtoul(ptr, NULL, 10); if (errno) return 27; // egid *term = ' '; str = strstr(term, "egid="); if (str == NULL) return 28; ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 29; *term = 0; errno = 0; s->egid = strtoul(ptr, NULL, 10); if (errno) return 30; *term = ' '; if (event_terminal) { // dont do this search unless needed str = strstr(term, "tty="); if (str) { str += 4; term = strchr(str, ' '); if (term == NULL) return 31; *term = 0; s->terminal = strdup(str); *term = ' '; } } if (event_comm) { // dont do this search unless needed str = strstr(term, "comm="); if (str) { /* Make the syscall one override */ if (s->comm) free(s->comm); str += 5; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) return 32; *term = 0; s->comm = strdup(str); *term = '"'; } else s->comm = unescape(str); } else return 33; } if (event_exe) { // dont do this search unless needed str = strstr(n->message, "exe="); if (str) { str += 4; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) return 34; *term = 0; s->exe = strdup(str); *term = '"'; } else s->exe = unescape(str); } else return 35; } if (event_subject) { // scontext str = strstr(term, "subj="); if (str != NULL) { str += 5; term = strchr(str, ' '); if (term == NULL) return 36; *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.scontext = strdup(str); alist_append(s->avc, &an); *term = ' '; } else return 37; } } if (event_key) { str = strstr(term, "key="); if (str) { str += 4; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) return 38; *term = 0; s->key = strdup(str); *term = '"'; } else s->key = unescape(str); } } return 0; } static int parse_dir(const lnode *n, search_items *s) { char *str, *term; if (event_filename) { // dont do this search unless needed str = strstr(n->message+NAME_OFFSET, " cwd="); if (str) { str += 5; if (*str == '"') { /* string is normal */ str++; term = strchr(str, '"'); if (term == NULL) return 1; *term = 0; if (!s->cwd) s->cwd = strdup(str); *term = '"'; } else if (!s->cwd) s->cwd = unescape(str); } } return 0; } static int common_path_parser(search_items *s, char *path) { char *term; if (*path == '"') { /* string is normal */ path++; term = strchr(path, '"'); if (term == NULL) return 1; if (!s->filename) { //create s->filename = malloc(sizeof(slist)); if (s->filename == NULL) return 2; slist_create(s->filename); } *term = 0; if (s->filename) { // append snode sn; sn.str = strdup(path); sn.key = NULL; sn.hits = 1; // Attempt to rebuild path if relative if ((sn.str[0] == '.') && ((sn.str[1] == '.') || (sn.str[1] == '/')) && s->cwd) { char *tmp = malloc(PATH_MAX); if (tmp == NULL) return 3; snprintf(tmp, PATH_MAX, "%s/%s", s->cwd, sn.str); free(sn.str); sn.str = tmp; } slist_append(s->filename, &sn); } *term = '"'; } else { if (!s->filename) { //create s->filename = malloc(sizeof(slist)); if (s->filename == NULL) return 4; slist_create(s->filename); } if (s->filename) { // append snode sn; sn.str = unescape(path); sn.key = NULL; sn.hits = 1; // Attempt to rebuild path if relative if ((sn.str[0] == '.') && ((sn.str[1] == '.') || (sn.str[1] == '/')) && s->cwd) { char *tmp = malloc(PATH_MAX); if (tmp == NULL) return 5; snprintf(tmp, PATH_MAX, "%s/%s", s->cwd, sn.str); free(sn.str); sn.str = tmp; } slist_append(s->filename, &sn); } } return 0; } static int avc_parse_path(const lnode *n, search_items *s) { char *str; if (event_filename) { // dont do this search unless needed str = strstr(n->message, " path="); if (str) { str += 6; return common_path_parser(s, str); } return 1; } return 0; } static int parse_path(const lnode *n, search_items *s) { // We add 32 to message because we do not nee to look at // anything before that. Its only time and type. char *str, *term = n->message+NAME_OFFSET; if (event_filename) { // dont do this search unless needed str = strstr(term, " name="); if (str) { str += 6; if (common_path_parser(s, str)) return 1; } } if (event_object) { // tcontext str = strstr(term, "obj="); if (str != NULL) { str += 4; term = strchr(str, ' '); if (term) *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.tcontext = strdup(str); alist_append(s->avc, &an); if (term) *term = ' '; } else return 6; } } return 0; } static int parse_user(const lnode *n, search_items *s) { char *ptr, *str, *term, saved, *mptr; // get pid str = strstr(n->message, "pid="); if (str == NULL) return 1; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 2; *term = 0; errno = 0; s->pid = strtoul(ptr, NULL, 10); if (errno) return 3; *term = ' '; // get uid str = strstr(term, "uid="); if (str == NULL) return 4; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 5; *term = 0; errno = 0; s->uid = strtoul(ptr, NULL, 10); if (errno) return 6; *term = ' '; // get loginuid *term = ' '; str = strstr(term, "auid="); if (str == NULL) { // Try the older one str = strstr(term, "loginuid="); if (str == NULL) return 7; ptr = str + 9; } else ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 8; *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 9; *term = ' '; if (event_subject) { // scontext str = strstr(term, "subj="); if (str != NULL) { str += 5; term = strchr(str, ' '); if (term == NULL) return 10; *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.scontext = strdup(str); alist_append(s->avc, &an); *term = ' '; } else return 11; } } // get uid - something has uid after auid ?? str = strstr(term, "uid="); if (str != NULL) { ptr = str + 4; term = ptr; while (isdigit(*term)) term++; if (term == ptr) return 12; saved = *term; *term = 0; errno = 0; s->uid = strtoul(ptr, NULL, 10); if (errno) return 13; *term = saved; } else { str = strstr(term, "acct="); if (str != NULL) { ptr = str + 5; term = ptr + 1; if (*ptr == '"') { while (term != '"') term++; *term = 0; s->acct = strdup(str); *term = '"'; } else s->acct = unescape(str); } } mptr = term + 1; // get hostname if (event_hostname) { // dont do this search unless needed str = strstr(mptr, "hostname="); if (str) { str += 9; term = strchr(str, ','); if (term == NULL) return 15; *term = 0; s->hostname = strdup(str); *term = ','; // Lets see if there is something more // meaningful in addr if (strcmp(s->hostname, "?") == 0) { term++; str = strstr(term, "addr="); if (str) { str += 5; term = strchr(str, ','); if (term == NULL) return 16; *term = 0; free(s->hostname); s->hostname = strdup(str); *term = ','; } } } } if (event_terminal) { // dont do this search unless needed str = strstr(mptr, "terminal="); if (str) { str += 9; term = strchr(str, ' '); if (term == NULL) return 17; *term = 0; s->terminal = strdup(str); *term = ' '; } } if (event_exe) { // dont do this search unless needed str = strstr(mptr, "exe="); if (str) { str += 4; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) return 18; *term = 0; s->exe = strdup(str); *term = '"'; } else s->exe = unescape(str); } } // get success str = strstr(mptr, "res="); if (str) { ptr = str + 4; term = strchr(ptr, '\''); if (term == NULL) return 19; *term = 0; if (strncmp(ptr, "failed", 6) == 0) s->success = S_FAILED; else s->success = S_SUCCESS; *term = '\''; } else if ((str = strstr(mptr, "result="))) { ptr = str + 7; term = strchr(ptr, ')'); if (term == NULL) return 20; *term = 0; if (strcasecmp(ptr, "success") == 0) s->success = S_SUCCESS; else s->success = S_FAILED; *term = ')'; } return 0; } static int parse_login(const lnode *n, search_items *s) { char *ptr, *str, *term; // get pid str = strstr(n->message, "pid="); if (str == NULL) return 1; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 2; *term = 0; errno = 0; s->pid = strtoul(ptr, NULL, 10); if (errno) return 3; // get uid *term = ' '; str = strstr(term, "uid="); if (str == NULL) return 4; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 5; *term = 0; errno = 0; s->uid = strtoul(ptr, NULL, 10); if (errno) return 6; // get loginuid *term = ' '; str = strstr(term, "new auid="); if (str == NULL) { str = strstr(term, "new loginuid="); if (str == NULL) return 7; ptr = str + 13; } else ptr = str + 9; term = strchr(ptr, ' '); if (term) *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 8; if (term) *term = ' '; // Login means the kernel changed loginuid, its always // successful at this point. s->success = S_SUCCESS; return 0; } static int parse_daemon(const lnode *n, search_items *s) { char *ptr, *str, *term, saved, *mptr; // Not all messages have a ')', use it if its there mptr = strchr(n->message, ')'); if (mptr == NULL) mptr = n->message; // auid str = strstr(mptr, "auid="); if (str == NULL) return 2; ptr = str + 5; term = strchr(ptr, ' '); if (term == NULL) return 3; saved = *term; *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 4; *term = saved; // pid str = strstr(term, "pid="); if (str == NULL) return 5; ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 6; saved = *term; *term = 0; errno = 0; s->pid = strtoul(ptr, NULL, 10); if (errno) return 7; *term = saved; if (event_subject) { // scontext str = strstr(term, "subj="); if (str != NULL) { str += 5; term = strchr(str, ' '); if (term == NULL) return 8; *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.scontext = strdup(str); alist_append(s->avc, &an); *term = ' '; } else return 9; } } // success str = strstr(mptr, "res="); if (str) { ptr = term = str + 4; while (isalpha(*term)) term++; if (term == ptr) return 10; saved = *term; *term = 0; if (strncmp(ptr, "failed", 6) == 0) s->success = S_FAILED; else s->success = S_SUCCESS; *term = saved; } return 0; } static int parse_sockaddr(const lnode *n, search_items *s) { char *str; if (event_hostname || event_filename) { str = strstr(n->message, "saddr="); if (str) { int len; struct sockaddr *saddr; char name[NI_MAXHOST]; str += 6; len = strlen(str)/2; s->hostname = unescape(str); saddr = (struct sockaddr *)s->hostname; if (saddr->sa_family == AF_INET) { if (len < sizeof(struct sockaddr_in)) { fprintf(stderr, "sockaddr len too short\n"); return 1; } len = sizeof(struct sockaddr_in); } else if (saddr->sa_family == AF_INET6) { if (len < sizeof(struct sockaddr_in6)) { fprintf(stderr, "sockaddr6 len too short\n"); return 2; } len = sizeof(struct sockaddr_in6); } else if (saddr->sa_family == AF_UNIX) { struct sockaddr_un *un = (struct sockaddr_un *)saddr; if (un->sun_path[0]) len = strlen(un->sun_path); else // abstract name len = strlen(&un->sun_path[1]); if (len == 0) { fprintf(stderr, "sun_path len too short\n"); return 3; } if (event_filename) { if (!s->filename) { //create s->filename = malloc(sizeof(slist)); if (s->filename == NULL) return 4; slist_create(s->filename); } if (s->filename) { // append snode sn; sn.str = strdup(un->sun_path); sn.key = NULL; sn.hits = 1; slist_append(s->filename, &sn); } free(s->hostname); s->hostname = NULL; return 0; } else { // No file name - no need for socket free(s->hostname); s->hostname = NULL; return 0; } } else { // addr family we don't care about free(s->hostname); s->hostname = NULL; return 0; } if (!event_hostname) { // we entered here for files - discard free(s->hostname); s->hostname = NULL; return 0; } if (getnameinfo(saddr, len, name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) ) { free(s->hostname); s->hostname = NULL; } else { free(s->hostname); s->hostname = strdup(name); } } } return 0; } /* FIXME: If they are in permissive mode or hit an auditallow, there can * be more that 1 avc in the same syscall. For now, we pickup just the first. */ static int parse_avc(const lnode *n, search_items *s) { char *str, *term; anode an; int rc=0; term = n->message; anode_init(&an); // get the avc message info. str = strstr(term, "avc: "); if (str) { str += 5; term = strchr(str, '{'); if (term == NULL) return 1; *term = 0; // FIXME. Do not override syscall pass/fail if its already // set. Syscall pass/fail is the authoritative value. if (strstr(str, "denied")) { s->success = S_FAILED; an.avc_result = AVC_DENIED; } else { s->success = S_SUCCESS; an.avc_result = AVC_GRANTED; } *term = '{'; // Now get permission str = term + 1; while (*str == ' ') str++; term = strchr(str, '}'); if (term == NULL) return 2; while (*(term-1) == ' ') term--; *term = 0; an.avc_perm = strdup(str); *term = ' '; } if (event_comm && s->comm == NULL) { // dont do this search unless needed str = strstr(term, "comm="); if (str == NULL) { rc = 3; goto err; } str += 5; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) { rc = 4; goto err; } *term = 0; s->comm = strdup(str); *term = '"'; } else { s->comm = unescape(str); term = str + 6; } } if (event_subject) { // scontext str = strstr(term, "scontext="); if (str != NULL) { str += 9; term = strchr(str, ' '); if (term == NULL) { rc = 5; goto err; } *term = 0; an.scontext = strdup(str); *term = ' '; } } if (event_object) { // tcontext str = strstr(term, "tcontext="); if (str != NULL) { str += 9; term = strchr(str, ' '); if (term == NULL) { rc = 6; goto err; } *term = 0; an.tcontext = strdup(str); *term = ' '; } } // Now get the class...its at the end, so we do things different str = strstr(term, "tclass="); if (str == NULL) { rc = 7; goto err; } str += 7; term = strchr(str, ' '); if (term) *term = 0; an.avc_class = strdup(str); if (term) *term = ' '; if (audit_avc_init(s) == 0) { alist_append(s->avc, &an); } else { rc = 8; goto err; } return 0; err: anode_clear(&an); return rc; } static int parse_kernel_anom(const lnode *n, search_items *s) { char *str, *ptr, *term; // get loginuid str = strstr(n->message, "auid="); if (str == NULL) return 1; ptr = str + 5; term = strchr(ptr, ' '); if (term) *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 2; if (term) *term = ' '; else term = n->message; // get uid str = strstr(term, "uid="); if (str) { ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 3; *term = 0; errno = 0; s->uid = strtoul(ptr, NULL, 10); if (errno) return 4; *term = ' '; } // get gid str = strstr(term, "gid="); if (str) { ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 5; *term = 0; errno = 0; s->gid = strtoul(ptr, NULL, 10); if (errno) return 6; *term = ' '; } if (event_subject) { // scontext str = strstr(term, "subj="); if (str) { str += 5; term = strchr(str, ' '); if (term == NULL) return 7; *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.scontext = strdup(str); alist_append(s->avc, &an); *term = ' '; } else return 8; } } // get pid str = strstr(term, "pid="); if (str) { ptr = str + 4; term = strchr(ptr, ' '); if (term == NULL) return 9; *term = 0; errno = 0; s->pid = strtoul(ptr, NULL, 10); if (errno) return 10; *term = ' '; } if (event_comm) { // dont do this search unless needed str = strstr(term, "comm="); if (str) { str += 5; if (*str == '"') { str++; term = strchr(str, '"'); if (term == NULL) return 11; *term = 0; s->comm = strdup(str); *term = '"'; } else s->comm = unescape(str); } } return 0; } // This is for messages that only have the loginuid as the item // of interest. static int parse_simple_message(const lnode *n, search_items *s) { char *str, *ptr, *term; // get loginuid str = strstr(n->message, "auid="); if (str == NULL) return 1; ptr = str + 5; term = strchr(ptr, ' '); if (term) *term = 0; errno = 0; s->loginuid = strtoul(ptr, NULL, 10); if (errno) return 2; if (term) *term = ' '; else term = ptr; // Now get subj label if (event_subject) { // scontext str = strstr(term, "subj="); if (str != NULL) { str += 5; term = strchr(str, ' '); if (term) *term = 0; if (audit_avc_init(s) == 0) { anode an; anode_init(&an); an.scontext = strdup(str); alist_append(s->avc, &an); if (term) *term = ' '; else // Set it back to something sane term = str; } else return 3; } } // defaulting this to 1 for these messages. The kernel generally // does not log the res since it can be nothing but success. // But it can still be overriden below if res= is found in the event if (n->type == AUDIT_CONFIG_CHANGE) s->success = S_SUCCESS; // and results (usually last) str = strstr(term, "res="); if (str != NULL) { ptr = str + 4; term = strchr(ptr, ' '); if (term) *term = 0; errno = 0; s->success = strtoul(ptr, NULL, 10); if (errno) return 4; if (term) *term = ' '; } return 0; }