aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/unix-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/unix-manager.c')
-rw-r--r--framework/src/suricata/src/unix-manager.c1030
1 files changed, 0 insertions, 1030 deletions
diff --git a/framework/src/suricata/src/unix-manager.c b/framework/src/suricata/src/unix-manager.c
deleted file mode 100644
index 9357f4c5..00000000
--- a/framework/src/suricata/src/unix-manager.c
+++ /dev/null
@@ -1,1030 +0,0 @@
-/* Copyright (C) 2013 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 Eric Leblond <eric@regit.org>
- */
-
-#include "suricata-common.h"
-#include "suricata.h"
-#include "unix-manager.h"
-#include "detect-engine.h"
-#include "tm-threads.h"
-#include "runmodes.h"
-#include "conf.h"
-
-#include "util-privs.h"
-#include "util-debug.h"
-#include "util-signal.h"
-
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#ifdef BUILD_UNIX_SOCKET
-#include <jansson.h>
-
-// MSG_NOSIGNAL does not exists on OS X
-#ifdef OS_DARWIN
-# ifndef MSG_NOSIGNAL
-# define MSG_NOSIGNAL SO_NOSIGPIPE
-# endif
-#endif
-
-#define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
-#define SOCKET_FILENAME "suricata-command.socket"
-#define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
-
-typedef struct Command_ {
- char *name;
- TmEcode (*Func)(json_t *, json_t *, void *);
- void *data;
- int flags;
- TAILQ_ENTRY(Command_) next;
-} Command;
-
-typedef struct Task_ {
- TmEcode (*Func)(void *);
- void *data;
- TAILQ_ENTRY(Task_) next;
-} Task;
-
-typedef struct UnixClient_ {
- int fd;
- TAILQ_ENTRY(UnixClient_) next;
-} UnixClient;
-
-typedef struct UnixCommand_ {
- time_t start_timestamp;
- int socket;
- struct sockaddr_un client_addr;
- int select_max;
- TAILQ_HEAD(, Command_) commands;
- TAILQ_HEAD(, Task_) tasks;
- TAILQ_HEAD(, UnixClient_) clients;
-} UnixCommand;
-
-/**
- * \brief Create a command unix socket on system
- *
- * \retval 0 in case of error, 1 in case of success
- */
-int UnixNew(UnixCommand * this)
-{
- struct sockaddr_un addr;
- int len;
- int ret;
- int on = 1;
- char *sockettarget = NULL;
- char *socketname;
-
- this->start_timestamp = time(NULL);
- this->socket = -1;
- this->select_max = 0;
-
- TAILQ_INIT(&this->commands);
- TAILQ_INIT(&this->tasks);
- TAILQ_INIT(&this->clients);
-
- if (ConfGet("unix-command.filename", &socketname) == 1) {
- if (PathIsAbsolute(socketname)) {
- sockettarget = SCStrdup(socketname);
- if (unlikely(sockettarget == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name");
- return 0;
- }
- } else {
- int socketlen = strlen(SOCKET_PATH) + strlen(socketname) + 2;
- sockettarget = SCMalloc(socketlen);
- if (unlikely(sockettarget == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name");
- return 0;
- }
- snprintf(sockettarget, socketlen, "%s/%s", SOCKET_PATH, socketname);
-
- /* Create socket dir */
- ret = mkdir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
- if ( ret != 0 ) {
- int err = errno;
- if (err != EEXIST) {
- SCFree(sockettarget);
- SCLogError(SC_ERR_OPENING_FILE,
- "Cannot create socket directory %s: %s", SOCKET_PATH, strerror(err));
- return 0;
- }
- }
-
- }
- SCLogInfo("Using unix socket file '%s'", sockettarget);
- }
- if (sockettarget == NULL) {
- sockettarget = SCStrdup(SOCKET_TARGET);
- if (unlikely(sockettarget == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate socket name");
- return 0;
- }
- }
-
- /* Remove socket file */
- (void) unlink(sockettarget);
-
- /* set address */
- addr.sun_family = AF_UNIX;
- strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path));
- addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
- len = strlen(addr.sun_path) + sizeof(addr.sun_family);
-
- /* create socket */
- this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (this->socket == -1) {
- SCLogWarning(SC_ERR_OPENING_FILE,
- "Unix Socket: unable to create UNIX socket %s: %s",
- addr.sun_path, strerror(errno));
- SCFree(sockettarget);
- return 0;
- }
- this->select_max = this->socket + 1;
-
- /* Set file mode: will not fully work on most system, the group
- * permission is not changed on some Linux and *BSD won't do the
- * chmod. */
- ret = fchmod(this->socket, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
- if (ret == -1) {
- int err = errno;
- SCLogWarning(SC_ERR_INITIALIZATION,
- "Unable to change permission on socket: %s (%d)",
- strerror(err),
- err);
- }
- /* set reuse option */
- ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
- (char *) &on, sizeof(on));
- if ( ret != 0 ) {
- SCLogWarning(SC_ERR_INITIALIZATION,
- "Cannot set sockets options: %s.", strerror(errno));
- }
-
- /* bind socket */
- ret = bind(this->socket, (struct sockaddr *) &addr, len);
- if (ret == -1) {
- SCLogWarning(SC_ERR_INITIALIZATION,
- "Unix socket: UNIX socket bind(%s) error: %s",
- sockettarget, strerror(errno));
- SCFree(sockettarget);
- return 0;
- }
-
- /* listen */
- if (listen(this->socket, 1) == -1) {
- SCLogWarning(SC_ERR_INITIALIZATION,
- "Command server: UNIX socket listen() error: %s",
- strerror(errno));
- SCFree(sockettarget);
- return 0;
- }
- SCFree(sockettarget);
- return 1;
-}
-
-void UnixCommandSetMaxFD(UnixCommand *this)
-{
- UnixClient *item;
-
- if (this == NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "Unix command is NULL, warn devel");
- return;
- }
-
- this->select_max = this->socket + 1;
- TAILQ_FOREACH(item, &this->clients, next) {
- if (item->fd >= this->select_max) {
- this->select_max = item->fd + 1;
- }
- }
-}
-
-/**
- * \brief Close the unix socket
- */
-void UnixCommandClose(UnixCommand *this, int fd)
-{
- UnixClient *item;
- int found = 0;
-
- TAILQ_FOREACH(item, &this->clients, next) {
- if (item->fd == fd) {
- found = 1;
- break;
- }
- }
-
- if (found == 0) {
- SCLogError(SC_ERR_INVALID_VALUE, "No fd found in client list");
- return;
- }
-
- TAILQ_REMOVE(&this->clients, item, next);
-
- close(item->fd);
- UnixCommandSetMaxFD(this);
- SCFree(item);
-}
-
-/**
- * \brief Callback function used to send message to socket
- */
-int UnixCommandSendCallback(const char *buffer, size_t size, void *data)
-{
- int fd = *(int *) data;
-
- if (send(fd, buffer, size, MSG_NOSIGNAL) == -1) {
- SCLogInfo("Unable to send block: %s", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-#define UNIX_PROTO_VERSION_LENGTH 200
-#define UNIX_PROTO_VERSION "0.1"
-
-/**
- * \brief Accept a new client on unix socket
- *
- * The function is called when a new user is detected
- * in UnixMain(). It does the initial protocol negotiation
- * with client.
- *
- * \retval 0 in case of error, 1 in case of success
- */
-int UnixCommandAccept(UnixCommand *this)
-{
- char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
- json_t *client_msg;
- json_t *server_msg;
- json_t *version;
- json_error_t jerror;
- int client;
- int ret;
- UnixClient *uclient = NULL;
-
- /* accept client socket */
- socklen_t len = sizeof(this->client_addr);
- client = accept(this->socket, (struct sockaddr *) &this->client_addr,
- &len);
- if (client < 0) {
- SCLogInfo("Unix socket: accept() error: %s",
- strerror(errno));
- return 0;
- }
- SCLogDebug("Unix socket: client connection");
-
- /* read client version */
- buffer[sizeof(buffer)-1] = 0;
- ret = recv(client, buffer, sizeof(buffer)-1, 0);
- if (ret < 0) {
- SCLogInfo("Command server: client doesn't send version");
- close(client);
- return 0;
- }
- if (ret >= (int)(sizeof(buffer)-1)) {
- SCLogInfo("Command server: client message is too long, "
- "disconnect him.");
- close(client);
- return 0;
- }
- buffer[ret] = 0;
-
- client_msg = json_loads(buffer, 0, &jerror);
- if (client_msg == NULL) {
- SCLogInfo("Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
- close(client);
- return 0;
- }
-
- version = json_object_get(client_msg, "version");
- if (!json_is_string(version)) {
- SCLogInfo("error: version is not a string");
- close(client);
- json_decref(client_msg);
- return 0;
- }
-
- /* check client version */
- if (strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0) {
- SCLogInfo("Unix socket: invalid client version: \"%s\"",
- json_string_value(version));
- json_decref(client_msg);
- close(client);
- return 0;
- } else {
- SCLogInfo("Unix socket: client version: \"%s\"",
- json_string_value(version));
- }
-
- json_decref(client_msg);
- /* send answer */
- server_msg = json_object();
- if (server_msg == NULL) {
- close(client);
- return 0;
- }
- json_object_set_new(server_msg, "return", json_string("OK"));
-
- if (json_dump_callback(server_msg, UnixCommandSendCallback, &client, 0) == -1) {
- SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
- json_decref(server_msg);
- close(client);
- return 0;
- }
- json_decref(server_msg);
-
- /* client connected */
- SCLogDebug("Unix socket: client connected");
-
- uclient = SCMalloc(sizeof(UnixClient));
- if (unlikely(uclient == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new cient");
- return 0;
- }
- uclient->fd = client;
- TAILQ_INSERT_TAIL(&this->clients, uclient, next);
- UnixCommandSetMaxFD(this);
- return 1;
-}
-
-int UnixCommandBackgroundTasks(UnixCommand* this)
-{
- int ret = 1;
- Task *ltask;
-
- TAILQ_FOREACH(ltask, &this->tasks, next) {
- int fret = ltask->Func(ltask->data);
- if (fret != TM_ECODE_OK) {
- ret = 0;
- }
- }
- return ret;
-}
-
-/**
- * \brief Command dispatcher
- *
- * \param this a UnixCommand:: structure
- * \param command a string containing a json formatted
- * command
- *
- * \retval 0 in case of error, 1 in case of success
- */
-int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client)
-{
- int ret = 1;
- json_error_t error;
- json_t *jsoncmd = NULL;
- json_t *cmd = NULL;
- json_t *server_msg = json_object();
- const char * value;
- int found = 0;
- Command *lcmd;
-
- if (server_msg == NULL) {
- return 0;
- }
-
- jsoncmd = json_loads(command, 0, &error);
- if (jsoncmd == NULL) {
- SCLogInfo("Invalid command, error on line %d: %s\n", error.line, error.text);
- goto error;
- }
-
- cmd = json_object_get(jsoncmd, "command");
- if(!json_is_string(cmd)) {
- SCLogInfo("error: command is not a string");
- goto error_cmd;
- }
- value = json_string_value(cmd);
-
- TAILQ_FOREACH(lcmd, &this->commands, next) {
- if (!strcmp(value, lcmd->name)) {
- int fret = TM_ECODE_OK;
- found = 1;
- if (lcmd->flags & UNIX_CMD_TAKE_ARGS) {
- cmd = json_object_get(jsoncmd, "arguments");
- if(!json_is_object(cmd)) {
- SCLogInfo("error: argument is not an object");
- goto error_cmd;
- }
- }
- fret = lcmd->Func(cmd, server_msg, lcmd->data);
- if (fret != TM_ECODE_OK) {
- ret = 0;
- }
- break;
- }
- }
-
- if (found == 0) {
- json_object_set_new(server_msg, "message", json_string("Unknown command"));
- ret = 0;
- }
-
- switch (ret) {
- case 0:
- json_object_set_new(server_msg, "return", json_string("NOK"));
- break;
- case 1:
- json_object_set_new(server_msg, "return", json_string("OK"));
- break;
- }
-
- /* send answer */
- if (json_dump_callback(server_msg, UnixCommandSendCallback, &client->fd, 0) == -1) {
- SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
- goto error_cmd;
- }
-
- json_decref(jsoncmd);
- json_decref(server_msg);
- return ret;
-
-error_cmd:
- json_decref(jsoncmd);
-error:
- json_decref(server_msg);
- UnixCommandClose(this, client->fd);
- return 0;
-}
-
-void UnixCommandRun(UnixCommand * this, UnixClient *client)
-{
- char buffer[4096];
- int ret;
- ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
- if (ret <= 0) {
- if (ret == 0) {
- SCLogDebug("Unix socket: lost connection with client");
- } else {
- SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
- strerror(errno));
- }
- UnixCommandClose(this, client->fd);
- return;
- }
- if (ret >= (int)(sizeof(buffer)-1)) {
- SCLogInfo("Command server: client command is too long, "
- "disconnect him.");
- UnixCommandClose(this, client->fd);
- }
- buffer[ret] = 0;
- UnixCommandExecute(this, buffer, client);
-}
-
-/**
- * \brief Select function
- *
- * \retval 0 in case of error, 1 in case of success
- */
-int UnixMain(UnixCommand * this)
-{
- struct timeval tv;
- int ret;
- fd_set select_set;
- UnixClient *uclient;
- UnixClient *tclient;
-
- /* Wait activity on the socket */
- FD_ZERO(&select_set);
- FD_SET(this->socket, &select_set);
- TAILQ_FOREACH(uclient, &this->clients, next) {
- FD_SET(uclient->fd, &select_set);
- }
-
- tv.tv_sec = 0;
- tv.tv_usec = 200 * 1000;
- ret = select(this->select_max, &select_set, NULL, NULL, &tv);
-
- /* catch select() error */
- if (ret == -1) {
- /* Signal was caught: just ignore it */
- if (errno == EINTR) {
- return 1;
- }
- SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno));
- return 0;
- }
-
- if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
- return 1;
- }
-
- /* timeout: continue */
- if (ret == 0) {
- return 1;
- }
-
- TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
- if (FD_ISSET(uclient->fd, &select_set)) {
- UnixCommandRun(this, uclient);
- }
- }
- if (FD_ISSET(this->socket, &select_set)) {
- if (!UnixCommandAccept(this))
- return 1;
- }
-
- return 1;
-}
-
-/**
- * \brief Used to kill unix manager thread(s).
- *
- * \todo Kinda hackish since it uses the tv name to identify unix manager
- * thread. We need an all weather identification scheme.
- */
-void UnixKillUnixManagerThread(void)
-{
- ThreadVars *tv = NULL;
- int cnt = 0;
-
- SCCtrlCondSignal(&unix_manager_ctrl_cond);
-
- SCMutexLock(&tv_root_lock);
-
- /* flow manager thread(s) is/are a part of mgmt threads */
- tv = tv_root[TVT_CMD];
-
- while (tv != NULL) {
- if (strcasecmp(tv->name, "UnixManagerThread") == 0) {
- TmThreadsSetFlag(tv, THV_KILL);
- TmThreadsSetFlag(tv, THV_DEINIT);
-
- /* be sure it has shut down */
- while (!TmThreadsCheckFlag(tv, THV_CLOSED)) {
- usleep(100);
- }
- cnt++;
- }
- tv = tv->next;
- }
-
- /* not possible, unless someone decides to rename UnixManagerThread */
- if (cnt == 0) {
- SCMutexUnlock(&tv_root_lock);
- abort();
- }
-
- SCMutexUnlock(&tv_root_lock);
- return;
-}
-
-
-TmEcode UnixManagerShutdownCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- json_object_set_new(server_msg, "message", json_string("Closing Suricata"));
- EngineStop();
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerVersionCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- json_object_set_new(server_msg, "message", json_string(
-#ifdef REVISION
- PROG_VER xstr(REVISION)
-#elif defined RELEASE
- PROG_VER " RELEASE"
-#else
- PROG_VER
-#endif
- ));
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerUptimeCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- int uptime;
- UnixCommand *ucmd = (UnixCommand *)data;
-
- uptime = time(NULL) - ucmd->start_timestamp;
- json_object_set_new(server_msg, "message", json_integer(uptime));
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerRunningModeCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- json_object_set_new(server_msg, "message", json_string(RunmodeGetActive()));
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode()));
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data)
-{
- SCEnter();
- DetectEngineReloadStart();
-
- while (DetectEngineReloadIsDone() == 0)
- usleep(100);
-
- json_object_set_new(server_msg, "message", json_string("done"));
- SCReturnInt(TM_ECODE_OK);
-}
-
-TmEcode UnixManagerConfGetCommand(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
-
- char *confval = NULL;
- char *variable = NULL;
-
- json_t *jarg = json_object_get(cmd, "variable");
- if(!json_is_string(jarg)) {
- SCLogInfo("error: variable is not a string");
- json_object_set_new(server_msg, "message", json_string("variable is not a string"));
- SCReturnInt(TM_ECODE_FAILED);
- }
-
- variable = (char *)json_string_value(jarg);
- if (ConfGet(variable, &confval) != 1) {
- json_object_set_new(server_msg, "message", json_string("Unable to get value"));
- SCReturnInt(TM_ECODE_FAILED);
- }
-
- if (confval) {
- json_object_set_new(server_msg, "message", json_string(confval));
- SCReturnInt(TM_ECODE_OK);
- }
-
- json_object_set_new(server_msg, "message", json_string("No string value"));
- SCReturnInt(TM_ECODE_FAILED);
-}
-
-TmEcode UnixManagerListCommand(json_t *cmd,
- json_t *answer, void *data)
-{
- SCEnter();
- json_t *jdata;
- json_t *jarray;
- Command *lcmd = NULL;
- UnixCommand *gcmd = (UnixCommand *) data;
- int i = 0;
-
- jdata = json_object();
- if (jdata == NULL) {
- json_object_set_new(answer, "message",
- json_string("internal error at json object creation"));
- return TM_ECODE_FAILED;
- }
- jarray = json_array();
- if (jarray == NULL) {
- json_object_set_new(answer, "message",
- json_string("internal error at json object creation"));
- return TM_ECODE_FAILED;
- }
-
- TAILQ_FOREACH(lcmd, &gcmd->commands, next) {
- json_array_append(jarray, json_string(lcmd->name));
- i++;
- }
-
- json_object_set_new(jdata, "count", json_integer(i));
- json_object_set_new(jdata, "commands", jarray);
- json_object_set_new(answer, "message", jdata);
- SCReturnInt(TM_ECODE_OK);
-}
-
-
-#if 0
-TmEcode UnixManagerReloadRules(json_t *cmd,
- json_t *server_msg, void *data)
-{
- SCEnter();
- if (suricata_ctl_flags != 0) {
- json_object_set_new(server_msg, "message",
- json_string("Live rule swap no longer possible."
- " Engine in shutdown mode."));
- SCReturn(TM_ECODE_FAILED);
- } else {
- /* FIXME : need to check option value */
- UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
- DetectEngineSpawnLiveRuleSwapMgmtThread();
- json_object_set_new(server_msg, "message", json_string("Reloading rules"));
- }
- SCReturn(TM_ECODE_OK);
-}
-#endif
-
-static UnixCommand command;
-
-/**
- * \brief Add a command to the list of commands
- *
- * This function adds a command to the list of commands available
- * through the unix socket.
- *
- * When a command is received from user through the unix socket, the content
- * of 'Command' field in the JSON message is match against keyword, then the
- * Func is called. See UnixSocketAddPcapFile() for an example.
- *
- * \param keyword name of the command
- * \param Func function to run when command is received
- * \param data a pointer to data that are passed to Func when it is run
- * \param flags a flag now used to tune the command type
- * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
- */
-TmEcode UnixManagerRegisterCommand(const char * keyword,
- TmEcode (*Func)(json_t *, json_t *, void *),
- void *data, int flags)
-{
- SCEnter();
- Command *cmd = NULL;
- Command *lcmd = NULL;
-
- if (Func == NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
- SCReturnInt(TM_ECODE_FAILED);
- }
-
- if (keyword == NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword");
- SCReturnInt(TM_ECODE_FAILED);
- }
-
- TAILQ_FOREACH(lcmd, &command.commands, next) {
- if (!strcmp(keyword, lcmd->name)) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword);
- SCReturnInt(TM_ECODE_FAILED);
- }
- }
-
- cmd = SCMalloc(sizeof(Command));
- if (unlikely(cmd == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd");
- SCReturnInt(TM_ECODE_FAILED);
- }
- cmd->name = SCStrdup(keyword);
- if (unlikely(cmd->name == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd name");
- SCFree(cmd);
- SCReturnInt(TM_ECODE_FAILED);
- }
- cmd->Func = Func;
- cmd->data = data;
- cmd->flags = flags;
- /* Add it to the list */
- TAILQ_INSERT_TAIL(&command.commands, cmd, next);
-
- SCReturnInt(TM_ECODE_OK);
-}
-
-/**
- * \brief Add a task to the list of tasks
- *
- * This function adds a task to run in the background. The task is run
- * each time the UnixMain() function exits from select.
- *
- * \param Func function to run when a command is received
- * \param data a pointer to data that are passed to Func when it is run
- * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
- */
-TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *),
- void *data)
-{
- SCEnter();
- Task *task = NULL;
-
- if (Func == NULL) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
- SCReturnInt(TM_ECODE_FAILED);
- }
-
- task = SCMalloc(sizeof(Task));
- if (unlikely(task == NULL)) {
- SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc task");
- SCReturnInt(TM_ECODE_FAILED);
- }
- task->Func = Func;
- task->data = data;
- /* Add it to the list */
- TAILQ_INSERT_TAIL(&command.tasks, task, next);
-
- SCReturnInt(TM_ECODE_OK);
-}
-
-typedef struct UnixManagerThreadData_ {
- int padding;
-} UnixManagerThreadData;
-
-static TmEcode UnixManagerThreadInit(ThreadVars *t, void *initdata, void **data)
-{
- UnixManagerThreadData *utd = SCCalloc(1, sizeof(*utd));
- if (utd == NULL)
- return TM_ECODE_FAILED;
-
- *data = utd;
- return TM_ECODE_OK;
-}
-
-static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data)
-{
- SCFree(data);
- return TM_ECODE_OK;
-}
-
-static TmEcode UnixManager(ThreadVars *th_v, void *thread_data)
-{
- int ret;
-
- /* set the thread name */
- SCLogDebug("%s started...", th_v->name);
-
- StatsSetupPrivate(th_v);
-
- if (UnixNew(&command) == 0) {
- int failure_fatal = 0;
- SCLogError(SC_ERR_INITIALIZATION,
- "Unable to create unix command socket");
- if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) {
- SCLogDebug("ConfGetBool could not load the value.");
- }
- if (failure_fatal) {
- exit(EXIT_FAILURE);
- } else {
- return TM_ECODE_FAILED;
- }
- }
-
- /* Set the threads capability */
- th_v->cap_flags = 0;
- SCDropCaps(th_v);
-
- /* Init Unix socket */
- UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0);
- UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0);
- UnixManagerRegisterCommand("help", UnixManagerListCommand, &command, 0);
- UnixManagerRegisterCommand("version", UnixManagerVersionCommand, &command, 0);
- UnixManagerRegisterCommand("uptime", UnixManagerUptimeCommand, &command, 0);
- UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0);
- UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0);
- UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS);
- UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0);
- UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0);
- UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
- UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
- UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS);
- UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS);
- UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS);
-
-
- TmThreadsSetFlag(th_v, THV_INIT_DONE);
- while (1) {
- ret = UnixMain(&command);
- if (ret == 0) {
- SCLogError(SC_ERR_FATAL, "Fatal error on unix socket");
- }
-
- if ((ret == 0) || (TmThreadsCheckFlag(th_v, THV_KILL))) {
- UnixClient *item;
- UnixClient *titem;
- TAILQ_FOREACH_SAFE(item, &(&command)->clients, next, titem) {
- close(item->fd);
- SCFree(item);
- }
- StatsSyncCounters(th_v);
- break;
- }
-
- UnixCommandBackgroundTasks(&command);
- }
- return TM_ECODE_OK;
-}
-
-
-/** \brief Spawn the unix socket manager thread
- *
- * \param mode if set to 1, init failure cause suricata exit
- * */
-void UnixManagerThreadSpawn(int mode)
-{
- ThreadVars *tv_unixmgr = NULL;
-
- SCCtrlCondInit(&unix_manager_ctrl_cond, NULL);
- SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL);
-
- tv_unixmgr = TmThreadCreateCmdThreadByName("UnixManagerThread",
- "UnixManager", 0);
-
- if (tv_unixmgr == NULL) {
- SCLogError(SC_ERR_INITIALIZATION, "TmThreadsCreate failed");
- exit(EXIT_FAILURE);
- }
- if (TmThreadSpawn(tv_unixmgr) != TM_ECODE_OK) {
- SCLogError(SC_ERR_INITIALIZATION, "TmThreadSpawn failed");
- exit(EXIT_FAILURE);
- }
- if (mode == 1) {
- if (TmThreadsCheckFlag(tv_unixmgr, THV_RUNNING_DONE)) {
- SCLogError(SC_ERR_INITIALIZATION, "Unix socket init failed");
- exit(EXIT_FAILURE);
- }
- }
- return;
-}
-
-/**
- * \brief Used to kill unix manager thread(s).
- *
- * \todo Kinda hackish since it uses the tv name to identify unix manager
- * thread. We need an all weather identification scheme.
- */
-void UnixSocketKillSocketThread(void)
-{
- ThreadVars *tv = NULL;
-
- SCMutexLock(&tv_root_lock);
-
- /* unix manager thread(s) is/are a part of command threads */
- tv = tv_root[TVT_CMD];
-
- while (tv != NULL) {
- if (strcasecmp(tv->name, "UnixManagerThread") == 0) {
- /* If the thread dies during init it will have
- * THV_RUNNING_DONE set, so we can set the correct flag
- * and exit.
- */
- if (TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
- TmThreadsSetFlag(tv, THV_KILL);
- TmThreadsSetFlag(tv, THV_DEINIT);
- TmThreadsSetFlag(tv, THV_CLOSED);
- break;
- }
- TmThreadsSetFlag(tv, THV_KILL);
- TmThreadsSetFlag(tv, THV_DEINIT);
- /* Be sure it has shut down */
- while (!TmThreadsCheckFlag(tv, THV_CLOSED)) {
- usleep(100);
- }
- }
- tv = tv->next;
- }
-
- SCMutexUnlock(&tv_root_lock);
- return;
-}
-
-#else /* BUILD_UNIX_SOCKET */
-
-void UnixManagerThreadSpawn(int mode)
-{
- SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled");
- return;
-}
-
-void UnixSocketKillSocketThread(void)
-{
- return;
-}
-
-#endif /* BUILD_UNIX_SOCKET */
-
-void TmModuleUnixManagerRegister (void)
-{
-#ifdef BUILD_UNIX_SOCKET
- tmm_modules[TMM_UNIXMANAGER].name = "UnixManager";
- tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit;
- tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit;
- tmm_modules[TMM_UNIXMANAGER].Management = UnixManager;
- tmm_modules[TMM_UNIXMANAGER].cap_flags = 0;
- tmm_modules[TMM_UNIXMANAGER].flags = TM_FLAG_COMMAND_TM;
-#endif /* BUILD_UNIX_SOCKET */
-}