/* * aureport.c - main file for aureport utility * Copyright 2005-08, 2010,11,2013 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libaudit.h" #include "auditd-config.h" #include "aureport-options.h" #include "aureport-scan.h" #include "ausearch-lol.h" #include "ausearch-lookup.h" event very_first_event, very_last_event; static FILE *log_fd = NULL; static lol lo; static int found = 0; static int files_to_process = 0; // Logs left when processing multiple static int userfile_is_dir = 0; static int process_logs(void); static int process_log_fd(const char *filename); static int process_stdin(void); static int process_file(char *filename); static int get_record(llist **); extern char *user_file; extern int force_logs; static int is_pipe(int fd) { struct stat st; if (fstat(fd, &st) == 0) { if (S_ISFIFO(st.st_mode)) return 1; } return 0; } int main(int argc, char *argv[]) { struct rlimit limit; int rc; /* Check params and build regexpr */ setlocale (LC_ALL, ""); if (check_params(argc, argv)) return 1; /* Raise the rlimits in case we're being started from a shell * with restrictions. Not a fatal error. */ limit.rlim_cur = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_FSIZE, &limit); setrlimit(RLIMIT_CPU, &limit); set_aumessage_mode(MSG_STDERR, DBG_NO); (void) umask( umask( 077 ) | 027 ); very_first_event.sec = 0; reset_counters(); print_title(); lol_create(&lo); if (user_file) { struct stat sb; if (stat(user_file, &sb) == -1) { perror("stat"); return 1; } else { switch (sb.st_mode & S_IFMT) { case S_IFDIR: userfile_is_dir = 1; rc = process_logs(); break; case S_IFREG: default: rc = process_file(user_file); break; } } } else if (force_logs) rc = process_logs(); else if (is_pipe(0)) rc = process_stdin(); else rc = process_logs(); lol_clear(&lo); if (rc) return rc; if (!found && report_detail == D_DETAILED && report_type != RPT_TIME) { printf("\n\n"); destroy_counters(); aulookup_destroy_uid_list(); aulookup_destroy_gid_list(); return 1; } else print_wrap_up(); destroy_counters(); aulookup_destroy_uid_list(); aulookup_destroy_gid_list(); free(user_file); return 0; } static int process_logs(void) { struct daemon_conf config; char *filename; int len, num = 0; if (user_file && userfile_is_dir) { char dirname[MAXPATHLEN]; clear_config (&config); strcpy(dirname, user_file); if (dirname[strlen(dirname)-1] != '/') strcat(dirname, "/"); strcat (dirname, "audit.log"); free((void *)config.log_file); config.log_file=strdup(dirname); fprintf(stderr, "NOTE - using logs in %s\n", config.log_file); } else { /* Load config so we know where logs are */ if (load_config(&config, TEST_SEARCH)) fprintf(stderr, "NOTE - using built-in logs: %s\n", config.log_file); } /* for each file */ len = strlen(config.log_file) + 16; filename = malloc(len); if (!filename) { fprintf(stderr, "No memory\n"); free_config(&config); return 1; } /* Find oldest log file */ snprintf(filename, len, "%s", config.log_file); do { if (access(filename, R_OK) != 0) break; // FIXME: do a time check and put them on linked list for later num++; snprintf(filename, len, "%s.%d", config.log_file, num); } while (1); num--; /* * We note how many files we need to process */ files_to_process = num; /* Got it, now process logs from last to first */ if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else snprintf(filename, len, "%s", config.log_file); do { int ret; if ((ret = process_file(filename))) { free(filename); free_config(&config); return ret; } /* Get next log file */ files_to_process--; /* one less file to process */ num--; if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else if (num == 0) snprintf(filename, len, "%s", config.log_file); else break; } while (1); free(filename); free_config(&config); return 0; } static int process_log_fd(const char *filename) { llist *entries; // entries in a record int ret; int first = 0; event first_event, last_event; last_event.sec = 0; last_event.milli = 0; /* For each record in file */ do { ret = get_record(&entries); if ((ret != 0)||(entries->cnt == 0)) break; // If report is RPT_TIME or RPT_SUMMARY, get if (report_type <= RPT_SUMMARY) { if (first == 0) { list_get_event(entries, &first_event); first = 1; if (very_first_event.sec == 0) list_get_event(entries, &very_first_event); } list_get_event(entries, &last_event); } if (scan(entries)) { // This is the per entry action item if (per_event_processing(entries)) found = 1; } list_clear(entries); free(entries); } while (ret == 0); fclose(log_fd); // This is the per file action items very_last_event.sec = last_event.sec; very_last_event.milli = last_event.milli; if (report_type == RPT_TIME) { if (first == 0) { printf("%s: no records\n", filename); } else { struct tm *btm; char tmp[32]; printf("%s: ", filename); btm = localtime(&first_event.sec); strftime(tmp, sizeof(tmp), "%x %T", btm); printf("%s.%03d - ", tmp, first_event.milli); btm = localtime(&last_event.sec); strftime(tmp, sizeof(tmp), "%x %T", btm); printf("%s.%03d\n", tmp, last_event.milli); } } return 0; } static int process_stdin(void) { log_fd = stdin; return process_log_fd("stdin"); } static int process_file(char *filename) { log_fd = fopen(filename, "rm"); if (log_fd == NULL) { fprintf(stderr, "Error opening %s (%s)\n", filename, strerror(errno)); return 1; } __fsetlocking(log_fd, FSETLOCKING_BYCALLER); return process_log_fd(filename); } /* * This function returns a malloc'd buffer of the next record in the audit * logs. It returns 0 on success, 1 on eof, -1 on error. */ static int get_record(llist **l) { char *rc; char *buff = NULL; *l = get_ready_event(&lo); if (*l) return 0; while (1) { if (!buff) { buff = malloc(MAX_AUDIT_MESSAGE_LENGTH); if (!buff) return -1; } rc = fgets_unlocked(buff, MAX_AUDIT_MESSAGE_LENGTH, log_fd); if (rc) { if (lol_add_record(&lo, buff)) { *l = get_ready_event(&lo); if (*l) break; } } else { free(buff); if (feof_unlocked(log_fd)) { // Only mark all events complete if this is // the last file. if (files_to_process == 0) { terminate_all_events(&lo); } *l = get_ready_event(&lo); if (*l) return 0; else return 1; } else return -1; } } free(buff); return 0; }