new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_execd / execd.c
old mode 100755 (executable)
new mode 100644 (file)
index 15fc42c..0aadaec
@@ -1,6 +1,3 @@
-/* @(#) $Id: ./src/os_execd/execd.c, 2011/09/08 dcid Exp $
- */
-
 /* Copyright (C) 2009 Trend Micro Inc.
  * All right reserved.
  *
  * Foundation
  */
 
-
-
 #include "shared.h"
 #include "list_op.h"
 #include "os_regex/os_regex.h"
 #include "os_net/os_net.h"
-
 #include "execd.h"
 
+int repeated_offenders_timeout[] = {0, 0, 0, 0, 0, 0, 0};
 
+#ifndef WIN32
 
-/* Timeout data structure */
-typedef struct _timeout_data
-{
-    time_t time_of_addition;
-    int time_to_block;
-    char **command;
-}timeout_data;
-
+/* Prototypes */
+static void help_execd(void) __attribute__((noreturn));
+static void execd_shutdown(int sig) __attribute__((noreturn));
+static void ExecdStart(int q) __attribute__((noreturn));
 
-/* Timeout list */
-OSList *timeout_list;
-OSListNode *timeout_node;
-OSHash *repeated_hash;
-int repeated_offenders_timeout[] = {0,0,0,0,0,0,0};
+/* Global variables */
+static OSList *timeout_list;
+static OSListNode *timeout_node;
+static OSHash *repeated_hash;
 
 
+/* Print help statement */
+static void help_execd()
+{
+    print_header();
+    print_out("  %s: -[Vhdtf] [-g group] [-c config]", ARGV0);
+    print_out("    -V          Version and license message");
+    print_out("    -h          This help message");
+    print_out("    -d          Execute in debug mode. This parameter");
+    print_out("                can be specified multiple times");
+    print_out("                to increase the debug level.");
+    print_out("    -t          Test configuration");
+    print_out("    -f          Run in foreground");
+    print_out("    -g <group>  Group to run as (default: %s)", GROUPGLOBAL);
+    print_out("    -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
+    print_out(" ");
+    exit(1);
+}
 
-/**
- * Shutdowns execd properly.
- */
-void execd_shutdown()
+/* Shut down execd properly */
+static void execd_shutdown(int sig)
 {
-    /* Removing pending active responses. */
+    int status;
+
+    /* Remove pending active responses */
     merror(EXEC_SHUTDOWN, ARGV0);
 
     timeout_node = OSList_GetFirstNode(timeout_list);
-    while(timeout_node)
-    {
+    while (timeout_node) {
         timeout_data *list_entry;
 
         list_entry = (timeout_data *)timeout_node->data;
 
         ExecCmd(list_entry->command);
+        wait(&status);
 
-        /* Delete currently node - already sets the pointer to next */
+        /* Delete current node - already sets the pointer to next */
         OSList_DeleteCurrentlyNode(timeout_list);
         timeout_node = OSList_GetCurrentlyNode(timeout_list);
     }
 
-    #ifndef WIN32
-    HandleSIG();
-    #endif
-
+    HandleSIG(sig);
 }
 
-
-#ifndef WIN32
-
-/** int main(int argc, char **argv) v0.1
- */
 int main(int argc, char **argv)
 {
     int c;
-    int test_config = 0,run_foreground = 0;
-    int gid = 0,m_queue = 0;
-
-    // TODO: delete or implement
-    char *dir __attribute__((unused)) = DEFAULTDIR;
-    char *group = GROUPGLOBAL;
-    // TODO: delete or implement
-    char *cfg __attribute__((unused)) = DEFAULTARPATH;
-    char *xmlcfg = DEFAULTCPATH;
+    int test_config = 0, run_foreground = 0;
+    gid_t gid;
+    int m_queue = 0;
 
+    const char *group = GROUPGLOBAL;
+    const char *cfg = DEFAULTCPATH;
 
-    /* Setting the name */
+    /* Set the name */
     OS_SetName(ARGV0);
 
-
-    while((c = getopt(argc, argv, "Vtdhfu:g:D:c:")) != -1){
-        switch(c){
+    while ((c = getopt(argc, argv, "Vtdhfg:c:")) != -1) {
+        switch (c) {
             case 'V':
                 print_version();
                 break;
             case 'h':
-                help(ARGV0);
+                help_execd();
                 break;
             case 'd':
                 nowDebug();
@@ -104,122 +99,99 @@ int main(int argc, char **argv)
                 run_foreground = 1;
                 break;
             case 'g':
-                if(!optarg)
-                    ErrorExit("%s: -g needs an argument.",ARGV0);
+                if (!optarg) {
+                    ErrorExit("%s: -g needs an argument.", ARGV0);
+                }
                 group = optarg;
                 break;
-            case 'D':
-                if(!optarg)
-                    ErrorExit("%s: -D needs an argument.",ARGV0);
-                dir = optarg;
-                break;
             case 'c':
-                if(!optarg)
-                    ErrorExit("%s: -c needs an argument.",ARGV0);
+                if (!optarg) {
+                    ErrorExit("%s: -c needs an argument.", ARGV0);
+                }
                 cfg = optarg;
                 break;
             case 't':
                 test_config = 1;
                 break;
             default:
-                help(ARGV0);
+                help_execd();
                 break;
         }
-
     }
 
-
-
-    /* Check if the group given are valid */
+    /* Check if the group given is valid */
     gid = Privsep_GetGroup(group);
-    if(gid < 0)
-        ErrorExit(USER_ERROR,ARGV0,"",group);
-
+    if (gid == (gid_t) - 1) {
+        ErrorExit(USER_ERROR, ARGV0, "", group);
+    }
 
     /* Privilege separation */
-    if(Privsep_SetGroup(gid) < 0)
-        ErrorExit(SETGID_ERROR,ARGV0,group);
-
-
-    /* Reading config */
-    if((c = ExecdConfig(xmlcfg)) < 0)
-    {
-        ErrorExit(CONFIG_ERROR, ARGV0, xmlcfg);
+    if (Privsep_SetGroup(gid) < 0) {
+        ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
     }
 
+    /* Read config */
+    if ((c = ExecdConfig(cfg)) < 0) {
+        ErrorExit(CONFIG_ERROR, ARGV0, cfg);
+    }
 
     /* Exit if test_config */
-    if(test_config)
+    if (test_config) {
         exit(0);
-
+    }
 
     /* Signal manipulation */
     StartSIG2(ARGV0, execd_shutdown);
 
-
-    if (!run_foreground)
-    {
+    if (!run_foreground) {
         /* Going daemon */
         nowDaemon();
         goDaemon();
     }
 
-
     /* Active response disabled */
-    if(c == 1)
-    {
+    if (c == 1) {
         verbose(EXEC_DISABLED, ARGV0);
         exit(0);
     }
 
-    /* Creating the PID file */
-    if(CreatePID(ARGV0, getpid()) < 0)
+    /* Create the PID file */
+    if (CreatePID(ARGV0, getpid()) < 0) {
         merror(PID_ERROR, ARGV0);
+    }
 
-
-    /* Starting queue (exec queue) */
-    if((m_queue = StartMQ(EXECQUEUEPATH,READ)) < 0)
+    /* Start exec queue */
+    if ((m_queue = StartMQ(EXECQUEUEPATH, READ)) < 0) {
         ErrorExit(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
-
+    }
 
     /* Start up message */
     verbose(STARTUP_MSG, ARGV0, (int)getpid());
 
-
     /* The real daemon Now */
     ExecdStart(m_queue);
 
     exit(0);
 }
 
-
 #endif
 
-
-
-/** void FreeTimeoutEntry(timeout_data *timeout_entry) v0.1
- * Free the timeout entry. Must be called after popping it
- * from the timeout list
+/* Free the timeout entry
+ * Must be called after popping it from the timeout list
  */
-void FreeTimeoutEntry(void *timeout_entry_pt)
+void FreeTimeoutEntry(timeout_data *timeout_entry)
 {
-    timeout_data *timeout_entry;
     char **tmp_str;
 
-    timeout_entry = (timeout_data *)timeout_entry_pt;
-
-    if(!timeout_entry)
-    {
+    if (!timeout_entry) {
         return;
     }
 
     tmp_str = timeout_entry->command;
 
-    /* Clearing the command arguments */
-    if(tmp_str)
-    {
-        while(*tmp_str)
-        {
+    /* Clear the command arguments */
+    if (tmp_str) {
+        while (*tmp_str) {
             os_free(*tmp_str);
             *tmp_str = NULL;
             tmp_str++;
@@ -228,20 +200,13 @@ void FreeTimeoutEntry(void *timeout_entry_pt)
         timeout_entry->command = NULL;
     }
 
-    os_free(timeout_entry);
-    timeout_entry = NULL;
-
-    return;
+    free(timeout_entry);
 }
 
-
 #ifndef WIN32
 
-
-/** void ExecdStart(int q) v0.2
- * Main function on the execd. Does all the data receiving ,etc.
- */
-void ExecdStart(int q)
+/* Main function on the execd. Does all the data receiving, etc. */
+static void ExecdStart(int q)
 {
     int i, childcount = 0;
     time_t curr_time;
@@ -250,190 +215,147 @@ void ExecdStart(int q)
     char *tmp_msg = NULL;
     char *name;
     char *command;
-    char *cmd_args[MAX_ARGS +2];
-
+    char *cmd_args[MAX_ARGS + 2];
 
     /* Select */
     fd_set fdset;
     struct timeval socket_timeout;
 
+    /* Clear the buffer */
+    memset(buffer, '\0', OS_MAXSTR + 1);
 
-    /* Clearing the buffer */
-    memset(buffer, '\0', OS_MAXSTR +1);
-
-
-    /* Initializing the cmd arguments */
-    for(i = 0; i<= MAX_ARGS +1; i++)
-    {
+    /* Initialize the cmd arguments */
+    for (i = 0; i <= MAX_ARGS + 1; i++) {
         cmd_args[i] = NULL;
     }
 
-
-    /* Creating list for timeout */
+    /* Create list for timeout */
     timeout_list = OSList_Create();
-    if(!timeout_list)
-    {
+    if (!timeout_list) {
         ErrorExit(LIST_ERROR, ARGV0);
     }
 
-
-    if(repeated_offenders_timeout[0] != 0)
-    {
+    if (repeated_offenders_timeout[0] != 0) {
         repeated_hash = OSHash_Create();
-    }
-    else
-    {
+    } else {
         repeated_hash = NULL;
     }
 
-
-
-    /* Main loop. */
-    while(1)
-    {
+    /* Main loop */
+    while (1) {
         int timeout_value;
         int added_before = 0;
-
         char **timeout_args;
         timeout_data *timeout_entry;
 
-
-        /* Cleaning up any child. */
-        while (childcount)
-        {
+        /* Clean up any children */
+        while (childcount) {
             int wp;
-            wp = waitpid((pid_t) -1, NULL, WNOHANG);
-            if (wp < 0)
-            {
-                merror(WAITPID_ERROR, ARGV0);
+            wp = waitpid((pid_t) - 1, NULL, WNOHANG);
+            if (wp < 0) {
+                merror(WAITPID_ERROR, ARGV0, errno, strerror(errno));
                 break;
             }
 
             /* if = 0, we still need to wait for the child process */
-            else if (wp == 0)
-            {
+            else if (wp == 0) {
                 break;
             }
             /* Child completed if wp > 0 */
-            else
-            {
+            else {
                 childcount--;
             }
         }
 
-
-        /* Getting currently time */
+        /* Get current time */
         curr_time = time(0);
 
-
-        /* Checking if there is any timeouted command to execute. */
+        /* Check if there is any timed out command to execute */
         timeout_node = OSList_GetFirstNode(timeout_list);
-        while(timeout_node)
-        {
+        while (timeout_node) {
             timeout_data *list_entry;
 
             list_entry = (timeout_data *)timeout_node->data;
 
-            /* Timeouted */
-            if((curr_time - list_entry->time_of_addition) >
-                    list_entry->time_to_block)
-            {
+            /* Timed out */
+            if ((curr_time - list_entry->time_of_addition) >
+                    list_entry->time_to_block) {
                 ExecCmd(list_entry->command);
 
-                /* Deletecurrently node already sets the pointer to next */
+                /* Delete current node - already sets the pointer to next */
                 OSList_DeleteCurrentlyNode(timeout_list);
                 timeout_node = OSList_GetCurrentlyNode(timeout_list);
 
-                /* Clearing the memory */
+                /* Clear the memory */
                 FreeTimeoutEntry(list_entry);
 
                 childcount++;
-            }
-
-            else
-            {
+            } else {
                 timeout_node = OSList_GetNextNode(timeout_list);
             }
         }
 
-
-        /* Setting timeout to EXECD_TIMEOUT */
+        /* Set timeout to EXECD_TIMEOUT */
         socket_timeout.tv_sec = EXECD_TIMEOUT;
-        socket_timeout.tv_usec= 0;
-
+        socket_timeout.tv_usec = 0;
 
-
-        /* Setting FD values */
+        /* Set FD values */
         FD_ZERO(&fdset);
         FD_SET(q, &fdset);
 
-        /* Adding timeout */
-        if(select(q+1, &fdset, NULL, NULL, &socket_timeout) == 0)
-        {
-            /* Timeout .. */
+        /* Add timeout */
+        if (select(q + 1, &fdset, NULL, NULL, &socket_timeout) == 0) {
+            /* Timeout */
             continue;
         }
 
-
-        /* Checking for error */
-        if(!FD_ISSET(q, &fdset))
-        {
-            merror(SELECT_ERROR, ARGV0);
+        /* Check for error */
+        if (!FD_ISSET(q, &fdset)) {
+            merror(SELECT_ERROR, ARGV0, errno, strerror(errno));
             continue;
         }
 
-
-        /* Receiving the message */
-        if(recv(q, buffer, OS_MAXSTR, 0) == -1)
-        {
+        /* Receive the message */
+        if (OS_RecvUnix(q, OS_MAXSTR, buffer) == 0) {
             merror(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
             continue;
         }
 
-
-        /* Currently time */
+        /* Current time */
         curr_time = time(0);
 
-
-        /* Getting application name */
+        /* Get application name */
         name = buffer;
 
-
-        /* Zeroing the name */
+        /* Zero the name */
         tmp_msg = strchr(buffer, ' ');
-        if(!tmp_msg)
-        {
+        if (!tmp_msg) {
             merror(EXECD_INV_MSG, ARGV0, buffer);
             continue;
         }
         *tmp_msg = '\0';
         tmp_msg++;
 
-
-        /* Getting the command to execute (valid name) */
+        /* Get the command to execute (valid name) */
         command = GetCommandbyName(name, &timeout_value);
-        if(!command)
-        {
+        if (!command) {
             ReadExecConfig();
             command = GetCommandbyName(name, &timeout_value);
-            if(!command)
-            {
+            if (!command) {
                 merror(EXEC_INV_NAME, ARGV0, name);
                 continue;
             }
         }
 
-
-        /* Command not present. */
-        if(command[0] == '\0')
+        /* Command not present */
+        if (command[0] == '\0') {
             continue;
+        }
 
+        /* Allocate memory for the timeout argument */
+        os_calloc(MAX_ARGS + 2, sizeof(char *), timeout_args);
 
-        /* Allocating memory for the timeout argument */
-        os_calloc(MAX_ARGS+2, sizeof(char *), timeout_args);
-
-
-        /* Adding initial variables to the cmd_arg and to the timeout cmd */
+        /* Add initial variables to the cmd_arg and to the timeout cmd */
         cmd_args[0] = command;
         cmd_args[1] = ADD_ENTRY;
         os_strdup(command, timeout_args[0]);
@@ -442,93 +364,77 @@ void ExecdStart(int q)
         cmd_args[2] = NULL;
         timeout_args[2] = NULL;
 
-
-        /* Getting the arguments. */
+        /* Get the arguments */
         i = 2;
-        while(i < (MAX_ARGS -1))
-        {
+        while (i < (MAX_ARGS - 1)) {
             cmd_args[i] = tmp_msg;
-            cmd_args[i+1] = NULL;
+            cmd_args[i + 1] = NULL;
 
             tmp_msg = strchr(tmp_msg, ' ');
-            if(!tmp_msg)
-            {
+            if (!tmp_msg) {
                 timeout_args[i] = strdup(cmd_args[i]);
-                timeout_args[i+1] = NULL;
+                timeout_args[i + 1] = NULL;
                 break;
             }
             *tmp_msg = '\0';
             tmp_msg++;
 
             timeout_args[i] = strdup(cmd_args[i]);
-            timeout_args[i+1] = NULL;
+            timeout_args[i + 1] = NULL;
 
             i++;
         }
 
-
-        /* Check this command was already executed. */
+        /* Check if this command was already executed */
         timeout_node = OSList_GetFirstNode(timeout_list);
         added_before = 0;
 
-
-        /* Checking for the username and ip argument */
-        if(!timeout_args[2] || !timeout_args[3])
-        {
+        /* Check for the username and IP argument */
+        if (!timeout_args[2] || !timeout_args[3]) {
             added_before = 1;
             merror("%s: Invalid number of arguments.", ARGV0);
         }
 
-
-
-        while(timeout_node)
-        {
+        while (timeout_node) {
             timeout_data *list_entry;
 
             list_entry = (timeout_data *)timeout_node->data;
-            if((strcmp(list_entry->command[3], timeout_args[3]) == 0) &&
-               (strcmp(list_entry->command[0], timeout_args[0]) == 0))
-            {
+            if ((strcmp(list_entry->command[3], timeout_args[3]) == 0) &&
+                    (strcmp(list_entry->command[0], timeout_args[0]) == 0)) {
                 /* Means we executed this command before
-                 * and we don't need to add it again.
+                 * and we don't need to add it again
                  */
                 added_before = 1;
 
-
-                /* updating the timeout */
+                /* Update the timeout */
                 list_entry->time_of_addition = curr_time;
 
-                if(repeated_offenders_timeout[0] != 0 &&
-                   repeated_hash != NULL &&
-                   strncmp(timeout_args[3],"-", 1) != 0)
-                {
+                if (repeated_offenders_timeout[0] != 0 &&
+                        repeated_hash != NULL &&
+                        strncmp(timeout_args[3], "-", 1) != 0) {
                     char *ntimes = NULL;
                     char rkey[256];
                     rkey[255] = '\0';
                     snprintf(rkey, 255, "%s%s", list_entry->command[0],
-                                                timeout_args[3]);
+                             timeout_args[3]);
 
-                    if((ntimes = OSHash_Get(repeated_hash, rkey)))
-                    {
+                    if ((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) {
                         int ntimes_int = 0;
                         int i2 = 0;
                         int new_timeout = 0;
                         ntimes_int = atoi(ntimes);
-                        while(repeated_offenders_timeout[i2] != 0)
-                        {
+                        while (repeated_offenders_timeout[i2] != 0) {
                             i2++;
                         }
-                        if(ntimes_int >= i2)
-                        {
-                            new_timeout = repeated_offenders_timeout[i2 - 1]*60;
-                        }
-                        else
-                        {
+                        if (ntimes_int >= i2) {
+                            new_timeout = repeated_offenders_timeout[i2 - 1] * 60;
+                        } else {
+                            free(ntimes);       /* In hash_op.c, data belongs to caller */
                             os_calloc(10, sizeof(char), ntimes);
-                            new_timeout = repeated_offenders_timeout[ntimes_int]*60;
+                            new_timeout = repeated_offenders_timeout[ntimes_int] * 60;
                             ntimes_int++;
                             snprintf(ntimes, 9, "%d", ntimes_int);
-                            OSHash_Update(repeated_hash,rkey,ntimes);
+                            OSHash_Update(repeated_hash, rkey, ntimes);
                         }
                         list_entry->time_to_block = new_timeout;
                     }
@@ -540,79 +446,63 @@ void ExecdStart(int q)
             timeout_node = OSList_GetNextNode(timeout_list);
         }
 
-
         /* If it wasn't added before, do it now */
-        if(!added_before)
-        {
-            /* executing command */
+        if (!added_before) {
+            /* Execute command */
             ExecCmd(cmd_args);
 
             /* We don't need to add to the list if the timeout_value == 0 */
-            if(timeout_value)
-            {
+            if (timeout_value) {
                 char *ntimes;
                 char rkey[256];
                 rkey[255] = '\0';
                 snprintf(rkey, 255, "%s%s", timeout_args[0],
-                                            timeout_args[3]);
-
-                if(repeated_hash != NULL)
-                {
-                  if((ntimes = OSHash_Get(repeated_hash, rkey)))
-                  {
-                    int ntimes_int = 0;
-                    int i2 = 0;
-                    int new_timeout = 0;
-
-                    ntimes_int = atoi(ntimes);
-                    while(repeated_offenders_timeout[i2] != 0)
-                    {
-                        i2++;
-                    }
-                    if(ntimes_int >= i2)
-                    {
-                        new_timeout = repeated_offenders_timeout[i2 - 1]*60;
-                    }
-                    else
-                    {
-                        os_calloc(10, sizeof(char), ntimes);
-                        new_timeout = repeated_offenders_timeout[ntimes_int]*60;
-                        ntimes_int++;
-                        snprintf(ntimes, 9, "%d", ntimes_int);
-                        OSHash_Update(repeated_hash, rkey, ntimes);
+                         timeout_args[3]);
+
+                if (repeated_hash != NULL) {
+                    if ((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) {
+                        int ntimes_int = 0;
+                        int i2 = 0;
+                        int new_timeout = 0;
+
+                        ntimes_int = atoi(ntimes);
+                        while (repeated_offenders_timeout[i2] != 0) {
+                            i2++;
+                        }
+                        if (ntimes_int >= i2) {
+                            new_timeout = repeated_offenders_timeout[i2 - 1] * 60;
+                        } else {
+                            os_calloc(10, sizeof(char), ntimes);
+                            new_timeout = repeated_offenders_timeout[ntimes_int] * 60;
+                            ntimes_int++;
+                            snprintf(ntimes, 9, "%d", ntimes_int);
+                            OSHash_Update(repeated_hash, rkey, ntimes);
+                        }
+                        timeout_value = new_timeout;
+                    } else {
+                        /* Add to the repeat offenders list */
+                        OSHash_Add(repeated_hash,
+                                   rkey, strdup("0"));
                     }
-                    timeout_value = new_timeout;
-                  }
-                  else
-                  {
-                      /* Adding to the repeated offenders list. */
-                      OSHash_Add(repeated_hash,
-                           strdup(rkey),strdup("0"));
-                  }
                 }
 
-
-                /* Creating the timeout entry */
+                /* Create the timeout entry */
                 os_calloc(1, sizeof(timeout_data), timeout_entry);
                 timeout_entry->command = timeout_args;
                 timeout_entry->time_of_addition = curr_time;
                 timeout_entry->time_to_block = timeout_value;
 
-
-                /* Adding command to the timeout list */
-                if(!OSList_AddData(timeout_list, timeout_entry))
-                {
+                /* Add command to the timeout list */
+                if (!OSList_AddData(timeout_list, timeout_entry)) {
                     merror(LIST_ADD_ERROR, ARGV0);
                     FreeTimeoutEntry(timeout_entry);
                 }
             }
 
             /* If no timeout, we still need to free it in here */
-            else
-            {
+            else {
                 char **ss_ta = timeout_args;
-                while(*timeout_args)
-                {
+                while (*timeout_args) {
                     os_free(*timeout_args);
                     *timeout_args = NULL;
                     timeout_args++;
@@ -624,13 +514,11 @@ void ExecdStart(int q)
         }
 
         /* We didn't add it to the timeout list */
-        else
-        {
+        else {
             char **ss_ta = timeout_args;
 
             /* Clear the timeout arguments */
-            while(*timeout_args)
-            {
+            while (*timeout_args) {
                 os_free(*timeout_args);
                 *timeout_args = NULL;
                 timeout_args++;
@@ -640,15 +528,12 @@ void ExecdStart(int q)
         }
 
         /* Some cleanup */
-        while(i > 0)
-        {
+        while (i > 0) {
             cmd_args[i] = NULL;
             i--;
         }
     }
 }
 
+#endif /* !WIN32 */
 
-#endif
-
-/* EOF */