From be9fbe3230a298c014ae2e619e5a1116b7f7e0fb Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Sat, 15 May 2021 10:08:33 -0400 Subject: [PATCH] output/syslog: Convert syslog eve output to plugin This commit converts the "built-in" syslog eve output handler into an internal plugin. --- output-eve-syslog.c | 114 ++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 2 + src/output-eve-syslog.c | 120 ++++++++++++++++++++++++++++++++++++++++ src/output-eve-syslog.h | 29 ++++++++++ src/util-logopenfile.c | 9 +-- src/util-logopenfile.h | 2 - src/util-plugin.c | 3 +- src/util-plugin.h | 1 + 8 files changed, 270 insertions(+), 10 deletions(-) create mode 100644 output-eve-syslog.c create mode 100644 src/output-eve-syslog.c create mode 100644 src/output-eve-syslog.h diff --git a/output-eve-syslog.c b/output-eve-syslog.c new file mode 100644 index 0000000000..4c06f8d461 --- /dev/null +++ b/output-eve-syslog.c @@ -0,0 +1,114 @@ +/* vi: set et ts=4: */ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mike Pomraning + * \author Jeff Lucovsky + * + * File-like output for logging: syslog + */ + +#ifndef OS_WIN32 +#include "suricata-plugin.h" /* errno.h, string.h, etc. */ +#include "conf.h" /* ConfNode, etc. */ +#include "output.h" /* DEFAULT_LOG_* */ +#include "output-eve-syslog.h" +#include "util-syslog.h" + +#define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" +#define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 +#define DEFAULT_ALERT_SYSLOG_LEVEL LOG_INFO + +#define OUTPUT_NAME "syslog" + +typedef struct Context_ { + int alert_syslog_level; +} Context; + +static int SyslogInit(ConfNode *conf, bool threaded, void **init_data) +{ + Context *context = SCCalloc(1, sizeof(Context)); + if (context == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate context for %s", OUTPUT_NAME); + return -1; + } + const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); + if (facility_s == NULL) { + facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; + } + + int facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); + if (facility == -1) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "Invalid syslog facility: \"%s\"," + " now using \"%s\" as syslog facility", + facility_s, DEFAULT_ALERT_SYSLOG_FACILITY_STR); + facility = DEFAULT_ALERT_SYSLOG_FACILITY; + } + + const char *level_s = ConfNodeLookupChildValue(conf, "level"); + if (level_s != NULL) { + int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); + if (level != -1) { + context->alert_syslog_level = level; + } + } + + const char *ident = ConfNodeLookupChildValue(conf, "identity"); + /* if null we just pass that to openlog, which will then + * figure it out by itself. */ + + openlog(ident, LOG_PID | LOG_NDELAY, facility); + SCLogNotice("Syslog: facility %s, level %s, ident %s", facility_s, level_s, ident); + *init_data = context; + return 0; +} + +static int SyslogWrite(const char *buffer, int buffer_len, void *init_data, void *thread_data) +{ + Context *context = init_data; + syslog(context->alert_syslog_level, "%s", (const char *)buffer); + + return 0; +} + +static void SyslogDeInit(void *init_data) +{ + if (init_data) { + closelog(); + SCFree(init_data); + } +} + +void SyslogInitialize(void) +{ + SCPluginFileType *plugin_data = SCCalloc(1, sizeof(SCPluginFileType)); + + if (plugin_data == NULL) { + FatalError(SC_ERR_MEM_ALLOC, "Unable to allocate memory for eve output %s", OUTPUT_NAME); + } + + plugin_data->internal = true; + plugin_data->name = OUTPUT_NAME; + plugin_data->Init = SyslogInit; + plugin_data->Deinit = SyslogDeInit; + plugin_data->Write = SyslogWrite; +} +#endif /* !OS_WIN32 */ diff --git a/src/Makefile.am b/src/Makefile.am index a5c1a8714e..b3c86be235 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -410,6 +410,7 @@ noinst_HEADERS = \ output-json-template-rust.h \ output-json-tftp.h \ output-json-tls.h \ + output-eve-syslog.h \ output-lua.h \ output-packet.h \ output-stats.h \ @@ -984,6 +985,7 @@ libsuricata_c_a_SOURCES = \ output-json-template-rust.c \ output-json-tftp.c \ output-json-tls.c \ + output-eve-syslog.c \ output-lua.c \ output-packet.c \ output-stats.c \ diff --git a/src/output-eve-syslog.c b/src/output-eve-syslog.c new file mode 100644 index 0000000000..1501fe0959 --- /dev/null +++ b/src/output-eve-syslog.c @@ -0,0 +1,120 @@ +/* vi: set et ts=4: */ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Mike Pomraning + * \author Jeff Lucovsky + * + * File-like output for logging: syslog + */ + +#include "suricata-common.h" /* errno.h, string.h, etc. */ +#include "output.h" /* DEFAULT_LOG_* */ +#include "output-eve-syslog.h" +#include "util-syslog.h" + +#define DEFAULT_ALERT_SYSLOG_FACILITY_STR "local0" +#define DEFAULT_ALERT_SYSLOG_FACILITY LOG_LOCAL0 +#define DEFAULT_ALERT_SYSLOG_LEVEL LOG_INFO + +#ifdef OS_WIN32 +void SyslogInitialize(void) +{ +} +#else /* !OS_WIN32 */ +#define OUTPUT_NAME "syslog" + +typedef struct Context_ { + int alert_syslog_level; +} Context; + +static int SyslogInit(ConfNode *conf, bool threaded, void **init_data) +{ + Context *context = SCCalloc(1, sizeof(Context)); + if (context == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate context for %s", OUTPUT_NAME); + return -1; + } + const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); + if (facility_s == NULL) { + facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; + } + + int facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); + if (facility == -1) { + SCLogWarning(SC_ERR_INVALID_ARGUMENT, + "Invalid syslog facility: \"%s\"," + " now using \"%s\" as syslog facility", + facility_s, DEFAULT_ALERT_SYSLOG_FACILITY_STR); + facility = DEFAULT_ALERT_SYSLOG_FACILITY; + } + + const char *level_s = ConfNodeLookupChildValue(conf, "level"); + if (level_s != NULL) { + int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); + if (level != -1) { + context->alert_syslog_level = level; + } + } + + const char *ident = ConfNodeLookupChildValue(conf, "identity"); + /* if null we just pass that to openlog, which will then + * figure it out by itself. */ + + openlog(ident, LOG_PID | LOG_NDELAY, facility); + SCLogNotice("Syslog: facility %s, level %s, ident %s", facility_s, level_s, ident); + *init_data = context; + return 0; +} + +static int SyslogWrite(const char *buffer, int buffer_len, void *init_data, void *thread_data) +{ + Context *context = init_data; + syslog(context->alert_syslog_level, "%s", (const char *)buffer); + + return 0; +} + +static void SyslogDeInit(void *init_data) +{ + if (init_data) { + closelog(); + SCFree(init_data); + } +} + +void SyslogInitialize(void) +{ + SCPluginFileType *plugin_data = SCCalloc(1, sizeof(SCPluginFileType)); + + if (plugin_data == NULL) { + FatalError(SC_ERR_MEM_ALLOC, "Unable to allocate memory for eve output %s", OUTPUT_NAME); + } + + plugin_data->internal = true; + plugin_data->name = OUTPUT_NAME; + plugin_data->Init = SyslogInit; + plugin_data->Deinit = SyslogDeInit; + plugin_data->Write = SyslogWrite; + if (!SCRegisterEveFileType(plugin_data)) { + FatalError(SC_ERR_PLUGIN, "Failed to register EVE output: %s", OUTPUT_NAME); + } +} +#endif /* !OS_WIN32 */ diff --git a/src/output-eve-syslog.h b/src/output-eve-syslog.h new file mode 100644 index 0000000000..03d5f3ed80 --- /dev/null +++ b/src/output-eve-syslog.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2021 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Jeff Lucovsky + */ + +#ifndef __OUTPUT_EVE_SYSLOG_H__ +#define __OUTPUT_EVE_SYSLOG_H__ + +void SyslogInitialize(void); + +#endif /* __OUTPUT_EVE_SYSLOG_H__ */ diff --git a/src/util-logopenfile.c b/src/util-logopenfile.c index a68cef887d..c7ef24ff96 100644 --- a/src/util-logopenfile.c +++ b/src/util-logopenfile.c @@ -884,13 +884,8 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx) int LogFileWrite(LogFileCtx *file_ctx, MemBuffer *buffer) { - if (file_ctx->type == LOGFILE_TYPE_SYSLOG) { - syslog(file_ctx->syslog_setup.alert_syslog_level, "%s", - (const char *)MEMBUFFER_BUFFER(buffer)); - } else if (file_ctx->type == LOGFILE_TYPE_FILE || - file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || - file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) - { + if (file_ctx->type == LOGFILE_TYPE_FILE || file_ctx->type == LOGFILE_TYPE_UNIX_DGRAM || + file_ctx->type == LOGFILE_TYPE_UNIX_STREAM) { /* append \n for files only */ MemBufferWriteString(buffer, "\n"); file_ctx->Write((const char *)MEMBUFFER_BUFFER(buffer), diff --git a/src/util-logopenfile.h b/src/util-logopenfile.h index e8b4499607..4cc2a28921 100644 --- a/src/util-logopenfile.h +++ b/src/util-logopenfile.h @@ -35,7 +35,6 @@ enum LogFileType { LOGFILE_TYPE_FILE, - LOGFILE_TYPE_SYSLOG, LOGFILE_TYPE_UNIX_DGRAM, LOGFILE_TYPE_UNIX_STREAM, LOGFILE_TYPE_REDIS, @@ -73,7 +72,6 @@ typedef struct LogFileCtx_ { LogThreadedFileCtx *threads; union { - SyslogSetup syslog_setup; #ifdef HAVE_LIBHIREDIS RedisSetup redis_setup; #endif diff --git a/src/util-plugin.c b/src/util-plugin.c index 0ed9ce225c..7e7eb595b3 100644 --- a/src/util-plugin.c +++ b/src/util-plugin.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Open Information Security Foundation +/* Copyright (C) 2020-2021 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -93,6 +93,7 @@ static void InitPlugin(char *path) */ void SCInternalLoad(void) { + SyslogInitialize(); } void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args) diff --git a/src/util-plugin.h b/src/util-plugin.h index 7415eb68e4..8d87da760e 100644 --- a/src/util-plugin.h +++ b/src/util-plugin.h @@ -19,6 +19,7 @@ #define __UTIL_PLUGIN_H__ #include "suricata-plugin.h" +#include "output-eve-syslog.h" void SCInternalLoad(void); void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args);