/
githubmirror
/
audit-userspace
Обзор
Документация
Войти
/
githubmirror
/
audit-userspace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
audisp/plugins/syslog/audisp-syslog.c
307 строк
8 KB
Steve Grubb
auplugin-fgets: handle read errors at call sites
19 июл 2026, 19:47
19 июл 2026, 19:47
7481ad5
Код
Авторство
О чём код?
/* audisp-syslog.c -- * Copyright 2018 Red Hat Inc. * 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 <signal.h> #include <string.h> #include <sys/select.h> #include <errno.h> #include <syslog.h> #include <stdlib.h> #ifdef HAVE_LIBCAP_NG #include <cap-ng.h> #endif #include "libaudit.h" #include "auplugin.h" #include "auparse.h" /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static int priority; static int interpret = 0; /* * SIGTERM handler * * Only honor the signal if it comes from the parent process so that other * tasks (cough, systemctl, cough) can't make the plugin exit without * the dispatcher in agreement. Otherwise it will restart the plugin. */ static void term_handler(int sig, siginfo_t *info, void *ucontext) { if (info && info->si_pid != getppid()) return; stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler( int sig ) { hup = 1; } static void reload_config(void) { hup = 0; } static int init_syslog(int argc, const char *argv[]) { int i, facility = LOG_USER; priority = LOG_INFO; for (i = 1; i < argc; i++) { if (argv[i]) { if (strcasecmp(argv[i], "LOG_DEBUG") == 0) priority = LOG_DEBUG; else if (strcasecmp(argv[i], "LOG_INFO") == 0) priority = LOG_INFO; else if (strcasecmp(argv[i], "LOG_NOTICE") == 0) priority = LOG_NOTICE; else if (strcasecmp(argv[i], "LOG_WARNING") == 0) priority = LOG_WARNING; else if (strcasecmp(argv[i], "LOG_ERR") == 0) priority = LOG_ERR; else if (strcasecmp(argv[i], "LOG_CRIT") == 0) priority = LOG_CRIT; else if (strcasecmp(argv[i], "LOG_ALERT") == 0) priority = LOG_ALERT; else if (strcasecmp(argv[i], "LOG_EMERG") == 0) priority = LOG_EMERG; else if (strcasecmp(argv[i], "LOG_LOCAL0") == 0) facility = LOG_LOCAL0; else if (strcasecmp(argv[i], "LOG_LOCAL1") == 0) facility = LOG_LOCAL1; else if (strcasecmp(argv[i], "LOG_LOCAL2") == 0) facility = LOG_LOCAL2; else if (strcasecmp(argv[i], "LOG_LOCAL3") == 0) facility = LOG_LOCAL3; else if (strcasecmp(argv[i], "LOG_LOCAL4") == 0) facility = LOG_LOCAL4; else if (strcasecmp(argv[i], "LOG_LOCAL5") == 0) facility = LOG_LOCAL5; else if (strcasecmp(argv[i], "LOG_LOCAL6") == 0) facility = LOG_LOCAL6; else if (strcasecmp(argv[i], "LOG_LOCAL7") == 0) facility = LOG_LOCAL7; else if (strcasecmp(argv[i], "LOG_AUTH") == 0) facility = LOG_AUTH; else if (strcasecmp(argv[i], "LOG_AUTHPRIV") == 0) facility = LOG_AUTHPRIV; else if (strcasecmp(argv[i], "LOG_DAEMON") == 0) facility = LOG_DAEMON; else if (strcasecmp(argv[i], "LOG_SYSLOG") == 0) facility = LOG_SYSLOG; else if (strcasecmp(argv[i], "LOG_USER") == 0) facility = LOG_USER; else if (strcasecmp(argv[i], "interpret") == 0) interpret = 1; else { syslog(LOG_ERR, "Unknown log priority/facility %s", argv[i]); return 1; } } } syslog(LOG_INFO, "syslog plugin initialized with facility %d and priority %d", facility, priority); if (facility != LOG_USER) openlog("audispd", 0, facility); return 0; } static char *record = NULL; /* * Append text to an interpreted record without exceeding its allocation. * Returns 0 on success and 1 when the complete text does not fit. */ static int append_text(char **cursor, size_t *remaining, const char *text) { size_t length = strlen(text); if (length >= *remaining) return 1; memcpy(*cursor, text, length); *cursor += length; *remaining -= length; **cursor = '\0'; return 0; } static inline void write_syslog(char *s) { if (interpret) { int rc, header = 0; char *mptr, tbuf[64]; size_t remaining; // Setup record buffer if (record == NULL) record = malloc(MAX_AUDIT_MESSAGE_LENGTH); if (record == NULL) return; auparse_state_t *au = auparse_init(AUSOURCE_BUFFER, s); if (au == NULL) return; rc = auparse_first_record(au); // AUDIT_EOE has no fields - drop it if (auparse_get_num_fields(au) == 0) { auparse_destroy(au); return; } // Now iterate over the fields and print each one mptr = record; remaining = MAX_AUDIT_MESSAGE_LENGTH; *mptr = '\0'; while (rc > 0) { int ftype = auparse_get_field_type(au); const char *fname = auparse_get_field_name(au); const char *fval; switch (ftype) { case AUPARSE_TYPE_ESCAPED_FILE: fval = auparse_interpret_realpath(au); break; case AUPARSE_TYPE_SOCKADDR: fval = auparse_interpret_sock_address(au); if (fval == NULL) fval = auparse_interpret_sock_family(au); break; default: fval = auparse_interpret_field(au); break; } if (append_text(&mptr, &remaining, fname ? fname : "?") || append_text(&mptr, &remaining, "=") || append_text(&mptr, &remaining, fval ? fval : "?") || append_text(&mptr, &remaining, " ")) break; rc = auparse_next_field(au); if (!header && fname && strcmp(fname, "type") == 0) { if (append_text(&mptr, &remaining, "msg=audit(")) break; time_t t = auparse_get_time(au); struct tm *tv = localtime(&t); if (tv) strftime(tbuf, sizeof(tbuf), "%x %T", tv); else strcpy(tbuf, "?"); if (append_text(&mptr, &remaining, tbuf) || append_text(&mptr, &remaining, ") : ")) break; header = 1; } } // Record is complete, dump it to syslog syslog(priority, "%s", record); auparse_destroy(au); } else { char *c = strchr(s, AUDIT_INTERP_SEPARATOR); if (c) *c = ' '; syslog(priority, "%s", s); } } int main(int argc, const char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; struct sigaction sa; if (init_syslog(argc, argv)) return 1; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_sigaction = term_handler; sa.sa_flags = SA_SIGINFO; sigaction(SIGTERM, &sa, NULL); #ifdef HAVE_LIBCAP_NG // Drop capabilities capng_clear(CAPNG_SELECT_BOTH); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "audisp-syslog plugin was unable to drop capabilities, continuing with elevated priviles"); #endif do { fd_set read_mask; int retval = -1; /* Load configuration */ if (hup) { reload_config(); } do { FD_ZERO(&read_mask); FD_SET(0, &read_mask); retval= select(1, &read_mask, NULL, NULL, NULL); } while (retval == -1 && errno == EINTR && !hup && !stop); /* Now the event loop */ if (!stop && !hup && retval > 0) { if (FD_ISSET(0, &read_mask)) { do { int read_rc; read_rc = auplugin_fgets(tmp, MAX_AUDIT_MESSAGE_LENGTH, 0); /* A read error leaves buffer and EOF unchanged. */ if (read_rc < 0) { syslog(LOG_ERR, "auplugin_fgets failed: %m"); stop = 1; break; } if (read_rc > 0) write_syslog(tmp); } while (auplugin_fgets_more( MAX_AUDIT_MESSAGE_LENGTH)); } } if (auplugin_fgets_eof()) break; } while (stop == 0); free(record); return 0; }