/* 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"); }
/* This function receives a single complete event at a time from the auparse * library. This is where the main analysis code would be added. */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { int type, num=0; if (cb_event_type != AUPARSE_CB_EVENT_READY) return; /* Loop through the records in the event looking for one to process. We use physical record number because we may search around and move the cursor accidentally skipping a record. */ while (auparse_goto_record_num(au, num) > 0) { type = auparse_get_type(au); /* Now we can branch based on what record type we find. This is just a few suggestions, but it could be anything. */ switch (type) { case AUDIT_AVC: dump_fields_of_record(au); break; case AUDIT_SYSCALL: dump_whole_record(au); break; case AUDIT_USER_LOGIN: break; case AUDIT_ANOM_ABEND: break; case AUDIT_MAC_STATUS: dump_whole_event(au); break; default: break; } num++; } }
static void auparse_callback(auparse_state_t *_au, auparse_cb_event_t cb_event_type, void *user_data) { int *event_cnt = (int *)user_data; int num_records = auparse_get_num_records(_au); int record_cnt; if (cb_event_type == AUPARSE_CB_EVENT_READY) { if (auparse_first_record(_au) <= 0) { return; } record_cnt = 1; do { int audtype = return_audtype(auparse_get_type(_au)); switch(audtype) { case PLACE_OBJ: // au, event number:total rec in event:this num in event process_place_obj(_au, event_cnt, num_records, record_cnt); break; case USER_OBJ: process_user_obj(_au, event_cnt, num_records, record_cnt); break; case SYSCALL_OBJ: process_syscall_obj(_au, event_cnt, num_records, record_cnt); break; case SOCK_OBJ: process_sock_obj(_au, event_cnt, num_records, record_cnt); break; case EXECVE_OBJ: process_execv_obj(_au, event_cnt, num_records, record_cnt); break; case GENERIC_OBJ: process_generic_obj(_au, event_cnt, num_records, record_cnt); break; } const au_event_t *e = auparse_get_timestamp(_au); if (e == NULL) { return; } record_cnt++; } while(auparse_next_record(_au) > 0); // end of do (*event_cnt)++; } // end cb_event_type == AUPARSE_CB_EVENT_READY }
int main(int argc, char *argv[]) { int i, use_stdin = 0; char *user = NULL, *file = NULL; struct passwd *p; auparse_state_t *au; setlocale (LC_ALL, ""); for (i=1; i<argc; i++) { if (argv[i][0] != '-') { //take input and lookup as if it were a user name //if that fails assume its a tty if (user == NULL) { p = getpwnam(argv[i]); if (p) { cuid = p->pw_uid; user = argv[i]; continue; } } if (cterm == NULL) { cterm = argv[i]; } else { usage(); return 1; } } else { if (strcmp(argv[i], "-f") == 0) { if (use_stdin == 0) { i++; file = argv[i]; } else { fprintf(stderr,"stdin already given\n"); return 1; } } else if (strcmp(argv[i], "--bad") == 0) { bad = 1; } else if (strcmp(argv[i], "--proof") == 0) { proof = 1; } else if (strcmp(argv[i], "--extract") == 0) { f = fopen("aulast.log", "wt"); } else if (strcmp(argv[i], "--stdin") == 0) { if (file == NULL) use_stdin = 1; else { fprintf(stderr, "file already given\n"); return 1; } } else if (strcmp(argv[i], "--debug") == 0) { debug = 1; } else { usage(); return 1; } } } list_create(&l); // Search for successful user logins if (file) au = auparse_init(AUSOURCE_FILE, file); else if (use_stdin) au = auparse_init(AUSOURCE_FILE_POINTER, stdin); else { if (getuid()) { fprintf(stderr, "You probably need to be root for this to work\n"); } au = auparse_init(AUSOURCE_LOGS, NULL); } if (au == NULL) { fprintf(stderr, "Error - %s\n", strerror(errno)); goto error_exit_1; } // The theory: iterate though events // 1) when LOGIN is found, create a new session node // 2) if that session number exists, close out the old one // 3) when USER_LOGIN is found, update session node // 4) When USER_END is found update session node and close it out // 5) When BOOT record found make new record and check for previous // 6) If previous boot found, set status to crash and logout everyone // 7) When SHUTDOWN found, close out reboot record while (auparse_next_event(au) > 0) { // We will take advantage of the fact that all events // of interest are one record long int type = auparse_get_type(au); if (type < 0) continue; switch (type) { case AUDIT_LOGIN: create_new_session(au); extract_record(au); break; case AUDIT_USER_LOGIN: update_session_login(au); extract_record(au); break; case AUDIT_USER_END: update_session_logout(au); extract_record(au); break; case AUDIT_SYSTEM_BOOT: process_bootup(au); extract_record(au); break; case AUDIT_SYSTEM_SHUTDOWN: process_shutdown(au); extract_record(au); break; case AUDIT_DAEMON_START: process_kernel(au); extract_record(au); break; } } auparse_destroy(au); // Now output the leftovers list_first(&l); do { lnode *cur = list_get_cur(&l); report_session(cur); } while (list_next(&l)); free(kernel); list_clear(&l); if (f) fclose(f); return 0; error_exit_1: list_clear(&l); if (f) fclose(f); return 1; }
int main(int argc, char **argv) { int rc = 0; auparse_state_t *au = NULL; setlocale(LC_ALL, ""); if (parse_args(argc, argv)) goto error; if (help_flag) { usage(stdout); goto exit; } /* Initialize event list*/ events = list_new((list_free_data_fn*) event_free); if (events == NULL) goto unexpected_error; /* Initialize auparse */ au = init_auparse(); if (au == NULL) goto error; if (create_search_criteria(au)) goto error; while (ausearch_next_event(au) > 0) { int err = 0; switch(auparse_get_type(au)) { case AUDIT_VIRT_MACHINE_ID: err = process_machine_id_event(au); break; case AUDIT_VIRT_CONTROL: err = process_control_event(au); break; case AUDIT_VIRT_RESOURCE: err = process_resource_event(au); break; case AUDIT_AVC: err = process_avc(au); break; case AUDIT_FIRST_ANOM_MSG ... AUDIT_LAST_ANOM_MSG: case AUDIT_FIRST_KERN_ANOM_MSG ... AUDIT_LAST_KERN_ANOM_MSG: err = process_anom(au); break; case AUDIT_SYSTEM_SHUTDOWN: err = process_shutdown(au); break; } if (err) { goto unexpected_error; } auparse_next_event(au); } /* Show results */ if (summary_flag) { print_summary(); } else { print_events(); } /* success */ goto exit; unexpected_error: fprintf(stderr, "Unexpected error\n"); error: rc = 1; exit: if (au) auparse_destroy(au); list_free(events); if (debug) fprintf(stdout, "Exit code: %d\n", rc); return rc; }
/* 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 will output a normalized line of audit * fields one line per event as an english sentence */ static void text_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { if (cb_event_type != AUPARSE_CB_EVENT_READY) return; char tmp[20]; const char *item, *action, *how; int rc, type, id = -2; time_t t = auparse_get_time(au); struct tm *tv = localtime(&t); if (tv) strftime(tmp, sizeof(tmp), "%T %x", tv); else strcpy(tmp, "?"); type = auparse_get_type(au); auparse_normalize(au, NORM_OPT_NO_ATTRS); item = auparse_get_node(au); if (item) { printf("On %s at %s ", auparse_interpret_field(au), tmp); free((void *)item); } else printf("At %s ", tmp); rc = auparse_normalize_subject_primary(au); if (rc == 1) { const char *subj = auparse_interpret_field(au); id = auparse_get_field_int(au); if (strcmp(subj, "unset") == 0) subj = "system"; printf("%s", subj); } // Need to compare auid and uid before doing this rc = auparse_normalize_subject_secondary(au); if (rc == 1) { int uid = auparse_get_field_int(au); if (uid != id && id != -2) printf(", acting as %s,", auparse_interpret_field(au)); } rc = auparse_normalize_get_results(au); if (rc == 1) { int i = 0; const char *res[] = { "unsuccessfully", "successfully" }; item = auparse_interpret_field(au); if (strcmp(item, "yes") == 0) i = 1; else if (strncmp(item, "suc", 3) == 0) i = 1; else if (auparse_get_field_type(au) == AUPARSE_TYPE_SECCOMP && strcmp(item, "allow") == 0) i = 1; printf(" %s ", res[i]); } else putchar(' '); action = auparse_normalize_get_action(au); if (event_debug) { if (action == NULL) printf("error on type:%d\n", type); } printf("%s ", action ? action : "did-unknown"); rc = auparse_normalize_object_primary(au); if (rc == 1) { const char *val = NULL; int ftype; // If we have an object and this is an AVC, add some words if (action && strstr(action, "violated")) val = "accessing "; ftype = auparse_get_field_type(au); if (ftype == AUPARSE_TYPE_ESCAPED_FILE) val = auparse_interpret_realpath(au); else if (ftype == AUPARSE_TYPE_SOCKADDR) { val = auparse_interpret_sock_address(au); if (val == NULL) val = auparse_interpret_sock_family(au); } if (val == NULL) val = auparse_interpret_field(au); printf("%s ", val); } rc = auparse_normalize_object_primary2(au); if (rc == 1) { const char *val; if (auparse_get_field_type(au) == AUPARSE_TYPE_ESCAPED_FILE) val = auparse_interpret_realpath(au); else val = auparse_interpret_field(au); printf("to %s ", val); } how = auparse_normalize_how(au); if (how && action && *action != 'e') // Don't print for ended-session printf("using %s", how); printf("\n"); }
/* * auparse_callback - callback routine to be executed once a complete event is composed */ void auparse_callback(auparse_state_t * au, auparse_cb_event_t cb_event_type, void *user_data) { int *event_cnt = (int *) user_data; if (cb_event_type == AUPARSE_CB_EVENT_READY) { if (auparse_first_record(au) <= 0) return; /* If no first record, then no event ! */ if (!(flags & F_CHECK)) printf("event=%d records=%d\n", *event_cnt, auparse_get_num_records(au)); do { const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) return; /* If no timestamp, then no event */ /* If checking, we just emit the raw record again */ if (flags & F_CHECK) { if (e->host != NULL) printf("node=%s type=%s msg=audit(%u.%3.3u:%lu):", e->host, auparse_get_type_name(au), (unsigned) e->sec, e->milli, e->serial); else printf("type=%s msg=audit(%u.%3.3u:%lu):", auparse_get_type_name(au), (unsigned) e->sec, e->milli, e->serial); auparse_first_field(au); /* Move to first field */ do { const char *fname = auparse_get_field_name(au); /* We ignore the node and type fields */ if (strcmp(fname, "type") == 0 || strcmp(fname, "node") == 0) continue; printf(" %s=%s", fname, auparse_get_field_str(au)); } while (auparse_next_field(au) > 0); printf("\n"); continue; } printf("fields=%d\t", auparse_get_num_fields(au)); printf("type=%d (%s) ", auparse_get_type(au), auparse_get_type_name(au)); printf("event_tid=%u.%3.3u:%lu ", (unsigned) e->sec, e->milli, e->serial); if (flags & F_VERBOSE) { char *fv, *ifv = NULL; auparse_first_field(au); /* Move to first field */ do { fv = (char *) auparse_get_field_str(au); ifv = (char *) auparse_interpret_field(au); printf("%s=", auparse_get_field_name(au)); print_escape(stdout, fv, "=()"); printf(" ("); print_escape(stdout, ifv, "=()"); printf(") "); } while (auparse_next_field(au) > 0); } printf("\n"); } while (auparse_next_record(au) > 0); (*event_cnt)++; } }