1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
12 #include "os_regex/os_regex.h"
13 #include "os_net/os_net.h"
16 int repeated_offenders_timeout[] = {0, 0, 0, 0, 0, 0, 0};
21 static void help_execd(void) __attribute__((noreturn));
22 static void execd_shutdown(int sig) __attribute__((noreturn));
23 static void ExecdStart(int q) __attribute__((noreturn));
25 /* Global variables */
26 static OSList *timeout_list;
27 static OSListNode *timeout_node;
28 static OSHash *repeated_hash;
31 /* Print help statement */
32 static void help_execd()
35 print_out(" %s: -[Vhdtf] [-g group] [-c config]", ARGV0);
36 print_out(" -V Version and license message");
37 print_out(" -h This help message");
38 print_out(" -d Execute in debug mode. This parameter");
39 print_out(" can be specified multiple times");
40 print_out(" to increase the debug level.");
41 print_out(" -t Test configuration");
42 print_out(" -f Run in foreground");
43 print_out(" -g <group> Group to run as (default: %s)", GROUPGLOBAL);
44 print_out(" -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
49 /* Shut down execd properly */
50 static void execd_shutdown(int sig)
54 /* Remove pending active responses */
55 merror(EXEC_SHUTDOWN, ARGV0);
57 timeout_node = OSList_GetFirstNode(timeout_list);
58 while (timeout_node) {
59 timeout_data *list_entry;
61 list_entry = (timeout_data *)timeout_node->data;
63 ExecCmd(list_entry->command);
66 /* Delete current node - already sets the pointer to next */
67 OSList_DeleteCurrentlyNode(timeout_list);
68 timeout_node = OSList_GetCurrentlyNode(timeout_list);
74 int main(int argc, char **argv)
77 int test_config = 0, run_foreground = 0;
81 const char *group = GROUPGLOBAL;
82 const char *cfg = DEFAULTCPATH;
87 while ((c = getopt(argc, argv, "Vtdhfg:c:")) != -1) {
103 ErrorExit("%s: -g needs an argument.", ARGV0);
109 ErrorExit("%s: -c needs an argument.", ARGV0);
122 /* Check if the group given is valid */
123 gid = Privsep_GetGroup(group);
124 if (gid == (gid_t) - 1) {
125 ErrorExit(USER_ERROR, ARGV0, "", group);
128 /* Privilege separation */
129 if (Privsep_SetGroup(gid) < 0) {
130 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
134 if ((c = ExecdConfig(cfg)) < 0) {
135 ErrorExit(CONFIG_ERROR, ARGV0, cfg);
138 /* Exit if test_config */
143 /* Signal manipulation */
144 StartSIG2(ARGV0, execd_shutdown);
146 if (!run_foreground) {
152 /* Active response disabled */
154 verbose(EXEC_DISABLED, ARGV0);
158 /* Create the PID file */
159 if (CreatePID(ARGV0, getpid()) < 0) {
160 merror(PID_ERROR, ARGV0);
163 /* Start exec queue */
164 if ((m_queue = StartMQ(EXECQUEUEPATH, READ)) < 0) {
165 ErrorExit(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
168 /* Start up message */
169 verbose(STARTUP_MSG, ARGV0, (int)getpid());
171 /* The real daemon Now */
179 /* Free the timeout entry
180 * Must be called after popping it from the timeout list
182 void FreeTimeoutEntry(timeout_data *timeout_entry)
186 if (!timeout_entry) {
190 tmp_str = timeout_entry->command;
192 /* Clear the command arguments */
199 os_free(timeout_entry->command);
200 timeout_entry->command = NULL;
208 /* Main function on the execd. Does all the data receiving, etc. */
209 static void ExecdStart(int q)
211 int i, childcount = 0;
214 char buffer[OS_MAXSTR + 1];
215 char *tmp_msg = NULL;
218 char *cmd_args[MAX_ARGS + 2];
222 struct timeval socket_timeout;
224 /* Clear the buffer */
225 memset(buffer, '\0', OS_MAXSTR + 1);
227 /* Initialize the cmd arguments */
228 for (i = 0; i <= MAX_ARGS + 1; i++) {
232 /* Create list for timeout */
233 timeout_list = OSList_Create();
235 ErrorExit(LIST_ERROR, ARGV0);
238 if (repeated_offenders_timeout[0] != 0) {
239 repeated_hash = OSHash_Create();
241 repeated_hash = NULL;
247 int added_before = 0;
249 timeout_data *timeout_entry;
251 /* Clean up any children */
254 wp = waitpid((pid_t) - 1, NULL, WNOHANG);
256 merror(WAITPID_ERROR, ARGV0, errno, strerror(errno));
260 /* if = 0, we still need to wait for the child process */
264 /* Child completed if wp > 0 */
270 /* Get current time */
273 /* Check if there is any timed out command to execute */
274 timeout_node = OSList_GetFirstNode(timeout_list);
275 while (timeout_node) {
276 timeout_data *list_entry;
278 list_entry = (timeout_data *)timeout_node->data;
281 if ((curr_time - list_entry->time_of_addition) >
282 list_entry->time_to_block) {
283 ExecCmd(list_entry->command);
285 /* Delete current node - already sets the pointer to next */
286 OSList_DeleteCurrentlyNode(timeout_list);
287 timeout_node = OSList_GetCurrentlyNode(timeout_list);
289 /* Clear the memory */
290 FreeTimeoutEntry(list_entry);
294 timeout_node = OSList_GetNextNode(timeout_list);
298 /* Set timeout to EXECD_TIMEOUT */
299 socket_timeout.tv_sec = EXECD_TIMEOUT;
300 socket_timeout.tv_usec = 0;
307 if (select(q + 1, &fdset, NULL, NULL, &socket_timeout) == 0) {
312 /* Check for error */
313 if (!FD_ISSET(q, &fdset)) {
314 merror(SELECT_ERROR, ARGV0, errno, strerror(errno));
318 /* Receive the message */
319 if (OS_RecvUnix(q, OS_MAXSTR, buffer) == 0) {
320 merror(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
327 /* Get application name */
331 tmp_msg = strchr(buffer, ' ');
333 merror(EXECD_INV_MSG, ARGV0, buffer);
339 /* Get the command to execute (valid name) */
340 command = GetCommandbyName(name, &timeout_value);
343 command = GetCommandbyName(name, &timeout_value);
345 merror(EXEC_INV_NAME, ARGV0, name);
350 /* Command not present */
351 if (command[0] == '\0') {
355 /* Allocate memory for the timeout argument */
356 os_calloc(MAX_ARGS + 2, sizeof(char *), timeout_args);
358 /* Add initial variables to the cmd_arg and to the timeout cmd */
359 cmd_args[0] = command;
360 cmd_args[1] = ADD_ENTRY;
361 os_strdup(command, timeout_args[0]);
362 os_strdup(DELETE_ENTRY, timeout_args[1]);
365 timeout_args[2] = NULL;
367 /* Get the arguments */
369 while (i < (MAX_ARGS - 1)) {
370 cmd_args[i] = tmp_msg;
371 cmd_args[i + 1] = NULL;
373 tmp_msg = strchr(tmp_msg, ' ');
375 timeout_args[i] = strdup(cmd_args[i]);
376 timeout_args[i + 1] = NULL;
382 timeout_args[i] = strdup(cmd_args[i]);
383 timeout_args[i + 1] = NULL;
388 /* Check if this command was already executed */
389 timeout_node = OSList_GetFirstNode(timeout_list);
392 /* Check for the username and IP argument */
393 if (!timeout_args[2] || !timeout_args[3]) {
395 merror("%s: Invalid number of arguments.", ARGV0);
398 while (timeout_node) {
399 timeout_data *list_entry;
401 list_entry = (timeout_data *)timeout_node->data;
402 if ((strcmp(list_entry->command[3], timeout_args[3]) == 0) &&
403 (strcmp(list_entry->command[0], timeout_args[0]) == 0)) {
404 /* Means we executed this command before
405 * and we don't need to add it again
409 /* Update the timeout */
410 list_entry->time_of_addition = curr_time;
412 if (repeated_offenders_timeout[0] != 0 &&
413 repeated_hash != NULL &&
414 strncmp(timeout_args[3], "-", 1) != 0) {
418 snprintf(rkey, 255, "%s%s", list_entry->command[0],
421 if ((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) {
425 ntimes_int = atoi(ntimes);
426 while (repeated_offenders_timeout[i2] != 0) {
429 if (ntimes_int >= i2) {
430 new_timeout = repeated_offenders_timeout[i2 - 1] * 60;
432 free(ntimes); /* In hash_op.c, data belongs to caller */
433 os_calloc(10, sizeof(char), ntimes);
434 new_timeout = repeated_offenders_timeout[ntimes_int] * 60;
436 snprintf(ntimes, 9, "%d", ntimes_int);
437 OSHash_Update(repeated_hash, rkey, ntimes);
439 list_entry->time_to_block = new_timeout;
445 /* Continue with the next entry in timeout list*/
446 timeout_node = OSList_GetNextNode(timeout_list);
449 /* If it wasn't added before, do it now */
451 /* Execute command */
454 /* We don't need to add to the list if the timeout_value == 0 */
459 snprintf(rkey, 255, "%s%s", timeout_args[0],
462 if (repeated_hash != NULL) {
463 if ((ntimes = (char *) OSHash_Get(repeated_hash, rkey))) {
468 ntimes_int = atoi(ntimes);
469 while (repeated_offenders_timeout[i2] != 0) {
472 if (ntimes_int >= i2) {
473 new_timeout = repeated_offenders_timeout[i2 - 1] * 60;
475 os_calloc(10, sizeof(char), ntimes);
476 new_timeout = repeated_offenders_timeout[ntimes_int] * 60;
478 snprintf(ntimes, 9, "%d", ntimes_int);
479 OSHash_Update(repeated_hash, rkey, ntimes);
481 timeout_value = new_timeout;
483 /* Add to the repeat offenders list */
484 OSHash_Add(repeated_hash,
489 /* Create the timeout entry */
490 os_calloc(1, sizeof(timeout_data), timeout_entry);
491 timeout_entry->command = timeout_args;
492 timeout_entry->time_of_addition = curr_time;
493 timeout_entry->time_to_block = timeout_value;
495 /* Add command to the timeout list */
496 if (!OSList_AddData(timeout_list, timeout_entry)) {
497 merror(LIST_ADD_ERROR, ARGV0);
498 FreeTimeoutEntry(timeout_entry);
502 /* If no timeout, we still need to free it in here */
504 char **ss_ta = timeout_args;
505 while (*timeout_args) {
506 os_free(*timeout_args);
507 *timeout_args = NULL;
516 /* We didn't add it to the timeout list */
518 char **ss_ta = timeout_args;
520 /* Clear the timeout arguments */
521 while (*timeout_args) {
522 os_free(*timeout_args);
523 *timeout_args = NULL;