/
githubmirror
/
audit-userspace
Обзор
Документация
Войти
/
githubmirror
/
audit-userspace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/aureport.c
405 строк
9 KB
Steve Grubb
tools: safely replace directory log overrides
12 июл 2026, 19:52
12 июл 2026, 19:52
90b7003
Код
Авторство
О чём код?
/* * aureport.c - main file for aureport utility * Copyright 2005-08, 2010,11,2013,2020 Red Hat * 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 <sgrubb@redhat.com> */ #include "config.h" #include <stdio.h> #include <stdio_ext.h> #include <string.h> #include <stdlib.h> #include <getopt.h> #include <unistd.h> #include <ctype.h> #include <time.h> #include <errno.h> #include <sys/resource.h> #include <sys/stat.h> #include <locale.h> #include <sys/param.h> #include "libaudit.h" #include "auditd-config.h" #include "aureport-options.h" #include "aureport-scan.h" #include "ausearch-lol.h" #include "ausearch-lookup.h" #include "auparse-idata.h" #include "ausearch-parse.h" #include "common.h" extern event very_first_event; event very_last_event; static auparse_state_t *au = NULL; 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 struct daemon_conf config; 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_event(llist **); extern char *user_file; extern int force_logs; /* * User space configuration items */ extern time_t arg_eoe_timeout; 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); set_allow_links(1); // auditd might have -l flag, aureport should be lenient here (void) umask( umask( 077 ) | 027 ); very_first_event.sec = 0; au = auparse_init(AUSOURCE_BUFFER, ""); if (au == NULL) { fprintf(stderr, "cannot init parser\n"); return 1; } reset_counters(); /* Load config so we know where logs are and eoe_timeout */ if (load_config(&config, TEST_SEARCH)) fprintf(stderr, "NOTE - using built-in logs: %s\n", config.log_file); /* Set timeout from the config file */ lol_set_eoe_timeout((time_t)config.end_of_event_timeout); /* * If an override was specified on the command line, override the config */ if (arg_eoe_timeout != 0) lol_set_eoe_timeout((time_t)arg_eoe_timeout); print_title(); if (arg_eoe_timeout != 0) { lol_set_eoe_timeout(arg_eoe_timeout); } 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("<no events of interest were found>\n\n"); destroy_counters(); aulookup_destroy_uid_list(); return 1; } else print_wrap_up(); destroy_counters(); aulookup_destroy_uid_list(); lookup_uid_destroy_list(); free(user_file); return 0; } static int process_logs(void) { struct audit_log_info *logs = NULL; char *filename; size_t len; size_t log_cnt = 0; if (user_file && userfile_is_dir) { char dirname[MAXPATHLEN+1]; char *new_log_file; strncpy(dirname, user_file, MAXPATHLEN-32); dirname[MAXPATHLEN-32] = '\0'; if (dirname[strlen(dirname)-1] != '/') strcat(dirname, "/"); strcat (dirname, "audit.log"); /* Keep loaded configuration allocations until the new path exists. */ new_log_file = strdup(dirname); if (new_log_file == NULL) { fprintf(stderr, "No memory\n"); free_config(&config); return 1; } /* Only the log path is overridden for a directory input. */ free((void *)config.log_file); config.log_file = new_log_file; fprintf(stderr, "NOTE - using logs in %s\n", config.log_file); } len = strlen(config.log_file) + 16; filename = malloc(len); if (!filename) { fprintf(stderr, "No memory\n"); free_config(&config); return 1; } /* Count the logs */ if (audit_log_list(config.log_file, &logs, &log_cnt)) { fprintf(stderr, "No memory\n"); free(filename); free_config(&config); return 1; } if (log_cnt == 0) { snprintf(filename, len, "%s", config.log_file); int ret = process_file(filename); audit_log_free(logs, log_cnt); free(filename); free_config(&config); return ret; } /* Locate the starting file that is in range */ files_to_process = audit_log_find_start(logs, log_cnt, start_time); audit_log_free(logs, log_cnt); /* Got it, now process logs from last to first */ if (files_to_process > 0) snprintf(filename, len, "%s.%d", config.log_file, files_to_process); else snprintf(filename, len, "%s", config.log_file); do { int ret; if ((ret = process_file(filename))) { free(filename); free_config(&config); return ret; } if (files_to_process == 0) break; /* Get next log file */ files_to_process--; if (files_to_process > 0) snprintf(filename, len, "%s.%d", config.log_file, files_to_process); else snprintf(filename, len, "%s", config.log_file); } while (1); free(filename); free_config(&config); return 0; } static void process_event(llist *entries) { if (scan(entries)) { // If its a single event or SYSCALL load interpretations if ((entries->cnt == 1) || (entries->head->type == AUDIT_SYSCALL)) { _auparse_load_interpretations(au, entries->head->interp); } // This is the per entry action item if (per_event_processing(entries)) found = 1; _auparse_free_interpretations(au); } } 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 event in file */ do { ret = get_event(&entries); if ((ret != 0)||(entries->cnt == 0)||(entries->head == NULL)) 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; } list_get_event(entries, &last_event); } // Are we within time range? if (start_time == 0 || entries->e.sec >= start_time) { if (end_time == 0 || entries->e.sec <= end_time) { process_event(entries); } } 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); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u - ", tmp, first_event.milli); btm = localtime(&last_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u\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 linked list of all records in an event. * It returns 0 on success, 1 on eof, -1 on error. */ static int get_event(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; }