static void interpret(char *name, char *val, int comma, int rtype) { int type; idata id; while (*name == ' '||*name == '(') name++; if (*name == 'a' && strcmp(name, "acct") == 0) { // Remove trailing punctuation int len = strlen(val); if (val[len-1] == ':') val[len-1] = 0; } type = auparse_interp_adjust_type(rtype, name, val); if (rtype == AUDIT_SYSCALL) { if (machine == (unsigned long)-1) machine = audit_detect_machine(); if (*name == 'a' && strcmp(name, "arch") == 0) { unsigned long ival; errno = 0; ival = strtoul(val, NULL, 16); if (errno) { printf("arch conversion error(%s) ", val); return; } machine = audit_elf_to_machine(ival); } if (cur_syscall < 0 && *name == 's' && strcmp(name, "syscall") == 0) { unsigned long ival; errno = 0; ival = strtoul(val, NULL, 10); if (errno) { printf("syscall conversion error(%s) ", val); return; } cur_syscall = ival; } id.syscall = cur_syscall; } else id.syscall = 0; id.machine = machine; id.a0 = a0; id.a1 = a1; id.name = name; id.val = val; char *out = auparse_do_interpretation(type, &id); if (type == AUPARSE_TYPE_UNCLASSIFIED) printf("%s%c", val, comma ? ',' : ' '); else if (name[0] == 'k' && strcmp(name, "key") == 0) { char *str, *ptr = out; int count = 0; while ((str = strchr(ptr, AUDIT_KEY_SEPARATOR))) { *str = 0; if (count == 0) { printf("%s", ptr); count++; } else printf(" key=%s", ptr); ptr = str+1; } if (count == 0) printf("%s ", out); else printf(" key=%s ", ptr); } else if (type == AUPARSE_TYPE_TTY_DATA) printf("%s", out); else printf("%s ", out); free(out); }
/* * 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_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"); }