summaryrefslogtreecommitdiffstats
path: root/src/util-plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util-plugin.c')
-rw-r--r--src/util-plugin.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/util-plugin.c b/src/util-plugin.c
new file mode 100644
index 0000000..3a08aa8
--- /dev/null
+++ b/src/util-plugin.c
@@ -0,0 +1,214 @@
+/* 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
+ * 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.
+ */
+
+#include "suricata-common.h"
+#include "suricata-plugin.h"
+#include "suricata.h"
+#include "runmodes.h"
+#include "output-eve-syslog.h"
+#include "util-plugin.h"
+#include "util-debug.h"
+
+#ifdef HAVE_PLUGINS
+
+#include <dlfcn.h>
+
+typedef struct PluginListNode_ {
+ SCPlugin *plugin;
+ void *lib;
+ TAILQ_ENTRY(PluginListNode_) entries;
+} PluginListNode;
+
+/**
+ * The list of loaded plugins.
+ *
+ * Currently only used as a place to stash the pointer returned from
+ * dlopen, but could have other uses, such as a plugin unload destructor.
+ */
+static TAILQ_HEAD(, PluginListNode_) plugins = TAILQ_HEAD_INITIALIZER(plugins);
+
+static TAILQ_HEAD(, SCEveFileType_) output_types = TAILQ_HEAD_INITIALIZER(output_types);
+
+static TAILQ_HEAD(, SCCapturePlugin_) capture_plugins = TAILQ_HEAD_INITIALIZER(capture_plugins);
+
+bool RegisterPlugin(SCPlugin *plugin, void *lib)
+{
+ BUG_ON(plugin->name == NULL);
+ BUG_ON(plugin->author == NULL);
+ BUG_ON(plugin->license == NULL);
+ BUG_ON(plugin->Init == NULL);
+
+ PluginListNode *node = SCCalloc(1, sizeof(*node));
+ if (node == NULL) {
+ SCLogError("Failed to allocate memory for plugin");
+ return false;
+ }
+ node->plugin = plugin;
+ node->lib = lib;
+ TAILQ_INSERT_TAIL(&plugins, node, entries);
+ SCLogNotice("Initializing plugin %s; author=%s; license=%s", plugin->name, plugin->author,
+ plugin->license);
+ (*plugin->Init)();
+ return true;
+}
+
+static void InitPlugin(char *path)
+{
+ void *lib = dlopen(path, RTLD_NOW);
+ if (lib == NULL) {
+ SCLogNotice("Failed to open %s as a plugin: %s", path, dlerror());
+ } else {
+ SCLogNotice("Loading plugin %s", path);
+
+ SCPluginRegisterFunc plugin_register = dlsym(lib, "SCPluginRegister");
+ if (plugin_register == NULL) {
+ SCLogError("Plugin does not export SCPluginRegister function: %s", path);
+ dlclose(lib);
+ return;
+ }
+
+ if (!RegisterPlugin(plugin_register(), lib)) {
+ SCLogError("Plugin registration failed: %s", path);
+ dlclose(lib);
+ return;
+ }
+ }
+}
+
+void SCPluginsLoad(const char *capture_plugin_name, const char *capture_plugin_args)
+{
+ ConfNode *conf = ConfGetNode("plugins");
+ if (conf == NULL) {
+ return;
+ }
+ ConfNode *plugin = NULL;
+ TAILQ_FOREACH(plugin, &conf->head, next) {
+ struct stat statbuf;
+ if (stat(plugin->val, &statbuf) == -1) {
+ SCLogError("Bad plugin path: %s: %s", plugin->val, strerror(errno));
+ continue;
+ }
+ if (S_ISDIR(statbuf.st_mode)) {
+ // coverity[toctou : FALSE]
+ DIR *dir = opendir(plugin->val);
+ if (dir == NULL) {
+ SCLogError("Failed to open plugin directory %s: %s", plugin->val, strerror(errno));
+ continue;
+ }
+ struct dirent *entry = NULL;
+ char path[PATH_MAX];
+ while ((entry = readdir(dir)) != NULL) {
+ if (strstr(entry->d_name, ".so") != NULL) {
+ snprintf(path, sizeof(path), "%s/%s", plugin->val, entry->d_name);
+ InitPlugin(path);
+ }
+ }
+ closedir(dir);
+ } else {
+ InitPlugin(plugin->val);
+ }
+ }
+
+ if (run_mode == RUNMODE_PLUGIN) {
+ SCCapturePlugin *capture = SCPluginFindCaptureByName(capture_plugin_name);
+ if (capture == NULL) {
+ FatalError("No capture plugin found with name %s", capture_plugin_name);
+ }
+ capture->Init(capture_plugin_args, RUNMODE_PLUGIN, TMM_RECEIVEPLUGIN,
+ TMM_DECODEPLUGIN);
+ }
+}
+
+static bool IsBuiltinTypeName(const char *name)
+{
+ const char *builtin[] = {
+ "regular",
+ "unix_dgram",
+ "unix_stream",
+ "redis",
+ NULL,
+ };
+ for (int i = 0;; i++) {
+ if (builtin[i] == NULL) {
+ break;
+ }
+ if (strcmp(builtin[i], name) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * \brief Register an Eve file type.
+ *
+ * \retval true if registered successfully, false if the file type name
+ * conflicts with a built-in or previously registered
+ * file type.
+ */
+bool SCRegisterEveFileType(SCEveFileType *plugin)
+{
+ /* First check that the name doesn't conflict with a built-in filetype. */
+ if (IsBuiltinTypeName(plugin->name)) {
+ SCLogError("Eve file type name conflicts with built-in type: %s", plugin->name);
+ return false;
+ }
+
+ /* Now check against previously registered file types. */
+ SCEveFileType *existing = NULL;
+ TAILQ_FOREACH (existing, &output_types, entries) {
+ if (strcmp(existing->name, plugin->name) == 0) {
+ SCLogError("Eve file type name conflicts with previously registered type: %s",
+ plugin->name);
+ return false;
+ }
+ }
+
+ SCLogDebug("Registering EVE file type plugin %s", plugin->name);
+ TAILQ_INSERT_TAIL(&output_types, plugin, entries);
+ return true;
+}
+
+SCEveFileType *SCPluginFindFileType(const char *name)
+{
+ SCEveFileType *plugin = NULL;
+ TAILQ_FOREACH(plugin, &output_types, entries) {
+ if (strcmp(name, plugin->name) == 0) {
+ return plugin;
+ }
+ }
+ return NULL;
+}
+
+int SCPluginRegisterCapture(SCCapturePlugin *plugin)
+{
+ TAILQ_INSERT_TAIL(&capture_plugins, plugin, entries);
+ SCLogNotice("Capture plugin registered: %s", plugin->name);
+ return 0;
+}
+
+SCCapturePlugin *SCPluginFindCaptureByName(const char *name)
+{
+ SCCapturePlugin *plugin = NULL;
+ TAILQ_FOREACH(plugin, &capture_plugins, entries) {
+ if (strcmp(name, plugin->name) == 0) {
+ return plugin;
+ }
+ }
+ return plugin;
+}
+#endif