/* This function shows how to iterate through the fields of a record * and print its name and raw value and interpretted value. */ static void dump_fields_of_record(auparse_state_t *au) { printf("record type %d(%s) has %d fields\n", auparse_get_type(au), audit_msg_type_to_name(auparse_get_type(au)), auparse_get_num_fields(au)); printf("line=%d file=%s\n", auparse_get_line_number(au), auparse_get_filename(au) ? auparse_get_filename(au) : "stdin"); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) { printf("Error getting timestamp - aborting\n"); return; } /* Note that e->sec can be treated as time_t data if you want * something a little more readable */ printf("event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec, e->milli, e->serial, e->host ? e->host : "?"); auparse_first_field(au); do { printf("field: %s=%s (%s)\n", auparse_get_field_name(au), auparse_get_field_str(au), auparse_interpret_field(au)); } while (auparse_next_field(au) > 0); printf("\n"); }
const char *auparse_get_type_name(auparse_state_t *au) { if (au->le == NULL) return NULL; rnode *r = aup_list_get_cur(au->le); if (r) return audit_msg_type_to_name(r->type); else return NULL; }
static void do_type_summary_output(ilist *sptr) { const int_node *in; if (sptr->cnt == 0) { printf("<no events of interest were found>\n\n"); return; } ilist_first(sptr); in=ilist_get_cur(sptr); while (in) { const char *name = audit_msg_type_to_name(in->num); if (report_format == RPT_DEFAULT) printf("%u %d\n", in->hits, in->num); else printf("%u %s\n", in->hits, name); in=ilist_next(sptr); } }
void print_per_event_item(llist *l) { char buf[128]; char name[64]; char date[32]; struct tm *tv; // The beginning is common to all reports tv = localtime(&l->e.sec); if (tv) strftime(date, sizeof(date), "%x %T", tv); else strcpy(date, "?"); if (report_type != RPT_AVC) { line_item++; printf("%u. %s ", line_item, date); } switch (report_type) { case RPT_AVC: alist_find_avc(l->s.avc); do { anode *an = l->s.avc->cur; line_item++; printf("%u. %s ", line_item, date); // command subject syscall action obj res event safe_print_string(l->s.comm ? l->s.comm : "?", 0); printf(" %s %s %s %s %s %s %lu\n", an->scontext, aulookup_syscall(l, buf,sizeof(buf)), an->avc_class, an->avc_perm, an->tcontext, aulookup_result(an->avc_result), l->e.serial); //printf("items:%d\n", l->s.avc->cnt); } while (alist_next_avc(l->s.avc)); break; case RPT_CONFIG: // FIXME:who, action, what, outcome, event // NOW: type auid success event printf("%s %s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_uid(l->s.loginuid, name, sizeof(name)), aulookup_success(l->s.success), l->e.serial); break; case RPT_AUTH: // who, addr, terminal, exe, success, event // Special note...uid is used here because that is // the way that the message works. This is because // on failed logins, loginuid is not set. safe_print_string(l->s.acct ? l->s.acct : aulookup_uid(l->s.uid, name, sizeof(name)), 0); printf(" %s %s %s %s %lu\n", l->s.hostname, l->s.terminal, l->s.exe, aulookup_success(l->s.success), l->e.serial); break; case RPT_LOGIN: // who, addr, terminal, exe, success, event // Special note...loginuid can be used here for // successful logins. loginuid is not set on failed // logins so acct is used in that situation. safe_print_string(((l->s.success == S_FAILED) && l->s.acct) ? l->s.acct : aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %s %s %lu\n", l->s.hostname, l->s.terminal, l->s.exe, aulookup_success(l->s.success), l->e.serial); break; case RPT_ACCT_MOD: // who, addr, terminal, exe, success, event safe_print_string( aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %s %s %s %lu\n", l->s.hostname ? l->s.hostname : "?", l->s.terminal ? l->s.terminal : "?", l->s.exe ? l->s.exe : "?", l->s.acct ? l->s.acct : "?", aulookup_success(l->s.success), l->e.serial); break; case RPT_EVENT: // report_detail == D_DETAILED // event, type, who, success printf("%lu %s ", l->e.serial, audit_msg_type_to_name(l->head->type)); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s\n", aulookup_success(l->s.success)); break; case RPT_FILE: // report_detail == D_DETAILED // file, syscall, success, exe, who, event { slist *s = l->s.filename; slist_first(s); if (s->cnt > 1) { char *key = s->cur ? s->cur->key : NULL; while (key && strcmp(key, "PARENT") == 0) { slist_next(s); key = s->cur ? s->cur->key : NULL; } } safe_print_string(s->cur ? s->cur->str : "", 0); printf(" %s %s ", aulookup_syscall(l,buf,sizeof(buf)), aulookup_success(l->s.success)); safe_print_string(l->s.exe ? l->s.exe : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); } break; case RPT_HOST: // report_detail == D_DETAILED // host, syscall, who, event printf("%s %s ", l->s.hostname, aulookup_syscall(l,buf,sizeof(buf))); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_PID: // report_detail == D_DETAILED // pid, exe, syscall, who, event printf("%u ", l->s.pid); safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %s ", aulookup_syscall(l,buf,sizeof(buf))); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_SYSCALL: // report_detail == D_DETAILED // syscall, pid, comm, who, event printf("%s %u ", aulookup_syscall(l,buf,sizeof(buf)), l->s.pid); safe_print_string(l->s.comm ? l->s.comm : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_TERM: // report_detail == D_DETAILED // terminal, host, exe, who, event printf("%s %s ", l->s.terminal, l->s.hostname); safe_print_string(l->s.exe, 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_USER: // report_detail == D_DETAILED // who, terminal, host, exe, event safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %lu\n", l->e.serial); break; case RPT_EXE: // report_detail == D_DETAILED // exe, terminal, host, who, event safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_COMM: // report_detail == D_DETAILED // comm, terminal, host, who, event safe_print_string(l->s.comm ? l->s.comm : "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_ANOMALY: // report_detail == D_DETAILED // type exe term host auid event printf("%s ", audit_msg_type_to_name(l->head->type)); safe_print_string(l->s.exe ? l->s.exe : l->s.comm ? l->s.comm: "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_RESPONSE: // report_detail == D_DETAILED // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_MAC: // auid type success event printf("%s %s %s %lu\n", aulookup_uid(l->s.loginuid, name, sizeof(name)), audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_INTEG: // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_VIRT: // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_CRYPTO: // auid type success event safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_KEY: // report_detail == D_DETAILED // key, success, exe, who, event slist_first(l->s.key); printf("%s %s ", l->s.key->cur->str, aulookup_success(l->s.success)); safe_print_string(l->s.exe ? l->s.exe : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_TTY: { char *ch, *ptr = strstr(l->head->message, "data="); if (!ptr) break; ptr += 5; ch = strrchr(ptr, ' '); if (ch) *ch = 0; // event who term sess data printf("%lu ", l->e.serial); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %u ", l->s.terminal ? l->s.terminal : "?", l->s.session_id); safe_print_string(l->s.comm ? l->s.comm: "?", 0); putchar(' '); print_tty_data(ptr); printf("\n"); } break; default: break; } }
/* * This function prints 1 rule from the kernel reply */ static void print_rule(const struct audit_rule_data *r) { unsigned int i, count = 0, sc = 0; size_t boffset = 0; int mach = -1, watch = is_watch(r); unsigned long long a0 = 0, a1 = 0; if (!watch) { /* This is syscall auditing */ printf("-a %s,%s", audit_action_to_name((int)r->action), audit_flag_to_name(r->flags)); // Now find the arch and print it for (i = 0; i < r->field_count; i++) { int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_ARCH) { int op = r->fieldflags[i] & AUDIT_OPERATORS; mach = print_arch(r->values[i], op); } } // And last do the syscalls count = print_syscall(r, &sc); } // Now iterate over the fields for (i = 0; i < r->field_count; i++) { const char *name; int op = r->fieldflags[i] & AUDIT_OPERATORS; int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_ARCH) continue; // already printed name = audit_field_to_name(field); if (name) { // Special cases to print the different field types // in a meaningful way. if (field == AUDIT_MSGTYPE) { if (!audit_msg_type_to_name(r->values[i])) printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); else printf(" -F %s%s%s", name, audit_operator_to_symbol(op), audit_msg_type_to_name( r->values[i])); } else if ((field >= AUDIT_SUBJ_USER && field <= AUDIT_OBJ_LEV_HIGH) && field != AUDIT_PPID) { printf(" -F %s%s%.*s", name, audit_operator_to_symbol(op), r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_WATCH) { if (watch) printf("-w %.*s", r->values[i], &r->buf[boffset]); else printf(" -F path=%.*s", r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_DIR) { if (watch) printf("-w %.*s/", r->values[i], &r->buf[boffset]); else printf(" -F dir=%.*s", r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_FILTERKEY) { char *rkey, *ptr, *saved; if (asprintf(&rkey, "%.*s", r->values[i], &r->buf[boffset]) < 0) rkey = NULL; boffset += r->values[i]; ptr = strtok_r(rkey, key_sep, &saved); while (ptr) { if (watch) printf(" -k %s", ptr); else printf(" -F key=%s", ptr); ptr = strtok_r(NULL, key_sep, &saved); } free(rkey); } else if (field == AUDIT_PERM) { char perms[5]; int val=r->values[i]; perms[0] = 0; if (val & AUDIT_PERM_READ) strcat(perms, "r"); if (val & AUDIT_PERM_WRITE) strcat(perms, "w"); if (val & AUDIT_PERM_EXEC) strcat(perms, "x"); if (val & AUDIT_PERM_ATTR) strcat(perms, "a"); if (watch) printf(" -p %s", perms); else printf(" -F perm=%s", perms); } else if (field == AUDIT_INODE) { // This is unsigned printf(" -F %s%s%u", name, audit_operator_to_symbol(op), r->values[i]); } else if (field == AUDIT_FIELD_COMPARE) { print_field_cmp(r->values[i], op); } else if (field >= AUDIT_ARG0 && field <= AUDIT_ARG3){ if (field == AUDIT_ARG0) a0 = r->values[i]; else if (field == AUDIT_ARG1) a1 = r->values[i]; // Show these as hex if (count > 1 || interpret == 0) printf(" -F %s%s0x%X", name, audit_operator_to_symbol(op), r->values[i]); else { // Use ignore to mean interpret const char *out; idata id; char val[32]; int type; id.syscall = sc; id.machine = mach; id.a0 = a0; id.a1 = a1; id.name = name; snprintf(val, 32, "%x", r->values[i]); id.val = val; type = auparse_interp_adjust_type( AUDIT_SYSCALL, name, val); out = auparse_do_interpretation(type, &id); printf(" -F %s%s%s", name, audit_operator_to_symbol(op), out); free((void *)out); } } else if (field == AUDIT_EXIT) { int e = abs((int)r->values[i]); const char *err = audit_errno_to_name(e); if (((int)r->values[i] < 0) && err) printf(" -F %s%s-%s", name, audit_operator_to_symbol(op), err); else printf(" -F %s%s%d", name, audit_operator_to_symbol(op), (int)r->values[i]); } else { // The default is signed decimal printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); } } else { // The field name is unknown printf(" f%d%s%d", r->fields[i], audit_operator_to_symbol(op), r->values[i]); } } printf("\n"); }
/* * This function will cycle through a single record and lookup each field's * value that it finds. */ static void output_interpreted_node(const lnode *n) { char *ptr, *str = n->message, *node = NULL; int found; // Reset these because each record could be different machine = -1; cur_syscall = -1; /* Check and see if we start with a node */ if (str[0] == 'n') { ptr=strchr(str, ' '); if (ptr) { *ptr = 0; node = str; str = ptr+1; } } // First locate time stamp. ptr = strchr(str, '('); if (ptr == NULL) { fprintf(stderr, "can't find time stamp\n"); return; } else { time_t t; int milli,num = n->type; unsigned long serial; struct tm *btm; char tmp[32]; const char *bptr; *ptr++ = 0; if (num == -1) { // see if we are older and wiser now. bptr = strchr(str, '['); if (bptr && bptr < ptr) { char *eptr; bptr++; eptr = strchr(bptr, ']'); if (eptr) { *eptr = 0; errno = 0; num = strtoul(bptr, NULL, 10); *eptr = ']'; if (errno) num = -1; } } } // print everything up to it. if (num >= 0) { bptr = audit_msg_type_to_name(num); if (bptr) { if (node) printf("%s ", node); printf("type=%s msg=audit(", bptr); goto no_print; } } if (node) printf("%s ", node); printf("%s(", str); no_print: // output formatted time. str = strchr(ptr, '.'); if (str == NULL) return; *str++ = 0; errno = 0; t = strtoul(ptr, NULL, 10); if (errno) return; ptr = strchr(str, ':'); if (ptr == NULL) return; *ptr++ = 0; milli = strtoul(str, NULL, 10); if (errno) return; str = strchr(ptr, ')'); if(str == NULL) return; *str++ = 0; serial = strtoul(ptr, NULL, 10); if (errno) return; btm = localtime(&t); strftime(tmp, sizeof(tmp), "%x %T", btm); printf("%s", tmp); printf(".%03d:%lu) ", milli, serial); } if (n->type == AUDIT_SYSCALL) { a0 = n->a0; a1 = n->a1; } // for each item. found = 0; while (str && *str && (ptr = strchr(str, '='))) { char *name, *val; int comma = 0; found = 1; // look back to last space - this is name name = ptr; while (*name != ' ' && name > str) --name; *ptr++ = 0; // print everything up to the '=' printf("%s=", str); // Some user messages have msg='uid=500 in this case // skip the msg= piece since the real stuff is the uid= if (strcmp(name, "msg") == 0) { str = ptr; continue; } // In the above case, after msg= we need to trim the ' from uid if (*name == '\'') name++; // get string after = to the next space or end - this is value if (*ptr == '\'' || *ptr == '"') { str = strchr(ptr+1, *ptr); if (str) { str++; if (*str) *str++ = 0; } } else { str = strchr(ptr, ','); val = strchr(ptr, ' '); if (str && val && (str < val)) { *str++ = 0; comma = 1; } else if (str && (val == NULL)) { *str++ = 0; comma = 1; } else if (val) { str = val; *str++ = 0; } } // val points to begin & str 1 past end val = ptr; // print interpreted string interpret(name, val, comma, n->type); } // If nothing found, just print out as is if (!found && ptr == NULL && str) printf("%s", str); printf("\n"); }
/* Returns 0 on stop, and 1 on HUP */ static int event_loop(void) { char *name = NULL, tmp_name[255]; /* Get the host name representation */ switch (daemon_config.node_name_format) { case N_NONE: break; case N_HOSTNAME: if (gethostname(tmp_name, sizeof(tmp_name))) { syslog(LOG_ERR, "Unable to get machine name"); name = strdup("?"); } else name = strdup(tmp_name); break; case N_USER: if (daemon_config.name) name = strdup(daemon_config.name); else { syslog(LOG_ERR, "User defined name missing"); name = strdup("?"); } break; case N_FQD: if (gethostname(tmp_name, sizeof(tmp_name))) { syslog(LOG_ERR, "Unable to get machine name"); name = strdup("?"); } else { int rc; struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; rc = getaddrinfo(tmp_name, NULL, &hints, &ai); if (rc != 0) { syslog(LOG_ERR, "Cannot resolve hostname %s (%s)", tmp_name, gai_strerror(rc)); name = strdup("?"); break; } name = strdup(ai->ai_canonname); freeaddrinfo(ai); } break; case N_NUMERIC: if (gethostname(tmp_name, sizeof(tmp_name))) { syslog(LOG_ERR, "Unable to get machine name"); name = strdup("?"); } else { int rc; struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; rc = getaddrinfo(tmp_name, NULL, &hints, &ai); if (rc != 0) { syslog(LOG_ERR, "Cannot resolve hostname %s (%s)", tmp_name, gai_strerror(rc)); name = strdup("?"); break; } inet_ntop(ai->ai_family, ai->ai_family == AF_INET ? (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr : (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, tmp_name, INET6_ADDRSTRLEN); freeaddrinfo(ai); name = strdup(tmp_name); } break; } /* Figure out the format for the af_unix socket */ while (stop == 0) { event_t *e; const char *type; char *v, *ptr, unknown[32]; unsigned int len; lnode *conf; /* This is where we block until we have an event */ e = dequeue(); if (e == NULL) { if (hup) { free(name); return 1; } continue; } /* Get the event formatted */ type = audit_msg_type_to_name(e->hdr.type); if (type == NULL) { snprintf(unknown, sizeof(unknown), "UNKNOWN[%d]", e->hdr.type); type = unknown; } if (daemon_config.node_name_format != N_NONE) { len = asprintf(&v, "node=%s type=%s msg=%.*s\n", name, type, e->hdr.size, e->data); } else len = asprintf(&v, "type=%s msg=%.*s\n", type, e->hdr.size, e->data); if (len <= 0) { free(e); /* Either corrupted event or no memory */ continue; } /* Strip newlines from event record */ ptr = v; while ((ptr = strchr(ptr, 0x0A)) != NULL) { if (ptr != &v[len-1]) *ptr = ' '; else break; /* Done - exit loop */ } /* Distribute event to the plugins */ plist_first(&plugin_conf); conf = plist_get_cur(&plugin_conf); do { if (conf == NULL || conf->p == NULL) continue; if (conf->p->active == A_NO) continue; /* Now send the event to the right child */ if (conf->p->type == S_SYSLOG) send_syslog(v); else if (conf->p->type == S_AF_UNIX) { if (conf->p->format == F_STRING) send_af_unix_string(v, len); else send_af_unix_binary(e); } else if (conf->p->type == S_ALWAYS) { int rc; rc = write_to_plugin(e, v, len, conf); if (rc < 0 && errno == EPIPE) { /* Child disappeared ? */ syslog(LOG_ERR, "plugin %s terminated unexpectedly", conf->p->path); conf->p->pid = 0; conf->p->restart_cnt++; if (conf->p->restart_cnt > daemon_config.max_restarts) { syslog(LOG_ERR, "plugin %s has exceeded max_restarts", conf->p->path); } close(conf->p->plug_pipe[1]); conf->p->plug_pipe[1] = -1; conf->p->active = A_NO; if (start_one_plugin(conf)) { rc = write_to_plugin(e, v, len, conf); syslog(LOG_NOTICE, "plugin %s was restarted", conf->p->path); conf->p->active = A_YES; } } } } while ((conf = plist_next(&plugin_conf))); /* Done with the memory...release it */ free(v); free(e); if (hup) break; } free(name); if (stop) return 0; else return 1; }
/* This function shows how to dump a whole record's text */ static void dump_whole_record(auparse_state_t *au) { printf("%s: %s\n", audit_msg_type_to_name(auparse_get_type(au)), auparse_get_record_text(au)); printf("\n"); }
/* * This function interprets the reply and prints it to stdout. It returns * 0 if no more should be read and 1 to indicate that more messages of this * type may need to be read. */ static int audit_print_reply(struct audit_reply *rep) { unsigned int i; int first; int sparse; int machine = audit_detect_machine(); size_t boffset; int show_syscall; _audit_elf = 0; switch (rep->type) { case NLMSG_NOOP: return 1; case NLMSG_DONE: if (printed == 0) printf("No rules\n"); return 0; case NLMSG_ERROR: printf("NLMSG_ERROR %d (%s)\n", -rep->error->error, strerror(-rep->error->error)); printed = 1; return 0; case AUDIT_GET: printf("AUDIT_STATUS: enabled=%d flag=%d pid=%d" " rate_limit=%d backlog_limit=%d lost=%d backlog=%u\n", rep->status->enabled, rep->status->failure, rep->status->pid, rep->status->rate_limit, rep->status->backlog_limit, rep->status->lost, rep->status->backlog); printed = 1; return 0; case AUDIT_LIST_RULES: list_requested = 0; boffset = 0; show_syscall = 1; if (key_match(rep) == 0) return 1; printed = 1; printf("%s: %s,%s", audit_msg_type_to_name(rep->type), audit_flag_to_name((int)rep->ruledata->flags), audit_action_to_name(rep->ruledata->action)); for (i = 0; i < rep->ruledata->field_count; i++) { const char *name; int op = rep->ruledata->fieldflags[i] & AUDIT_OPERATORS; int field = rep->ruledata->fields[i] & ~AUDIT_OPERATORS; name = audit_field_to_name(field); if (name) { if (strcmp(name, "arch") == 0) { _audit_elf = rep->ruledata->values[i]; printf(" %s%s%u", name, audit_operator_to_symbol(op), (unsigned)rep->ruledata->values[i]); } else if (strcmp(name, "msgtype") == 0) { if (!audit_msg_type_to_name( rep->ruledata->values[i])) printf(" %s%s%d", name, audit_operator_to_symbol(op), rep->ruledata->values[i]); else { printf(" %s%s%s", name, audit_operator_to_symbol(op), audit_msg_type_to_name(rep->ruledata->values[i])); } } else if ((field >= AUDIT_SUBJ_USER && field <= AUDIT_OBJ_LEV_HIGH) && field != AUDIT_PPID && rep->type == AUDIT_LIST_RULES) { printf(" %s%s%.*s", name, audit_operator_to_symbol(op), rep->ruledata->values[i], &rep->ruledata->buf[boffset]); boffset += rep->ruledata->values[i]; } else if (field == AUDIT_WATCH) { printf(" watch=%.*s", rep->ruledata->values[i], &rep->ruledata->buf[boffset]); boffset += rep->ruledata->values[i]; } else if (field == AUDIT_DIR) { printf(" dir=%.*s", rep->ruledata->values[i], &rep->ruledata->buf[boffset]); boffset += rep->ruledata->values[i]; } else if (field == AUDIT_FILTERKEY) { char *rkey, *ptr; asprintf(&rkey, "%.*s", rep->ruledata->values[i], &rep->ruledata->buf[boffset]); boffset += rep->ruledata->values[i]; ptr = strtok(rkey, key_sep); while (ptr) { printf(" key=%s", ptr); ptr = strtok(NULL, key_sep); } free(rkey); } else if (field == AUDIT_PERM) { char perms[5]; int val=rep->ruledata->values[i]; perms[0] = 0; if (val & AUDIT_PERM_READ) strcat(perms, "r"); if (val & AUDIT_PERM_WRITE) strcat(perms, "w"); if (val & AUDIT_PERM_EXEC) strcat(perms, "x"); if (val & AUDIT_PERM_ATTR) strcat(perms, "a"); printf(" perm=%s", perms); show_syscall = 0; } else if (field == AUDIT_INODE) { // Unsigned items printf(" %s%s%u", name, audit_operator_to_symbol(op), rep->ruledata->values[i]); } else if (field == AUDIT_FIELD_COMPARE) { switch (rep->ruledata->values[i]) { case AUDIT_COMPARE_UID_TO_OBJ_UID: printf(" uid%sobj_uid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_OBJ_GID: printf(" gid%sobj_gid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_OBJ_UID: printf(" euid%sobj_uid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_OBJ_GID: printf(" egid%sobj_gid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_OBJ_UID: printf(" auid%sobj_uid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SUID_TO_OBJ_UID: printf(" suid%sobj_uid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SGID_TO_OBJ_GID: printf(" sgid%sobj_gid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_FSUID_TO_OBJ_UID: printf(" fsuid%sobj_uid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_FSGID_TO_OBJ_GID: printf(" fsgid%sobj_gid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_AUID: printf(" uid%sauid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_EUID: printf(" uid%seuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_FSUID: printf(" uid%sfsuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_SUID: printf(" uid%ssuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_FSUID: printf(" auid%sfsuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_SUID: printf(" auid%ssuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_EUID: printf(" auid%seuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_SUID: printf(" euid%ssuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_FSUID: printf(" euid%sfsuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SUID_TO_FSUID: printf(" suid%sfsuid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_EGID: printf(" gid%segid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_FSGID: printf(" gid%sfsgid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_SGID: printf(" gid%ssgid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_FSGID: printf(" egid%sfsgid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_SGID: printf(" egid%ssgid",audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SGID_TO_FSGID: printf(" sgid%sfsgid",audit_operator_to_symbol(op)); break; } } else { // Signed items printf(" %s%s%d", name, audit_operator_to_symbol(op), rep->ruledata->values[i]); } } else { printf(" f%d%s%d", rep->ruledata->fields[i], audit_operator_to_symbol(op), rep->ruledata->values[i]); } /* Avoid printing value if the field type is * known to return a string. */ if (rep->ruledata->values[i] && (field < AUDIT_SUBJ_USER || field > AUDIT_SUBJ_CLR) && field != AUDIT_WATCH && field != AUDIT_FILTERKEY && field != AUDIT_PERM && field != AUDIT_FIELD_COMPARE) printf(" (0x%x)", rep->ruledata->values[i]); } if (show_syscall && ((rep->ruledata->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_USER) && ((rep->ruledata->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK) && ((rep->ruledata->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_EXCLUDE)) { printf(" syscall="); for (sparse = 0, i = 0; i < (AUDIT_BITMASK_SIZE-1); i++) { if (rep->ruledata->mask[i] != (uint32_t)~0) sparse = 1; } if (!sparse) { printf("all"); } else for (first = 1, i = 0; i < AUDIT_BITMASK_SIZE * 32; i++) { int word = AUDIT_WORD(i); int bit = AUDIT_BIT(i); if (rep->ruledata->mask[word] & bit) { const char *ptr; if (_audit_elf) machine = audit_elf_to_machine( _audit_elf); if (machine < 0) ptr = NULL; else ptr = audit_syscall_to_name(i, machine); if (ptr) printf("%s%s", first ? "" : ",", ptr); else printf("%s%d", first ? "" : ",", i); first = 0; } } } printf("\n"); return 1; /* get more messages until NLMSG_DONE */ default: printf("Unknown: type=%d, len=%d\n", rep->type, rep->nlh->nlmsg_len); printed = 1; return 0; } }
/* * This function examines the commandline parameters and sets various * search options. It returns a 0 on success and < 0 on failure */ int check_params(int count, char *vars[]) { int c = 1; int retval = 0; const char *optarg; if (count < 2) { usage(); return -1; } while (c < count && retval == 0) { // Go ahead and point to the next argument if (c+1 < count) { if (vars[c+1][0] != '-') optarg = vars[c+1]; else optarg = NULL; } else optarg = NULL; switch (audit_lookup_option(vars[c])) { case S_EVENT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_id = strtoul(optarg, NULL, 10); if (errno) { fprintf(stderr, "Illegal value for audit event ID"); retval = -1; } c++; } else { fprintf(stderr, "Audit event id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_COMM: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_comm = strdup(optarg); if (event_comm == NULL) retval = -1; c++; } break; case S_FILENAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_filename = strdup(optarg); if (event_filename == NULL) retval = -1; c++; } break; case S_KEY: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_key = strdup(optarg); if (event_key == NULL) retval = -1; c++; } break; case S_ALL_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_gid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_gid = gr->gr_gid; } event_egid = event_gid; event_ga = 1; c++; break; case S_EFF_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_egid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Effective group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_egid = gr->gr_gid; } c++; break; case S_GID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_gid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric group ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct group *gr ; gr = getgrnam(optarg) ; if (gr == NULL) { fprintf(stderr, "Group ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_gid = gr->gr_gid; } c++; break; case S_HELP: usage(); exit(0); break; case S_HOSTNAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_hostname = strdup(optarg); if (event_hostname == NULL) retval = -1; c++; } break; case S_INTERP: if (report_format == RPT_DEFAULT) report_format = RPT_INTERP; else { fprintf(stderr, "Conflicting output format %s\n", vars[c]); retval = -1; } if (optarg) { fprintf(stderr, "Argument is NOT required for %s\n", vars[c]); retval = -1; } break; case S_INFILE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { user_file = strdup(optarg); if (user_file == NULL) retval = -1; c++; } break; case S_MESSAGE_TYPE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { if (strcasecmp(optarg, "ALL") != 0) { retval = parse_msg(optarg); } c++; } if (retval < 0) { int i; fprintf(stderr, "Valid message types are: ALL "); for (i=AUDIT_USER;i<=AUDIT_LAST_VIRT_MSG;i++){ const char *name; if (i == AUDIT_WATCH_INS) // Skip a few i = AUDIT_FIRST_USER_MSG; name = audit_msg_type_to_name(i); if (name) fprintf(stderr, "%s ", name); } fprintf(stderr, "\n"); } break; case S_OBJECT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_object = strdup(optarg); if (event_object == NULL) retval = -1; c++; } break; case S_PPID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_ppid = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else { fprintf(stderr, "Parent process id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_PID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_pid = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else { fprintf(stderr, "Process id must be a numeric value, was %s\n", optarg); retval = -1; } break; case S_RAW: if (report_format == RPT_DEFAULT) report_format = RPT_RAW; else { fprintf(stderr, "Conflicting output format --raw\n"); retval = -1; } if (optarg) { fprintf(stderr, "Argument is NOT required for --raw\n"); retval = -1; } break; case S_NODE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { snode sn; c++; if (!event_node_list) { event_node_list = malloc(sizeof (slist)); if (!event_node_list) { retval = -1; break; } slist_create(event_node_list); } sn.str = strdup(optarg); sn.key = NULL; sn.hits=0; slist_append(event_node_list, &sn); } break; case S_SYSCALL: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_syscall = (int)strtoul(optarg, NULL, 10); if (errno) { fprintf(stderr, "Syscall numeric conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { int machine; machine = audit_detect_machine(); if (machine < 0) { fprintf(stderr, "Error detecting machine type"); retval = -1; break; } event_syscall = audit_name_to_syscall(optarg, machine); if (event_syscall == -1) { fprintf(stderr, "Syscall %s not found\n", optarg); retval = -1; } } c++; break; case S_CONTEXT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_subject = strdup(optarg); if (event_subject == NULL) retval = -1; event_object = strdup(optarg); if (event_object == NULL) retval = -1; event_se = 1; c++; } break; case S_SUBJECT: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } else { event_subject = strdup(optarg); if (event_subject == NULL) retval = -1; c++; } break; case S_OSUCCESS: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if ( (strstr(optarg, "yes")!=NULL) || (strstr(optarg, "no")!=NULL) ) { if (strcmp(optarg, "yes") == 0) event_success = S_SUCCESS; else event_success = S_FAILED; } else { fprintf(stderr, "Success must be 'yes' or 'no'.\n"); retval = -1; } c++; break; case S_SESSION: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_session_id = strtol(optarg,NULL,10); if (errno) retval = -1; c++; } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_session_id = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } c++; } else { fprintf(stderr, "Session id must be a numeric value, was %s\n", optarg); retval = -1; } } break; case S_EXIT: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_exit = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_exit = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else { event_exit = audit_name_to_errno(optarg); if (event_exit == 0) { retval = -1; fprintf(stderr, "Unknown errno, was %s\n", optarg); } } c++; if (retval != -1) event_exit_is_set = 1; } break; case S_TIME_END: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order*/ if (strchr(optarg, ':')) { if (ausearch_time_end(vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_end(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_end(optarg, NULL) != 0) retval = -1; } else if ( (strchr(optarg, ':')) == NULL) { /* Only have date */ if (ausearch_time_end(optarg, NULL) != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_end(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case S_TIME_START: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order */ if (strchr(optarg, ':')) { if (ausearch_time_start( vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_start(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else if ( strchr(optarg, ':') == NULL) { /* Only have date */ if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_start(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case S_TERMINAL: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_terminal = strdup(optarg); if (event_terminal == NULL) retval = -1; c++; } break; case S_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_uid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw; pw = getpwnam(optarg); if (pw == NULL) { fprintf(stderr, "Effective user ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_uid = pw->pw_uid; } c++; break; case S_EFF_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_euid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "User ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_euid = pw->pw_uid; } c++; break; case S_ALL_UID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit(optarg[0])) { errno = 0; event_uid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "User ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_uid = pw->pw_uid; } event_ua = 1; event_euid = event_uid; event_loginuid = event_uid; c++; break; case S_LOGINID: if (!optarg) { if ((c+1 < count) && vars[c+1]) optarg = vars[c+1]; else { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } } { size_t len = strlen(optarg); if (isdigit(optarg[0])) { errno = 0; event_loginuid = strtoul(optarg,NULL,10); if (errno) { fprintf(stderr, "Numeric user ID conversion error (%s) for %s\n", strerror(errno), optarg); retval = -1; } } else if (len >= 2 && *(optarg)=='-' && (isdigit(optarg[1]))) { errno = 0; event_loginuid = strtol(optarg, NULL, 0); if (errno) { retval = -1; fprintf(stderr, "Error converting %s\n", optarg); } } else { struct passwd *pw ; pw = getpwnam(optarg) ; if (pw == NULL) { fprintf(stderr, "Login user ID is non-numeric and unknown (%s)\n", optarg); retval = -1; break; } event_loginuid = pw->pw_uid; } } c++; break; case S_UUID: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_uuid = strdup(optarg); if (event_uuid == NULL) { retval = -1; } c++; } break; case S_VMNAME: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_vmname= strdup(optarg); if (event_vmname == NULL) { retval = -1; } c++; } break; case S_VERSION: printf("ausearch version %s\n", VERSION); exit(0); break; case S_EXACT_MATCH: event_exact_match=1; break; case S_IN_LOGS: force_logs = 1; break; case S_JUST_ONE: just_one = 1; break; case S_EXECUTABLE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { event_exe = strdup(optarg); if (event_exe == NULL) retval = -1; c++; } break; case S_LINEBUFFERED: line_buffered = 1; break; default: fprintf(stderr, "%s is an unsupported option\n", vars[c]); retval = -1; break; } c++; } return retval; }
/* * This function will cycle through a single record and lookup each field's * value that it finds. */ static void output_interpreted_record(const lnode *n, const event *e) { char *ptr, *str = n->message; int found, comma = 0; int num = n->type; struct tm *btm; char tmp[32]; // Reset these because each record could be different machine = -1; cur_syscall = -1; /* Check and see if we start with a node * If we do, and there is a space in the line * move the pointer to the first character past * the space */ if (e->node) { if ((ptr=strchr(str, ' ')) != NULL) { str = ptr+1; } } // First locate time stamp. ptr = strchr(str, '('); if (ptr == NULL) { fprintf(stderr, "can't find time stamp\n"); return; } *ptr++ = 0; /* move to the start of the timestamp */ // print everything up to it. if (num >= 0) { const char * bptr; bptr = audit_msg_type_to_name(num); if (bptr) { if (e->node) printf("node=%s ", e->node); printf("type=%s msg=audit(", bptr); goto no_print; } } if (e->node) printf("node=%s ", e->node); printf("%s(", str); no_print: str = strchr(ptr, ')'); if(str == NULL) return; *str++ = 0; btm = localtime(&e->sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s", tmp); printf(".%03u:%lu) ", e->milli, e->serial); if (n->type == AUDIT_SYSCALL) { a0 = n->a0; a1 = n->a1; } // for each item. ausearch_load_interpretations(n); found = 0; while (str && *str && (ptr = strchr(str, '='))) { char *name, *val; comma = 0; found = 1; // look back to last space - this is name name = ptr; while (*name != ' ' && name > str) --name; *ptr++ = 0; // print everything up to the '=' printf("%s=", str); // Some user messages have msg='uid=500 in this case // skip the msg= piece since the real stuff is the uid= if (strcmp(name, "msg") == 0) { str = ptr; continue; } // In the above case, after msg= we need to trim the ' from uid if (*name == '\'') name++; // get string after = to the next space or end - this is value if (*ptr == '\'' || *ptr == '"') { str = strchr(ptr+1, *ptr); if (str) { str++; if (*str) *str++ = 0; } } else { str = strchr(ptr, ','); val = strchr(ptr, ' '); if (str && val && (str < val)) { // Value side has commas and another field exists // Known: LABEL_LEVEL_CHANGE banners=none,none // Known: ROLL_ASSIGN new-role=r,r // Known: any MAC LABEL can potentially have commas int ftype = auparse_interp_adjust_type(n->type, name, val); if (ftype == AUPARSE_TYPE_MAC_LABEL) { str = val; *str++ = 0; } else { *str++ = 0; comma = 1; } } else if (str && (val == NULL)) { // Goes all the way to the end. Done parsing // Known: MCS context in PATH rec obj=u:r:t:s0:c2,c7 int ftype = auparse_interp_adjust_type(n->type, name, ptr); if (ftype == AUPARSE_TYPE_MAC_LABEL) str = NULL; else { *str++ = 0; comma = 1; } } else if (val) { // There is another field, point to next (normal path) str = val; *str++ = 0; } } // val points to begin & str 1 past end val = ptr; // print interpreted string interpret(name, val, comma, n->type); } ausearch_free_interpretations(); // If nothing found, just print out as is if (!found && ptr == NULL && str) safe_print_string(str, 1); // If last field had comma, output the rest else if (comma) safe_print_string(str, 1); printf("\n"); }