1 /* Copyright (C) 2013-2018 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Eric Leblond <eric@regit.org>
22  */
23 
24 #include "suricata-common.h"
25 #include "suricata.h"
26 #include "unix-manager.h"
27 #include "detect-engine.h"
28 #include "tm-threads.h"
29 #include "runmodes.h"
30 #include "conf.h"
31 
32 #include "output-json-stats.h"
33 
34 #include "util-privs.h"
35 #include "util-debug.h"
36 #include "util-device.h"
37 #include "util-ebpf.h"
38 #include "util-signal.h"
39 #include "util-buffer.h"
40 
41 #if (defined BUILD_UNIX_SOCKET) && (defined HAVE_SYS_UN_H) && (defined HAVE_SYS_STAT_H) && (defined HAVE_SYS_TYPES_H)
42 #include <sys/un.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 
46 #include "output.h"
47 #include "output-json.h"
48 
49 // MSG_NOSIGNAL does not exists on OS X
50 #ifdef OS_DARWIN
51 # ifndef MSG_NOSIGNAL
52 #   define MSG_NOSIGNAL SO_NOSIGPIPE
53 # endif
54 #endif
55 
56 #define SOCKET_PATH LOCAL_STATE_DIR "/run/suricata/"
57 #define SOCKET_FILENAME "suricata-command.socket"
58 #define SOCKET_TARGET SOCKET_PATH SOCKET_FILENAME
59 
60 SCCtrlCondT unix_manager_ctrl_cond;
61 SCCtrlMutex unix_manager_ctrl_mutex;
62 
63 #define MAX_FAILED_RULES   20
64 
65 typedef struct Command_ {
66     char *name;
67     TmEcode (*Func)(json_t *, json_t *, void *);
68     void *data;
69     int flags;
70     TAILQ_ENTRY(Command_) next;
71 } Command;
72 
73 typedef struct Task_ {
74     TmEcode (*Func)(void *);
75     void *data;
76     TAILQ_ENTRY(Task_) next;
77 } Task;
78 
79 #define CLIENT_BUFFER_SIZE 4096
80 typedef struct UnixClient_ {
81     int fd;
82     MemBuffer *mbuf; /**< buffer for response construction */
83     int version;
84     TAILQ_ENTRY(UnixClient_) next;
85 } UnixClient;
86 
87 typedef struct UnixCommand_ {
88     time_t start_timestamp;
89     int socket;
90     struct sockaddr_un client_addr;
91     int select_max;
92     TAILQ_HEAD(, Command_) commands;
93     TAILQ_HEAD(, Task_) tasks;
94     TAILQ_HEAD(, UnixClient_) clients;
95 } UnixCommand;
96 
97 /**
98  * \brief Create a command unix socket on system
99  *
100  * \retval 0 in case of error, 1 in case of success
101  */
UnixNew(UnixCommand * this)102 static int UnixNew(UnixCommand * this)
103 {
104     struct sockaddr_un addr;
105     int len;
106     int ret;
107     int on = 1;
108     char sockettarget[PATH_MAX];
109     const char *socketname;
110 
111     this->start_timestamp = time(NULL);
112     this->socket = -1;
113     this->select_max = 0;
114 
115     TAILQ_INIT(&this->commands);
116     TAILQ_INIT(&this->tasks);
117     TAILQ_INIT(&this->clients);
118 
119     int check_dir = 0;
120     if (ConfGet("unix-command.filename", &socketname) == 1) {
121         if (PathIsAbsolute(socketname)) {
122             strlcpy(sockettarget, socketname, sizeof(sockettarget));
123         } else {
124             snprintf(sockettarget, sizeof(sockettarget), "%s/%s",
125                     SOCKET_PATH, socketname);
126             check_dir = 1;
127         }
128     } else {
129         strlcpy(sockettarget, SOCKET_TARGET, sizeof(sockettarget));
130         check_dir = 1;
131     }
132     SCLogInfo("Using unix socket file '%s'", sockettarget);
133 
134     if (check_dir) {
135         struct stat stat_buf;
136         /* coverity[toctou] */
137         if (stat(SOCKET_PATH, &stat_buf) != 0) {
138             /* coverity[toctou] */
139             ret = SCMkDir(SOCKET_PATH, S_IRWXU|S_IXGRP|S_IRGRP);
140             if (ret != 0) {
141                 int err = errno;
142                 if (err != EEXIST) {
143                     SCLogError(SC_ERR_INITIALIZATION,
144                             "Cannot create socket directory %s: %s",
145                             SOCKET_PATH, strerror(err));
146                     return 0;
147                 }
148             } else {
149                 SCLogInfo("Created socket directory %s",
150                         SOCKET_PATH);
151             }
152         }
153     }
154 
155     /* Remove socket file */
156     (void) unlink(sockettarget);
157 
158     /* set address */
159     addr.sun_family = AF_UNIX;
160     strlcpy(addr.sun_path, sockettarget, sizeof(addr.sun_path));
161     addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
162     len = strlen(addr.sun_path) + sizeof(addr.sun_family) + 1;
163 
164     /* create socket */
165     this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
166     if (this->socket == -1) {
167         SCLogWarning(SC_ERR_OPENING_FILE,
168                      "Unix Socket: unable to create UNIX socket %s: %s",
169                      addr.sun_path, strerror(errno));
170         return 0;
171     }
172     this->select_max = this->socket + 1;
173 
174     /* set reuse option */
175     ret = setsockopt(this->socket, SOL_SOCKET, SO_REUSEADDR,
176                      (char *) &on, sizeof(on));
177     if ( ret != 0 ) {
178         SCLogWarning(SC_ERR_INITIALIZATION,
179                      "Cannot set sockets options: %s.",  strerror(errno));
180     }
181 
182     /* bind socket */
183     ret = bind(this->socket, (struct sockaddr *) &addr, len);
184     if (ret == -1) {
185         SCLogWarning(SC_ERR_INITIALIZATION,
186                      "Unix socket: UNIX socket bind(%s) error: %s",
187                      sockettarget, strerror(errno));
188         return 0;
189     }
190 
191 #if !(defined OS_FREEBSD || defined __OpenBSD__ || defined __DragonFly__)
192     /* Set file mode: will not fully work on most system, the group
193      * permission is not changed on some Linux. *BSD won't do the
194      * chmod: it returns EINVAL when calling chmod on sockets. */
195     ret = chmod(sockettarget, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
196     if (ret == -1) {
197         int err = errno;
198         SCLogWarning(SC_ERR_INITIALIZATION,
199                      "Unable to change permission on socket: %s (%d)",
200                      strerror(err),
201                      err);
202     }
203 #endif
204 
205     /* listen */
206     if (listen(this->socket, 1) == -1) {
207         SCLogWarning(SC_ERR_INITIALIZATION,
208                      "Command server: UNIX socket listen() error: %s",
209                      strerror(errno));
210         return 0;
211     }
212     return 1;
213 }
214 
UnixCommandSetMaxFD(UnixCommand * this)215 static void UnixCommandSetMaxFD(UnixCommand *this)
216 {
217     UnixClient *item;
218 
219     if (this == NULL) {
220         SCLogError(SC_ERR_INVALID_ARGUMENT, "Unix command is NULL, warn devel");
221         return;
222     }
223 
224     this->select_max = this->socket + 1;
225     TAILQ_FOREACH(item, &this->clients, next) {
226         if (item->fd >= this->select_max) {
227             this->select_max = item->fd + 1;
228         }
229     }
230 }
231 
UnixClientAlloc(void)232 static UnixClient *UnixClientAlloc(void)
233 {
234     UnixClient *uclient = SCMalloc(sizeof(UnixClient));
235     if (unlikely(uclient == NULL)) {
236         SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
237         return NULL;
238     }
239     uclient->mbuf = MemBufferCreateNew(CLIENT_BUFFER_SIZE);
240     if (uclient->mbuf == NULL) {
241         SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client send buffer");
242         SCFree(uclient);
243         return NULL;
244     }
245     return uclient;
246 }
247 
UnixClientFree(UnixClient * c)248 static void UnixClientFree(UnixClient *c)
249 {
250     if (c != NULL) {
251         MemBufferFree(c->mbuf);
252         SCFree(c);
253     }
254 }
255 
256 /**
257  * \brief Close the unix socket
258  */
UnixCommandClose(UnixCommand * this,int fd)259 static void UnixCommandClose(UnixCommand  *this, int fd)
260 {
261     UnixClient *item;
262     int found = 0;
263 
264     TAILQ_FOREACH(item, &this->clients, next) {
265         if (item->fd == fd) {
266             found = 1;
267             break;
268         }
269     }
270 
271     if (found == 0) {
272         SCLogError(SC_ERR_INVALID_VALUE, "No fd found in client list");
273         return;
274     }
275 
276     TAILQ_REMOVE(&this->clients, item, next);
277 
278     close(item->fd);
279     UnixCommandSetMaxFD(this);
280     UnixClientFree(item);
281 }
282 
283 #define UNIX_PROTO_VERSION_LENGTH 200
284 #define UNIX_PROTO_VERSION_V1 "0.1"
285 #define UNIX_PROTO_V1 1
286 #define UNIX_PROTO_VERSION "0.2"
287 #define UNIX_PROTO_V2 2
288 
UnixCommandSendJSONToClient(UnixClient * client,json_t * js)289 static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
290 {
291     MemBufferReset(client->mbuf);
292 
293     OutputJSONMemBufferWrapper wrapper = {
294         .buffer = &client->mbuf,
295         .expand_by = CLIENT_BUFFER_SIZE
296     };
297 
298     int r = json_dump_callback(js, OutputJSONMemBufferCallback, &wrapper,
299             JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
300             JSON_ESCAPE_SLASH);
301     if (r != 0) {
302         SCLogWarning(SC_ERR_SOCKET, "unable to serialize JSON object");
303         return -1;
304     }
305 
306     if (client->version > UNIX_PROTO_V1) {
307         if (MEMBUFFER_OFFSET(client->mbuf) + 1 >= MEMBUFFER_SIZE(client->mbuf)) {
308             MemBufferExpand(&client->mbuf, 1);
309         }
310         MemBufferWriteRaw(client->mbuf, "\n", 1);
311     }
312 
313     if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf),
314                 MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1)
315     {
316         SCLogWarning(SC_ERR_SOCKET, "unable to send block of size "
317                 "%"PRIuMAX": %s", (uintmax_t)MEMBUFFER_OFFSET(client->mbuf),
318                 strerror(errno));
319         return -1;
320     }
321 
322     SCLogDebug("sent message of size %"PRIuMAX" to client socket %d",
323             (uintmax_t)MEMBUFFER_OFFSET(client->mbuf), client->fd);
324     return 0;
325 }
326 
327 /**
328  * \brief Accept a new client on unix socket
329  *
330  *  The function is called when a new user is detected
331  *  in UnixMain(). It does the initial protocol negotiation
332  *  with client.
333  *
334  * \retval 0 in case of error, 1 in case of success
335  */
UnixCommandAccept(UnixCommand * this)336 static int UnixCommandAccept(UnixCommand *this)
337 {
338     char buffer[UNIX_PROTO_VERSION_LENGTH + 1];
339     json_t *client_msg;
340     json_t *server_msg;
341     json_t *version;
342     json_error_t jerror;
343     int client;
344     int client_version;
345     int ret;
346     UnixClient *uclient = NULL;
347 
348     /* accept client socket */
349     socklen_t len = sizeof(this->client_addr);
350     client = accept(this->socket, (struct sockaddr *) &this->client_addr,
351                           &len);
352     if (client < 0) {
353         SCLogInfo("Unix socket: accept() error: %s",
354                   strerror(errno));
355         return 0;
356     }
357     SCLogDebug("Unix socket: client connection");
358 
359     /* read client version */
360     buffer[sizeof(buffer)-1] = 0;
361     ret = recv(client, buffer, sizeof(buffer)-1, 0);
362     if (ret < 0) {
363         SCLogInfo("Command server: client doesn't send version");
364         close(client);
365         return 0;
366     }
367     if (ret >= (int)(sizeof(buffer)-1)) {
368         SCLogInfo("Command server: client message is too long, "
369                   "disconnect him.");
370         close(client);
371         return 0;
372     }
373     buffer[ret] = 0;
374 
375     client_msg = json_loads(buffer, 0, &jerror);
376     if (client_msg == NULL) {
377         SCLogInfo("Invalid command, error on line %d: %s\n", jerror.line, jerror.text);
378         close(client);
379         return 0;
380     }
381 
382     version = json_object_get(client_msg, "version");
383     if (!json_is_string(version)) {
384         SCLogInfo("error: version is not a string");
385         close(client);
386         json_decref(client_msg);
387         return 0;
388     }
389 
390     /* check client version */
391     if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0)
392         && (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) {
393         SCLogInfo("Unix socket: invalid client version: \"%s\"",
394                 json_string_value(version));
395         json_decref(client_msg);
396         close(client);
397         return 0;
398     } else {
399         SCLogDebug("Unix socket: client version: \"%s\"",
400                 json_string_value(version));
401         if (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) == 0) {
402             client_version = UNIX_PROTO_V1;
403         } else {
404             client_version = UNIX_PROTO_V2;
405         }
406     }
407 
408     json_decref(client_msg);
409     /* send answer */
410     server_msg = json_object();
411     if (server_msg == NULL) {
412         close(client);
413         return 0;
414     }
415     json_object_set_new(server_msg, "return", json_string("OK"));
416 
417     uclient = UnixClientAlloc();
418     if (unlikely(uclient == NULL)) {
419         SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate new client");
420         json_decref(server_msg);
421         close(client);
422         return 0;
423     }
424     uclient->fd = client;
425     uclient->version = client_version;
426 
427     if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
428         SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
429 
430         UnixClientFree(uclient);
431         json_decref(server_msg);
432         close(client);
433         return 0;
434     }
435 
436     json_decref(server_msg);
437 
438     /* client connected */
439     SCLogDebug("Unix socket: client connected");
440     TAILQ_INSERT_TAIL(&this->clients, uclient, next);
441     UnixCommandSetMaxFD(this);
442     return 1;
443 }
444 
UnixCommandBackgroundTasks(UnixCommand * this)445 static int UnixCommandBackgroundTasks(UnixCommand* this)
446 {
447     int ret = 1;
448     Task *ltask;
449 
450     TAILQ_FOREACH(ltask, &this->tasks, next) {
451         int fret = ltask->Func(ltask->data);
452         if (fret != TM_ECODE_OK) {
453             ret = 0;
454         }
455     }
456     return ret;
457 }
458 
459 /**
460  * \brief Command dispatcher
461  *
462  * \param this a UnixCommand:: structure
463  * \param command a string containing a json formatted
464  * command
465  *
466  * \retval 0 in case of error, 1 in case of success
467  */
UnixCommandExecute(UnixCommand * this,char * command,UnixClient * client)468 static int UnixCommandExecute(UnixCommand * this, char *command, UnixClient *client)
469 {
470     int ret = 1;
471     json_error_t error;
472     json_t *jsoncmd = NULL;
473     json_t *cmd = NULL;
474     json_t *server_msg = json_object();
475     const char * value;
476     int found = 0;
477     Command *lcmd;
478 
479     if (server_msg == NULL) {
480         return 0;
481     }
482 
483     jsoncmd = json_loads(command, 0, &error);
484     if (jsoncmd == NULL) {
485         SCLogInfo("Invalid command, error on line %d: %s\n", error.line, error.text);
486         goto error;
487     }
488 
489     cmd = json_object_get(jsoncmd, "command");
490     if(!json_is_string(cmd)) {
491         SCLogInfo("error: command is not a string");
492         goto error_cmd;
493     }
494     value = json_string_value(cmd);
495 
496     TAILQ_FOREACH(lcmd, &this->commands, next) {
497         if (!strcmp(value, lcmd->name)) {
498             int fret = TM_ECODE_OK;
499             found = 1;
500             if (lcmd->flags & UNIX_CMD_TAKE_ARGS) {
501                 cmd = json_object_get(jsoncmd, "arguments");
502                 if(!json_is_object(cmd)) {
503                     SCLogInfo("error: argument is not an object");
504                     goto error_cmd;
505                 }
506             }
507             fret = lcmd->Func(cmd, server_msg, lcmd->data);
508             if (fret != TM_ECODE_OK) {
509                 ret = 0;
510             }
511             break;
512         }
513     }
514 
515     if (found == 0) {
516         json_object_set_new(server_msg, "message", json_string("Unknown command"));
517         ret = 0;
518     }
519 
520     switch (ret) {
521         case 0:
522             json_object_set_new(server_msg, "return", json_string("NOK"));
523             break;
524         case 1:
525             json_object_set_new(server_msg, "return", json_string("OK"));
526             break;
527     }
528 
529     if (UnixCommandSendJSONToClient(client, server_msg) != 0) {
530         goto error;
531     }
532 
533     json_decref(jsoncmd);
534     json_decref(server_msg);
535     return ret;
536 
537 error_cmd:
538     json_decref(jsoncmd);
539 error:
540     json_decref(server_msg);
541     UnixCommandClose(this, client->fd);
542     return 0;
543 }
544 
UnixCommandRun(UnixCommand * this,UnixClient * client)545 static void UnixCommandRun(UnixCommand * this, UnixClient *client)
546 {
547     char buffer[4096];
548     int ret;
549     if (client->version <= UNIX_PROTO_V1) {
550         ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
551         if (ret <= 0) {
552             if (ret == 0) {
553                 SCLogDebug("Unix socket: lost connection with client");
554             } else {
555                 SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
556                         strerror(errno));
557             }
558             UnixCommandClose(this, client->fd);
559             return;
560         }
561         if (ret >= (int)(sizeof(buffer)-1)) {
562             SCLogError(SC_ERR_SOCKET, "Command server: client command is too long, "
563                     "disconnect him.");
564             UnixCommandClose(this, client->fd);
565         }
566         buffer[ret] = 0;
567     } else {
568         int try = 0;
569         int offset = 0;
570         int cmd_over = 0;
571         ret = recv(client->fd, buffer + offset, sizeof(buffer) - offset - 1, 0);
572         do {
573             if (ret <= 0) {
574                 if (ret == 0) {
575                     SCLogInfo("Unix socket: lost connection with client");
576                 } else {
577                     SCLogInfo("Unix socket: error on recv() from client: %s",
578                             strerror(errno));
579                 }
580                 UnixCommandClose(this, client->fd);
581                 return;
582             }
583             if (ret >= (int)(sizeof(buffer)- offset - 1)) {
584                 SCLogInfo("Command server: client command is too long, "
585                         "disconnect him.");
586                 UnixCommandClose(this, client->fd);
587             }
588             if (buffer[ret - 1] == '\n') {
589                 buffer[ret-1] = 0;
590                 cmd_over = 1;
591             } else {
592                 struct timeval tv;
593                 fd_set select_set;
594                 offset += ret;
595                 do {
596                     FD_ZERO(&select_set);
597                     FD_SET(client->fd, &select_set);
598                     tv.tv_sec = 0;
599                     tv.tv_usec = 200 * 1000;
600                     try++;
601                     ret = select(client->fd, &select_set, NULL, NULL, &tv);
602                     /* catch select() error */
603                     if (ret == -1) {
604                         /* Signal was caught: just ignore it */
605                         if (errno != EINTR) {
606                             SCLogInfo("Unix socket: lost connection with client");
607                             UnixCommandClose(this, client->fd);
608                             return;
609                         }
610                     }
611                 } while (ret == 0 && try < 3);
612                 if (ret > 0) {
613                     ret = recv(client->fd, buffer + offset,
614                                sizeof(buffer) - offset - 1, 0);
615                 }
616             }
617         } while (try < 3 && cmd_over == 0);
618 
619         if (try == 3 && cmd_over == 0) {
620             SCLogInfo("Unix socket: imcomplete client message, closing connection");
621             UnixCommandClose(this, client->fd);
622             return;
623         }
624     }
625     UnixCommandExecute(this, buffer, client);
626 }
627 
628 /**
629  * \brief Select function
630  *
631  * \retval 0 in case of error, 1 in case of success
632  */
UnixMain(UnixCommand * this)633 static int UnixMain(UnixCommand * this)
634 {
635     struct timeval tv;
636     int ret;
637     fd_set select_set;
638     UnixClient *uclient;
639     UnixClient *tclient;
640 
641     /* Wait activity on the socket */
642     FD_ZERO(&select_set);
643     FD_SET(this->socket, &select_set);
644     TAILQ_FOREACH(uclient, &this->clients, next) {
645         FD_SET(uclient->fd, &select_set);
646     }
647 
648     tv.tv_sec = 0;
649     tv.tv_usec = 200 * 1000;
650     ret = select(this->select_max, &select_set, NULL, NULL, &tv);
651 
652     /* catch select() error */
653     if (ret == -1) {
654         /* Signal was caught: just ignore it */
655         if (errno == EINTR) {
656             return 1;
657         }
658         SCLogError(SC_ERR_SOCKET, "Command server: select() fatal error: %s", strerror(errno));
659         return 0;
660     }
661 
662     if (suricata_ctl_flags & SURICATA_STOP) {
663         TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
664             UnixCommandClose(this, uclient->fd);
665         }
666         return 1;
667     }
668 
669     /* timeout: continue */
670     if (ret == 0) {
671         return 1;
672     }
673 
674     TAILQ_FOREACH_SAFE(uclient, &this->clients, next, tclient) {
675         if (FD_ISSET(uclient->fd, &select_set)) {
676             UnixCommandRun(this, uclient);
677         }
678     }
679     if (FD_ISSET(this->socket, &select_set)) {
680         if (!UnixCommandAccept(this))
681             return 1;
682     }
683 
684     return 1;
685 }
686 
UnixManagerShutdownCommand(json_t * cmd,json_t * server_msg,void * data)687 static TmEcode UnixManagerShutdownCommand(json_t *cmd,
688                                    json_t *server_msg, void *data)
689 {
690     SCEnter();
691     json_object_set_new(server_msg, "message", json_string("Closing Suricata"));
692     EngineStop();
693     SCReturnInt(TM_ECODE_OK);
694 }
695 
UnixManagerVersionCommand(json_t * cmd,json_t * server_msg,void * data)696 static TmEcode UnixManagerVersionCommand(json_t *cmd,
697                                    json_t *server_msg, void *data)
698 {
699     SCEnter();
700     json_object_set_new(server_msg, "message", json_string(GetProgramVersion()));
701     SCReturnInt(TM_ECODE_OK);
702 }
703 
UnixManagerUptimeCommand(json_t * cmd,json_t * server_msg,void * data)704 static TmEcode UnixManagerUptimeCommand(json_t *cmd,
705                                  json_t *server_msg, void *data)
706 {
707     SCEnter();
708     int uptime;
709     UnixCommand *ucmd = (UnixCommand *)data;
710 
711     uptime = time(NULL) - ucmd->start_timestamp;
712     json_object_set_new(server_msg, "message", json_integer(uptime));
713     SCReturnInt(TM_ECODE_OK);
714 }
715 
UnixManagerRunningModeCommand(json_t * cmd,json_t * server_msg,void * data)716 static TmEcode UnixManagerRunningModeCommand(json_t *cmd,
717                                       json_t *server_msg, void *data)
718 {
719     SCEnter();
720     json_object_set_new(server_msg, "message", json_string(RunmodeGetActive()));
721     SCReturnInt(TM_ECODE_OK);
722 }
723 
UnixManagerCaptureModeCommand(json_t * cmd,json_t * server_msg,void * data)724 static TmEcode UnixManagerCaptureModeCommand(json_t *cmd,
725                                       json_t *server_msg, void *data)
726 {
727     SCEnter();
728     json_object_set_new(server_msg, "message", json_string(RunModeGetMainMode()));
729     SCReturnInt(TM_ECODE_OK);
730 }
731 
UnixManagerReloadRulesWrapper(json_t * cmd,json_t * server_msg,void * data,int do_wait)732 static TmEcode UnixManagerReloadRulesWrapper(json_t *cmd, json_t *server_msg, void *data, int do_wait)
733 {
734     SCEnter();
735 
736     if (SuriHasSigFile()) {
737         json_object_set_new(server_msg, "message",
738                             json_string("Live rule reload not possible if -s "
739                                         "or -S option used at runtime."));
740         SCReturnInt(TM_ECODE_FAILED);
741     }
742 
743     int r = DetectEngineReloadStart();
744 
745     if (r == 0 && do_wait) {
746         while (!DetectEngineReloadIsIdle())
747             usleep(100);
748     } else {
749         if (r == -1) {
750             json_object_set_new(server_msg, "message", json_string("Reload already in progress"));
751             SCReturnInt(TM_ECODE_FAILED);
752         }
753     }
754 
755     json_object_set_new(server_msg, "message", json_string("done"));
756     SCReturnInt(TM_ECODE_OK);
757 }
758 
UnixManagerReloadRules(json_t * cmd,json_t * server_msg,void * data)759 static TmEcode UnixManagerReloadRules(json_t *cmd, json_t *server_msg, void *data)
760 {
761     return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 1);
762 }
763 
UnixManagerNonBlockingReloadRules(json_t * cmd,json_t * server_msg,void * data)764 static TmEcode UnixManagerNonBlockingReloadRules(json_t *cmd, json_t *server_msg, void *data)
765 {
766     return UnixManagerReloadRulesWrapper(cmd, server_msg, data, 0);
767 }
768 
UnixManagerReloadTimeCommand(json_t * cmd,json_t * server_msg,void * data)769 static TmEcode UnixManagerReloadTimeCommand(json_t *cmd,
770                                             json_t *server_msg, void *data)
771 {
772     SCEnter();
773     TmEcode retval;
774     json_t *jdata = NULL;
775 
776     retval = OutputEngineStatsReloadTime(&jdata);
777     json_object_set_new(server_msg, "message", jdata);
778     SCReturnInt(retval);
779 }
780 
UnixManagerRulesetStatsCommand(json_t * cmd,json_t * server_msg,void * data)781 static TmEcode UnixManagerRulesetStatsCommand(json_t *cmd,
782                                               json_t *server_msg, void *data)
783 {
784     SCEnter();
785     TmEcode retval;
786     json_t *jdata = NULL;
787 
788     retval = OutputEngineStatsRuleset(&jdata);
789     json_object_set_new(server_msg, "message", jdata);
790     SCReturnInt(retval);
791 }
792 
UnixManagerShowFailedRules(json_t * cmd,json_t * server_msg,void * data)793 static TmEcode UnixManagerShowFailedRules(json_t *cmd,
794                                           json_t *server_msg, void *data)
795 {
796     SCEnter();
797     int rules_cnt = 0;
798     DetectEngineCtx *de_ctx = DetectEngineGetCurrent();
799     if (de_ctx == NULL) {
800         json_object_set_new(server_msg, "message", json_string("Unable to get info"));
801         SCReturnInt(TM_ECODE_OK);
802     }
803 
804     /* Since we need to deference de_ctx, we don't want to lost it. */
805     DetectEngineCtx *list = de_ctx;
806     json_t *js_sigs_array = json_array();
807 
808     if (js_sigs_array == NULL) {
809         json_object_set_new(server_msg, "message", json_string("Unable to get info"));
810         goto error;
811     }
812     while (list) {
813         SigString *sigs_str = NULL;
814         TAILQ_FOREACH(sigs_str, &list->sig_stat.failed_sigs, next) {
815             json_t *jdata = json_object();
816             if (jdata == NULL) {
817                 json_object_set_new(server_msg, "message", json_string("Unable to get the sig"));
818                 goto error;
819             }
820 
821             json_object_set_new(jdata, "tenant_id", json_integer(list->tenant_id));
822             json_object_set_new(jdata, "rule", json_string(sigs_str->sig_str));
823             json_object_set_new(jdata, "filename", json_string(sigs_str->filename));
824             json_object_set_new(jdata, "line", json_integer(sigs_str->line));
825             if (sigs_str->sig_error) {
826                 json_object_set_new(jdata, "error", json_string(sigs_str->sig_error));
827             }
828             json_array_append_new(js_sigs_array, jdata);
829             if (++rules_cnt > MAX_FAILED_RULES) {
830                 break;
831             }
832         }
833         if (rules_cnt > MAX_FAILED_RULES) {
834             break;
835         }
836         list = list->next;
837     }
838 
839     json_object_set_new(server_msg, "message", js_sigs_array);
840     DetectEngineDeReference(&de_ctx);
841     SCReturnInt(TM_ECODE_OK);
842 
843 error:
844     DetectEngineDeReference(&de_ctx);
845     json_object_clear(js_sigs_array);
846     json_decref(js_sigs_array);
847     SCReturnInt(TM_ECODE_FAILED);
848 }
849 
UnixManagerConfGetCommand(json_t * cmd,json_t * server_msg,void * data)850 static TmEcode UnixManagerConfGetCommand(json_t *cmd,
851                                          json_t *server_msg, void *data)
852 {
853     SCEnter();
854 
855     const char *confval = NULL;
856     char *variable = NULL;
857 
858     json_t *jarg = json_object_get(cmd, "variable");
859     if(!json_is_string(jarg)) {
860         SCLogInfo("error: variable is not a string");
861         json_object_set_new(server_msg, "message", json_string("variable is not a string"));
862         SCReturnInt(TM_ECODE_FAILED);
863     }
864 
865     variable = (char *)json_string_value(jarg);
866     if (ConfGet(variable, &confval) != 1) {
867         json_object_set_new(server_msg, "message", json_string("Unable to get value"));
868         SCReturnInt(TM_ECODE_FAILED);
869     }
870 
871     if (confval) {
872         json_object_set_new(server_msg, "message", json_string(confval));
873         SCReturnInt(TM_ECODE_OK);
874     }
875 
876     json_object_set_new(server_msg, "message", json_string("No string value"));
877     SCReturnInt(TM_ECODE_FAILED);
878 }
879 
UnixManagerListCommand(json_t * cmd,json_t * answer,void * data)880 static TmEcode UnixManagerListCommand(json_t *cmd,
881                                json_t *answer, void *data)
882 {
883     SCEnter();
884     json_t *jdata;
885     json_t *jarray;
886     Command *lcmd = NULL;
887     UnixCommand *gcmd = (UnixCommand *) data;
888     int i = 0;
889 
890     jdata = json_object();
891     if (jdata == NULL) {
892         json_object_set_new(answer, "message",
893                             json_string("internal error at json object creation"));
894         return TM_ECODE_FAILED;
895     }
896     jarray = json_array();
897     if (jarray == NULL) {
898         json_object_set_new(answer, "message",
899                             json_string("internal error at json object creation"));
900         return TM_ECODE_FAILED;
901     }
902 
903     TAILQ_FOREACH(lcmd, &gcmd->commands, next) {
904         json_array_append_new(jarray, json_string(lcmd->name));
905         i++;
906     }
907 
908     json_object_set_new(jdata, "count", json_integer(i));
909     json_object_set_new(jdata, "commands", jarray);
910     json_object_set_new(answer, "message", jdata);
911     SCReturnInt(TM_ECODE_OK);
912 }
913 
UnixManagerReopenLogFiles(json_t * cmd,json_t * server_msg,void * data)914 static TmEcode UnixManagerReopenLogFiles(json_t *cmd, json_t *server_msg, void *data)
915 {
916     OutputNotifyFileRotation();
917     json_object_set_new(server_msg, "message", json_string("done"));
918     SCReturnInt(TM_ECODE_OK);
919 }
920 
921 #if 0
922 TmEcode UnixManagerReloadRules(json_t *cmd,
923                                json_t *server_msg, void *data)
924 {
925     SCEnter();
926     if (suricata_ctl_flags != 0) {
927         json_object_set_new(server_msg, "message",
928                             json_string("Live rule swap no longer possible."
929                                         " Engine in shutdown mode."));
930         SCReturn(TM_ECODE_FAILED);
931     } else {
932         /* FIXME : need to check option value */
933         UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2Idle);
934         DetectEngineSpawnLiveRuleSwapMgmtThread();
935         json_object_set_new(server_msg, "message", json_string("Reloading rules"));
936     }
937     SCReturn(TM_ECODE_OK);
938 }
939 #endif
940 
941 static UnixCommand command;
942 
943 /**
944  * \brief Add a command to the list of commands
945  *
946  * This function adds a command to the list of commands available
947  * through the unix socket.
948  *
949  * When a command is received from user through the unix socket, the content
950  * of 'Command' field in the JSON message is match against keyword, then the
951  * Func is called. See UnixSocketAddPcapFile() for an example.
952  *
953  * \param keyword name of the command
954  * \param Func function to run when command is received
955  * \param data a pointer to data that are passed to Func when it is run
956  * \param flags a flag now used to tune the command type
957  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
958  */
UnixManagerRegisterCommand(const char * keyword,TmEcode (* Func)(json_t *,json_t *,void *),void * data,int flags)959 TmEcode UnixManagerRegisterCommand(const char * keyword,
960                                    TmEcode (*Func)(json_t *, json_t *, void *),
961                                    void *data, int flags)
962 {
963     SCEnter();
964     Command *cmd = NULL;
965     Command *lcmd = NULL;
966 
967     if (Func == NULL) {
968         SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
969         SCReturnInt(TM_ECODE_FAILED);
970     }
971 
972     if (keyword == NULL) {
973         SCLogError(SC_ERR_INVALID_ARGUMENT, "Null keyword");
974         SCReturnInt(TM_ECODE_FAILED);
975     }
976 
977     TAILQ_FOREACH(lcmd, &command.commands, next) {
978         if (!strcmp(keyword, lcmd->name)) {
979             SCLogError(SC_ERR_INVALID_ARGUMENT, "%s already registered", keyword);
980             SCReturnInt(TM_ECODE_FAILED);
981         }
982     }
983 
984     cmd = SCMalloc(sizeof(Command));
985     if (unlikely(cmd == NULL)) {
986         SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd");
987         SCReturnInt(TM_ECODE_FAILED);
988     }
989     cmd->name = SCStrdup(keyword);
990     if (unlikely(cmd->name == NULL)) {
991         SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc cmd name");
992         SCFree(cmd);
993         SCReturnInt(TM_ECODE_FAILED);
994     }
995     cmd->Func = Func;
996     cmd->data = data;
997     cmd->flags = flags;
998     /* Add it to the list */
999     TAILQ_INSERT_TAIL(&command.commands, cmd, next);
1000 
1001     SCReturnInt(TM_ECODE_OK);
1002 }
1003 
1004 /**
1005  * \brief Add a task to the list of tasks
1006  *
1007  * This function adds a task to run in the background. The task is run
1008  * each time the UnixMain() function exits from select.
1009  *
1010  * \param Func function to run when a command is received
1011  * \param data a pointer to data that are passed to Func when it is run
1012  * \retval TM_ECODE_OK in case of success, TM_ECODE_FAILED in case of failure
1013  */
UnixManagerRegisterBackgroundTask(TmEcode (* Func)(void *),void * data)1014 TmEcode UnixManagerRegisterBackgroundTask(TmEcode (*Func)(void *),
1015                                           void *data)
1016 {
1017     SCEnter();
1018     Task *task = NULL;
1019 
1020     if (Func == NULL) {
1021         SCLogError(SC_ERR_INVALID_ARGUMENT, "Null function");
1022         SCReturnInt(TM_ECODE_FAILED);
1023     }
1024 
1025     task = SCMalloc(sizeof(Task));
1026     if (unlikely(task == NULL)) {
1027         SCLogError(SC_ERR_MEM_ALLOC, "Can't alloc task");
1028         SCReturnInt(TM_ECODE_FAILED);
1029     }
1030     task->Func = Func;
1031     task->data = data;
1032     /* Add it to the list */
1033     TAILQ_INSERT_TAIL(&command.tasks, task, next);
1034 
1035     SCReturnInt(TM_ECODE_OK);
1036 }
1037 
UnixManagerInit(void)1038 int UnixManagerInit(void)
1039 {
1040     if (UnixNew(&command) == 0) {
1041         int failure_fatal = 0;
1042         if (ConfGetBool("engine.init-failure-fatal", &failure_fatal) != 1) {
1043             SCLogDebug("ConfGetBool could not load the value.");
1044         }
1045         if (failure_fatal) {
1046                     FatalError(SC_ERR_FATAL,
1047                                "Unable to create unix command socket");
1048         } else {
1049             SCLogWarning(SC_ERR_INITIALIZATION,
1050                     "Unable to create unix command socket");
1051             return -1;
1052         }
1053     }
1054 
1055     /* Init Unix socket */
1056     UnixManagerRegisterCommand("shutdown", UnixManagerShutdownCommand, NULL, 0);
1057     UnixManagerRegisterCommand("command-list", UnixManagerListCommand, &command, 0);
1058     UnixManagerRegisterCommand("help", UnixManagerListCommand, &command, 0);
1059     UnixManagerRegisterCommand("version", UnixManagerVersionCommand, &command, 0);
1060     UnixManagerRegisterCommand("uptime", UnixManagerUptimeCommand, &command, 0);
1061     UnixManagerRegisterCommand("running-mode", UnixManagerRunningModeCommand, &command, 0);
1062     UnixManagerRegisterCommand("capture-mode", UnixManagerCaptureModeCommand, &command, 0);
1063     UnixManagerRegisterCommand("conf-get", UnixManagerConfGetCommand, &command, UNIX_CMD_TAKE_ARGS);
1064     UnixManagerRegisterCommand("dump-counters", StatsOutputCounterSocket, NULL, 0);
1065     UnixManagerRegisterCommand("reload-rules", UnixManagerReloadRules, NULL, 0);
1066     UnixManagerRegisterCommand("ruleset-reload-rules", UnixManagerReloadRules, NULL, 0);
1067     UnixManagerRegisterCommand("ruleset-reload-nonblocking", UnixManagerNonBlockingReloadRules, NULL, 0);
1068     UnixManagerRegisterCommand("ruleset-reload-time", UnixManagerReloadTimeCommand, NULL, 0);
1069     UnixManagerRegisterCommand("ruleset-stats", UnixManagerRulesetStatsCommand, NULL, 0);
1070     UnixManagerRegisterCommand("ruleset-failed-rules", UnixManagerShowFailedRules, NULL, 0);
1071     UnixManagerRegisterCommand("register-tenant-handler", UnixSocketRegisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1072     UnixManagerRegisterCommand("unregister-tenant-handler", UnixSocketUnregisterTenantHandler, &command, UNIX_CMD_TAKE_ARGS);
1073     UnixManagerRegisterCommand("register-tenant", UnixSocketRegisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1074     UnixManagerRegisterCommand("reload-tenant", UnixSocketReloadTenant, &command, UNIX_CMD_TAKE_ARGS);
1075     UnixManagerRegisterCommand("unregister-tenant", UnixSocketUnregisterTenant, &command, UNIX_CMD_TAKE_ARGS);
1076     UnixManagerRegisterCommand("add-hostbit", UnixSocketHostbitAdd, &command, UNIX_CMD_TAKE_ARGS);
1077     UnixManagerRegisterCommand("remove-hostbit", UnixSocketHostbitRemove, &command, UNIX_CMD_TAKE_ARGS);
1078     UnixManagerRegisterCommand("list-hostbit", UnixSocketHostbitList, &command, UNIX_CMD_TAKE_ARGS);
1079     UnixManagerRegisterCommand("reopen-log-files", UnixManagerReopenLogFiles, NULL, 0);
1080     UnixManagerRegisterCommand("memcap-set", UnixSocketSetMemcap, &command, UNIX_CMD_TAKE_ARGS);
1081     UnixManagerRegisterCommand("memcap-show", UnixSocketShowMemcap, &command, UNIX_CMD_TAKE_ARGS);
1082     UnixManagerRegisterCommand("memcap-list", UnixSocketShowAllMemcap, NULL, 0);
1083 
1084     UnixManagerRegisterCommand("dataset-add", UnixSocketDatasetAdd, &command, UNIX_CMD_TAKE_ARGS);
1085     UnixManagerRegisterCommand("dataset-remove", UnixSocketDatasetRemove, &command, UNIX_CMD_TAKE_ARGS);
1086 
1087     return 0;
1088 }
1089 
1090 typedef struct UnixManagerThreadData_ {
1091     int padding;
1092 } UnixManagerThreadData;
1093 
UnixManagerThreadInit(ThreadVars * t,const void * initdata,void ** data)1094 static TmEcode UnixManagerThreadInit(ThreadVars *t, const void *initdata, void **data)
1095 {
1096     UnixManagerThreadData *utd = SCCalloc(1, sizeof(*utd));
1097     if (utd == NULL)
1098         return TM_ECODE_FAILED;
1099 
1100     *data = utd;
1101     return TM_ECODE_OK;
1102 }
1103 
UnixManagerThreadDeinit(ThreadVars * t,void * data)1104 static TmEcode UnixManagerThreadDeinit(ThreadVars *t, void *data)
1105 {
1106     SCFree(data);
1107     return TM_ECODE_OK;
1108 }
1109 
UnixManager(ThreadVars * th_v,void * thread_data)1110 static TmEcode UnixManager(ThreadVars *th_v, void *thread_data)
1111 {
1112     int ret;
1113 
1114     /* set the thread name */
1115     SCLogDebug("%s started...", th_v->name);
1116 
1117     StatsSetupPrivate(th_v);
1118 
1119     /* Set the threads capability */
1120     th_v->cap_flags = 0;
1121     SCDropCaps(th_v);
1122 
1123     TmThreadsSetFlag(th_v, THV_INIT_DONE);
1124     while (1) {
1125         ret = UnixMain(&command);
1126         if (ret == 0) {
1127             SCLogError(SC_ERR_FATAL, "Fatal error on unix socket");
1128         }
1129 
1130         if ((ret == 0) || (TmThreadsCheckFlag(th_v, THV_KILL))) {
1131             UnixClient *item;
1132             UnixClient *titem;
1133             TAILQ_FOREACH_SAFE(item, &(&command)->clients, next, titem) {
1134                 close(item->fd);
1135                 SCFree(item);
1136             }
1137             StatsSyncCounters(th_v);
1138             break;
1139         }
1140 
1141         UnixCommandBackgroundTasks(&command);
1142     }
1143     return TM_ECODE_OK;
1144 }
1145 
1146 
1147 /** \brief Spawn the unix socket manager thread
1148  *
1149  * \param mode if set to 1, init failure cause suricata exit
1150  * */
UnixManagerThreadSpawn(int mode)1151 void UnixManagerThreadSpawn(int mode)
1152 {
1153     ThreadVars *tv_unixmgr = NULL;
1154 
1155     SCCtrlCondInit(&unix_manager_ctrl_cond, NULL);
1156     SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL);
1157 
1158     tv_unixmgr = TmThreadCreateCmdThreadByName(thread_name_unix_socket,
1159                                           "UnixManager", 0);
1160 
1161     if (tv_unixmgr == NULL) {
1162         FatalError(SC_ERR_FATAL, "TmThreadsCreate failed");
1163     }
1164     if (TmThreadSpawn(tv_unixmgr) != TM_ECODE_OK) {
1165         FatalError(SC_ERR_FATAL, "TmThreadSpawn failed");
1166     }
1167     if (mode == 1) {
1168         if (TmThreadsCheckFlag(tv_unixmgr, THV_RUNNING_DONE)) {
1169             FatalError(SC_ERR_FATAL, "Unix socket init failed");
1170         }
1171     }
1172     return;
1173 }
1174 
1175 // TODO can't think of a good name
UnixManagerThreadSpawnNonRunmode(void)1176 void UnixManagerThreadSpawnNonRunmode(void)
1177 {
1178     /* Spawn the unix socket manager thread */
1179     int unix_socket = ConfUnixSocketIsEnable();
1180     if (unix_socket == 1) {
1181         if (UnixManagerInit() == 0) {
1182             UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL,
1183                     UNIX_CMD_TAKE_ARGS);
1184             UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0);
1185             UnixManagerRegisterCommand("iface-bypassed-stat",
1186                                        LiveDeviceGetBypassedStats, NULL, 0);
1187             /* For backward compatibility */
1188             UnixManagerRegisterCommand("ebpf-bypassed-stat",
1189                                        LiveDeviceGetBypassedStats, NULL, 0);
1190             UnixManagerThreadSpawn(0);
1191         }
1192     }
1193 }
1194 
1195 /**
1196  * \brief Used to kill unix manager thread(s).
1197  *
1198  * \todo Kinda hackish since it uses the tv name to identify unix manager
1199  *       thread.  We need an all weather identification scheme.
1200  */
UnixSocketKillSocketThread(void)1201 void UnixSocketKillSocketThread(void)
1202 {
1203     ThreadVars *tv = NULL;
1204 
1205 again:
1206     SCMutexLock(&tv_root_lock);
1207 
1208     /* unix manager thread(s) is/are a part of command threads */
1209     tv = tv_root[TVT_CMD];
1210 
1211     while (tv != NULL) {
1212         if (strcasecmp(tv->name, "UnixManagerThread") == 0) {
1213             /* If the thread dies during init it will have
1214              * THV_RUNNING_DONE set, so we can set the correct flag
1215              * and exit.
1216              */
1217             if (TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
1218                 TmThreadsSetFlag(tv, THV_KILL);
1219                 TmThreadsSetFlag(tv, THV_DEINIT);
1220                 TmThreadsSetFlag(tv, THV_CLOSED);
1221                 break;
1222             }
1223             TmThreadsSetFlag(tv, THV_KILL);
1224             TmThreadsSetFlag(tv, THV_DEINIT);
1225             /* Be sure it has shut down */
1226             if (!TmThreadsCheckFlag(tv, THV_CLOSED)) {
1227                 SCMutexUnlock(&tv_root_lock);
1228                 usleep(100);
1229                 goto again;
1230             }
1231         }
1232         tv = tv->next;
1233     }
1234 
1235     SCMutexUnlock(&tv_root_lock);
1236     return;
1237 }
1238 
1239 #else /* BUILD_UNIX_SOCKET */
1240 
UnixManagerThreadSpawn(int mode)1241 void UnixManagerThreadSpawn(int mode)
1242 {
1243     SCLogError(SC_ERR_UNIMPLEMENTED, "Unix socket is not compiled");
1244     return;
1245 }
1246 
UnixSocketKillSocketThread(void)1247 void UnixSocketKillSocketThread(void)
1248 {
1249     return;
1250 }
1251 
UnixManagerThreadSpawnNonRunmode(void)1252 void UnixManagerThreadSpawnNonRunmode(void)
1253 {
1254     return;
1255 }
1256 
1257 #endif /* BUILD_UNIX_SOCKET */
1258 
TmModuleUnixManagerRegister(void)1259 void TmModuleUnixManagerRegister (void)
1260 {
1261 #if defined(BUILD_UNIX_SOCKET) && defined(HAVE_SYS_UN_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H)
1262     tmm_modules[TMM_UNIXMANAGER].name = "UnixManager";
1263     tmm_modules[TMM_UNIXMANAGER].ThreadInit = UnixManagerThreadInit;
1264     tmm_modules[TMM_UNIXMANAGER].ThreadDeinit = UnixManagerThreadDeinit;
1265     tmm_modules[TMM_UNIXMANAGER].Management = UnixManager;
1266     tmm_modules[TMM_UNIXMANAGER].cap_flags = 0;
1267     tmm_modules[TMM_UNIXMANAGER].flags = TM_FLAG_COMMAND_TM;
1268 #endif /* BUILD_UNIX_SOCKET */
1269 }
1270