# --- SDE-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # Filename: package/.../specter/specter-1.4-0003-EXEC-plugin-zombie.patch # Copyright (C) 2011 The OpenSDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- SDE-COPYRIGHT-NOTE-END --- Description: Prevent EXEC plugin from creating zombie processes Origin: Upstream (http://bazaar.launchpad.net/~ruby/specter/trunk/diff/5) === modified file 'plugins/specter_EXEC.c' --- specter-1.4/plugins/specter_EXEC.c 2008-01-06 17:26:23 +0000 +++ specter-1.4/plugins/specter_EXEC.c 2008-02-22 19:27:02 +0000 @@ -5,12 +5,12 @@ * This target executes application on packet receive, expanding few * conversion tags into values appropriate for current packet. * - * (C) 2004,2005 by Michal Kwiatkowski + * (C) 2004-2005,2008 by Michal Kwiatkowski */ /* * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 + * it 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, @@ -60,407 +60,420 @@ #endif static config_entry_t my_config[] = { - { .key = "command", .type = CONFIG_TYPE_STRING, .options = CONFIG_OPT_MANDATORY }, - { .key = "wait", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, - .u = { .value = 0 } }, - { .key = "force", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, - .u = { .value = 0 } }, - { .key = "environment", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, - .u = { .value = 0 } }, + { .key = "command", .type = CONFIG_TYPE_STRING, .options = CONFIG_OPT_MANDATORY }, + { .key = "wait", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, + .u = { .value = 0 } }, + { .key = "force", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, + .u = { .value = 0 } }, + { .key = "environment", .type = CONFIG_TYPE_BOOLEAN, .options = CONFIG_OPT_NONE, + .u = { .value = 0 } }, }; /* structure to lower number of operations during execution time */ struct arguments { - int type; - union { - char *str; - char c; - } u; + int type; + union { + char *str; + char c; + } u; }; #define ATT_FLAG 0x4 enum { - ARG_TYPE_NONE = 0x0, /* array terminator */ - ARG_TYPE_IRET = 0x1, - ARG_TYPE_STRING = 0x2, - ARG_TYPE_IRET_ATT = ARG_TYPE_IRET|ATT_FLAG, - ARG_TYPE_STRING_ATT = ARG_TYPE_STRING|ATT_FLAG, + ARG_TYPE_NONE = 0x0, /* array terminator */ + ARG_TYPE_IRET = 0x1, + ARG_TYPE_STRING = 0x2, + ARG_TYPE_IRET_ATT = ARG_TYPE_IRET|ATT_FLAG, + ARG_TYPE_STRING_ATT = ARG_TYPE_STRING|ATT_FLAG, }; struct redirection { - char file[PATH_MAX]; - int flags; + char file[PATH_MAX]; + int flags; }; struct my_data { - char execline[EXEC_MAX_LINE]; - struct arguments args[EXEC_MAX_ARGS+1]; - struct redirection stdin, stdout, stderr; - int free_command; + char execline[EXEC_MAX_LINE]; + struct arguments args[EXEC_MAX_ARGS+1]; + struct redirection stdin, stdout, stderr; + int free_command; }; /* here goes conversion stuff */ #define LOCAL_RET_NUM 10 static struct { - char name[SPECTER_IRET_NAME_LEN]; - specter_iret_t *p; - char c; + char name[SPECTER_IRET_NAME_LEN]; + specter_iret_t *p; + char c; } local_ret[LOCAL_RET_NUM] = { /* 0 */{ "oob.in", NULL, 'I' }, - { "oob.out", NULL, 'O' }, - { "ip.saddr", NULL, 'S' }, - { "ip.daddr", NULL, 'D' }, - { "ip.protocol", NULL, 'P' }, + { "oob.out", NULL, 'O' }, + { "ip.saddr", NULL, 'S' }, + { "ip.daddr", NULL, 'D' }, + { "ip.protocol", NULL, 'P' }, /* 5 */{ "tcp.sport", NULL, 's' }, - { "tcp.dport", NULL, 'd' }, - { "udp.sport", NULL, 's' }, - { "udp.dport", NULL, 'd' }, - { "icmp.type", NULL, 'i' }, + { "tcp.dport", NULL, 'd' }, + { "udp.sport", NULL, 's' }, + { "udp.dport", NULL, 'd' }, + { "icmp.type", NULL, 'i' }, }; static specter_iret_t *find_tag(const char c) { - int ctr; - specter_iret_t *iret = NULL; - - for (ctr = 0; ctr < LOCAL_RET_NUM; ctr++) - if (local_ret[ctr].c == c) { - iret = local_ret[ctr].p; - if (IS_VALID(iret)) - break; - } - - return iret; + int ctr; + specter_iret_t *iret = NULL; + + for (ctr = 0; ctr < LOCAL_RET_NUM; ctr++) + if (local_ret[ctr].c == c) { + iret = local_ret[ctr].p; + if (IS_VALID(iret)) + break; + } + + return iret; } static int fill_tag(const char c) { - int ctr; - - for (ctr = 0; ctr < LOCAL_RET_NUM; ctr++) { - if (local_ret[ctr].c == c) { - if ((local_ret[ctr].p = find_iret(local_ret[ctr].name)) != NULL) - return 0; - } - } - - return -1; + int ctr; + + for (ctr = 0; ctr < LOCAL_RET_NUM; ctr++) { + if (local_ret[ctr].c == c) { + if ((local_ret[ctr].p = find_iret(local_ret[ctr].name)) != NULL) + return 0; + } + } + + return -1; } static void check_status(char *comm, pid_t pid, int status) { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) { - specter_log(SPECTER_NOTICE, "%s[%i] returned %i.\n", - comm, pid, WEXITSTATUS(status)); - } else { - specter_log(SPECTER_DEBUG, "%s[%i] returned 0.\n", - comm, pid); - } - } else if (WIFSIGNALED(status)) { - specter_log(SPECTER_NOTICE, "%s[%i] terminated by signal #%i.\n", - comm, pid, WTERMSIG(status)); - } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status)) { + specter_log(SPECTER_NOTICE, "%s[%i] returned %i.\n", + comm, pid, WEXITSTATUS(status)); + } else { + specter_log(SPECTER_DEBUG, "%s[%i] returned 0.\n", + comm, pid); + } + } else if (WIFSIGNALED(status)) { + specter_log(SPECTER_NOTICE, "%s[%i] terminated by signal #%i.\n", + comm, pid, WTERMSIG(status)); + } } static int fill_arg(char *buff, specter_iret_t *iret, int size) { - int number = 0; - - if (!IS_VALID(iret)) { - return -1; - } - - switch (iret->type) { - case SPECTER_IRET_INT8: - number += snprintf(buff, size, "%d", iret->value.i8); - break; - case SPECTER_IRET_INT16: - number += snprintf(buff, size, "%d", iret->value.i16); - break; - case SPECTER_IRET_INT32: - number += snprintf(buff, size, "%d", iret->value.i32); - break; - case SPECTER_IRET_INT64: - number += snprintf(buff, size, "%lld", iret->value.i64); - break; - case SPECTER_IRET_UINT8: - number += snprintf(buff, size, "%u", iret->value.ui8); - break; - case SPECTER_IRET_UINT16: - number += snprintf(buff, size, "%u", iret->value.ui16); - break; - case SPECTER_IRET_UINT32: - number += snprintf(buff, size, "%u", iret->value.ui32); - break; - case SPECTER_IRET_UINT64: - number += snprintf(buff, size, "%llu", iret->value.ui64); - break; - case SPECTER_IRET_BOOL: - number += snprintf(buff, size, "%d", iret->value.b); - break; - case SPECTER_IRET_IPADDR: - { - struct in_addr ia; - char *str; - - ia.s_addr = ntohl(iret->value.ui32); - str = inet_ntoa(ia); - - if (strlen(str) > EXEC_ARG_SPACE - 1) { - specter_log(SPECTER_DEBUG, - "Address too long: %s.\n", str); - return -1; - } - strncpy(buff, str, size); - number += strlen(str); - } - break; - case SPECTER_IRET_STRING: - strncpy(buff, (char *)iret->value.ptr, size); - number += strlen((char *)iret->value.ptr); - break; - default: - specter_log(SPECTER_DEBUG, - "Unknown key type %i for \"%s\".\n", - iret->type, iret->name); - return -1; - break; - } - - return number; + int number = 0; + + if (!IS_VALID(iret)) { + return -1; + } + + switch (iret->type) { + case SPECTER_IRET_INT8: + number += snprintf(buff, size, "%d", iret->value.i8); + break; + case SPECTER_IRET_INT16: + number += snprintf(buff, size, "%d", iret->value.i16); + break; + case SPECTER_IRET_INT32: + number += snprintf(buff, size, "%d", iret->value.i32); + break; + case SPECTER_IRET_INT64: + number += snprintf(buff, size, "%lld", iret->value.i64); + break; + case SPECTER_IRET_UINT8: + number += snprintf(buff, size, "%u", iret->value.ui8); + break; + case SPECTER_IRET_UINT16: + number += snprintf(buff, size, "%u", iret->value.ui16); + break; + case SPECTER_IRET_UINT32: + number += snprintf(buff, size, "%u", iret->value.ui32); + break; + case SPECTER_IRET_UINT64: + number += snprintf(buff, size, "%llu", iret->value.ui64); + break; + case SPECTER_IRET_BOOL: + number += snprintf(buff, size, "%d", iret->value.b); + break; + case SPECTER_IRET_IPADDR: + { + struct in_addr ia; + char *str; + + ia.s_addr = ntohl(iret->value.ui32); + str = inet_ntoa(ia); + + if (strlen(str) > EXEC_ARG_SPACE - 1) { + specter_log(SPECTER_DEBUG, + "Address too long: %s.\n", str); + return -1; + } + strncpy(buff, str, size); + number += strlen(str); + } + break; + case SPECTER_IRET_STRING: + strncpy(buff, (char *)iret->value.ptr, size); + number += strlen((char *)iret->value.ptr); + break; + default: + specter_log(SPECTER_DEBUG, + "Unknown key type %i for \"%s\".\n", + iret->type, iret->name); + return -1; + break; + } + + return number; } static void exec_fini(config_entry_t *ce, void *data) { - int ret, status; - struct my_data *md = data; - - while ((ret = waitpid(-1, &status, WNOHANG)) > 0) { - check_status(md->args[0].u.str, ret, status); - } - - if (md->free_command) { - /* mallocated by strdup() in exec_init() */ - free(md->args[0].u.str); - } - - free(data); + int ret, status; + struct my_data *md = data; + + while ((ret = waitpid(-1, &status, WNOHANG)) > 0) { + check_status(md->args[0].u.str, ret, status); + } + + if (md->free_command) { + /* mallocated by strdup() in exec_init() */ + free(md->args[0].u.str); + } + + free(data); } static inline int get_word(char *dst, char *src, int size) { - int ctr = 0; - - while (*src == ' ' || *src == '\t') { - ctr++; - src++; - } - - if (*src == '\0') - return 0; - - while (*src != ' ' && *src != '\t' && *src != '\0' && ctr < size) { - *dst++ = *src++; - ctr++; - } - - return ctr; -} - + int ctr = 0; + + while (*src == ' ' || *src == '\t') { + ctr++; + src++; + } + + if (*src == '\0') + return 0; + + while (*src != ' ' && *src != '\t' && *src != '\0' && ctr < size) { + *dst++ = *src++; + ctr++; + } + + return ctr; +} + +static char *application_name = NULL; +static void sigchld_hanlder(int signal) +{ + int pid, status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + check_status(application_name, pid, status); + } +} static void *exec_init(config_entry_t *ce) { - struct my_data *data; - char *tmp, *line; - int ctr, new_arg; - struct stat st; - - if ((data = malloc(sizeof(struct my_data))) == NULL) { - specter_log(SPECTER_FATAL, "Couldn't allocate data: %s.\n", - strerror(errno)); - return NULL; - } - - memset(data, 0x0, sizeof(data)); - tmp = GET_CE(ce,0)->u.string; - line = data->execline; - ctr = 0; - new_arg = 1; - - /* divide execline into separate args */ - while (*tmp) { - if (*tmp == ' ' || *tmp == '\t') { - while (*tmp == ' ' || *tmp == '\t') - tmp++; - *line++ = '\0'; - new_arg = 1; - } else if (*tmp == '%' && *++tmp != '%') { - if (fill_tag(*tmp) == -1) { - specter_log(SPECTER_FATAL, - "Bad exec tag: \"%%%c\".\n", *tmp); - return NULL; - } - if (!new_arg) { - data->args[ctr-1].type |= ATT_FLAG; - *line++ = '\0'; - } - data->args[ctr].u.c = *tmp++; - data->args[ctr].type = ARG_TYPE_IRET; - if (++ctr == EXEC_MAX_ARGS) { - specter_log(SPECTER_FATAL, - "Command line has too many arguments.\n"); - return NULL; - } - new_arg = 0; - } else if ((*tmp == '>') || (*tmp == '1' && *(tmp+1) == '>' && tmp++)) { - int ret; - if (*++tmp == '>') { - tmp++; - data->stdout.flags = O_WRONLY|O_CREAT|O_APPEND; - } else { - data->stdout.flags = O_WRONLY|O_CREAT|O_TRUNC; - } - if ((ret = get_word(data->stdout.file, tmp, PATH_MAX)) == 0) { - specter_log(SPECTER_FATAL, "Empty filename in command " - "line stdout redirection.\n"); - return NULL; - } - tmp += ret; - new_arg = 1; - } else if (*tmp == '2' && *(tmp+1) == '>' && tmp++) { - int ret; - if (*++tmp == '>') { - tmp++; - data->stderr.flags = O_WRONLY|O_CREAT|O_APPEND; - } else { - data->stderr.flags = O_WRONLY|O_CREAT|O_TRUNC; - } - if ((ret = get_word(data->stderr.file, tmp, PATH_MAX)) == 0) { - specter_log(SPECTER_FATAL, "Empty filename in command " - "line stderr redirection.\n"); - return NULL; - } - tmp += ret; - new_arg = 1; - } else if (*tmp == '&' && *(tmp+1) == '>' && tmp++) { - int ret; - if (*++tmp == '>') { - tmp++; - data->stdout.flags = O_WRONLY|O_CREAT|O_APPEND; - data->stderr.flags = O_WRONLY|O_CREAT|O_APPEND; - } else { - data->stdout.flags = O_WRONLY|O_CREAT|O_TRUNC; - data->stderr.flags = O_WRONLY|O_CREAT|O_TRUNC; - } - if ((ret = get_word(data->stdout.file, tmp, PATH_MAX)) == 0) { - specter_log(SPECTER_FATAL, "Empty filename in command " - "line stdout redirection.\n"); - return NULL; - } - get_word(data->stderr.file, tmp, PATH_MAX); - tmp += ret; - new_arg = 1; - } else if (*tmp == '<') { - int ret; - tmp++; - data->stdin.flags = O_RDONLY; - if ((ret = get_word(data->stdin.file, tmp, PATH_MAX)) == 0) { - specter_log(SPECTER_FATAL, "Empty filename in command " - "line stdin redirection.\n"); - return NULL; - } - tmp += ret; - new_arg = 1; - } else { - if (new_arg || data->args[ctr-1].type == ARG_TYPE_IRET) { - if (!new_arg) { - data->args[ctr-1].type |= ATT_FLAG; - } - data->args[ctr].u.str = line; - data->args[ctr].type = ARG_TYPE_STRING; - if (++ctr == EXEC_MAX_ARGS) { - specter_log(SPECTER_FATAL, - "Command line has too many arguments.\n"); - return NULL; - } - new_arg = 0; - } - /* it's not a special character - rewrite it */ - *line++ = *tmp++; - } - } - - *line = '\0'; - data->args[ctr].type = ARG_TYPE_NONE; + struct my_data *data; + char *tmp, *line; + int ctr, new_arg; + struct stat st; + + if ((data = malloc(sizeof(struct my_data))) == NULL) { + specter_log(SPECTER_FATAL, "Couldn't allocate data: %s.\n", + strerror(errno)); + return NULL; + } + + memset(data, 0x0, sizeof(data)); + tmp = GET_CE(ce,0)->u.string; + line = data->execline; + ctr = 0; + new_arg = 1; + + /* divide execline into separate args */ + while (*tmp) { + if (*tmp == ' ' || *tmp == '\t') { + while (*tmp == ' ' || *tmp == '\t') + tmp++; + *line++ = '\0'; + new_arg = 1; + } else if (*tmp == '%' && *++tmp != '%') { + if (fill_tag(*tmp) == -1) { + specter_log(SPECTER_FATAL, + "Bad exec tag: \"%%%c\".\n", *tmp); + return NULL; + } + if (!new_arg) { + data->args[ctr-1].type |= ATT_FLAG; + *line++ = '\0'; + } + data->args[ctr].u.c = *tmp++; + data->args[ctr].type = ARG_TYPE_IRET; + if (++ctr == EXEC_MAX_ARGS) { + specter_log(SPECTER_FATAL, + "Command line has too many arguments.\n"); + return NULL; + } + new_arg = 0; + } else if ((*tmp == '>') || (*tmp == '1' && *(tmp+1) == '>' && tmp++)) { + int ret; + if (*++tmp == '>') { + tmp++; + data->stdout.flags = O_WRONLY|O_CREAT|O_APPEND; + } else { + data->stdout.flags = O_WRONLY|O_CREAT|O_TRUNC; + } + if ((ret = get_word(data->stdout.file, tmp, PATH_MAX)) == 0) { + specter_log(SPECTER_FATAL, "Empty filename in command " + "line stdout redirection.\n"); + return NULL; + } + tmp += ret; + new_arg = 1; + } else if (*tmp == '2' && *(tmp+1) == '>' && tmp++) { + int ret; + if (*++tmp == '>') { + tmp++; + data->stderr.flags = O_WRONLY|O_CREAT|O_APPEND; + } else { + data->stderr.flags = O_WRONLY|O_CREAT|O_TRUNC; + } + if ((ret = get_word(data->stderr.file, tmp, PATH_MAX)) == 0) { + specter_log(SPECTER_FATAL, "Empty filename in command " + "line stderr redirection.\n"); + return NULL; + } + tmp += ret; + new_arg = 1; + } else if (*tmp == '&' && *(tmp+1) == '>' && tmp++) { + int ret; + if (*++tmp == '>') { + tmp++; + data->stdout.flags = O_WRONLY|O_CREAT|O_APPEND; + data->stderr.flags = O_WRONLY|O_CREAT|O_APPEND; + } else { + data->stdout.flags = O_WRONLY|O_CREAT|O_TRUNC; + data->stderr.flags = O_WRONLY|O_CREAT|O_TRUNC; + } + if ((ret = get_word(data->stdout.file, tmp, PATH_MAX)) == 0) { + specter_log(SPECTER_FATAL, "Empty filename in command " + "line stdout redirection.\n"); + return NULL; + } + get_word(data->stderr.file, tmp, PATH_MAX); + tmp += ret; + new_arg = 1; + } else if (*tmp == '<') { + int ret; + tmp++; + data->stdin.flags = O_RDONLY; + if ((ret = get_word(data->stdin.file, tmp, PATH_MAX)) == 0) { + specter_log(SPECTER_FATAL, "Empty filename in command " + "line stdin redirection.\n"); + return NULL; + } + tmp += ret; + new_arg = 1; + } else { + if (new_arg || data->args[ctr-1].type == ARG_TYPE_IRET) { + if (!new_arg) { + data->args[ctr-1].type |= ATT_FLAG; + } + data->args[ctr].u.str = line; + data->args[ctr].type = ARG_TYPE_STRING; + if (++ctr == EXEC_MAX_ARGS) { + specter_log(SPECTER_FATAL, + "Command line has too many arguments.\n"); + return NULL; + } + new_arg = 0; + } + /* it's not a special character - rewrite it */ + *line++ = *tmp++; + } + } + + *line = '\0'; + data->args[ctr].type = ARG_TYPE_NONE; #ifdef DEBUG - for (ctr = 0; data->args[ctr].type != ARG_TYPE_NONE; ctr++) { - printf("%i: ", ctr); - if (data->args[ctr].type & ARG_TYPE_STRING) - printf("string: %s", data->args[ctr].u.str); - else - printf("tag: %c", data->args[ctr].u.c); - if (data->args[ctr].type & ATT_FLAG) - printf(" "); - printf("\n"); - } + for (ctr = 0; data->args[ctr].type != ARG_TYPE_NONE; ctr++) { + printf("%i: ", ctr); + if (data->args[ctr].type & ARG_TYPE_STRING) + printf("string: %s", data->args[ctr].u.str); + else + printf("tag: %c", data->args[ctr].u.c); + if (data->args[ctr].type & ATT_FLAG) + printf(" "); + printf("\n"); + } #endif - if (data->args[0].type != ARG_TYPE_STRING) { - specter_log(SPECTER_FATAL, "First argument of command should be a plain string.\n"); - return NULL; - } - - /* check if file exists and is an executable */ - if (stat(data->args[0].u.str, &st) == -1) { - tmp = getenv("PATH"); - while (1) { - char command[256]; - char *t = strchr(tmp, ':'); - if (t) - *t = '\0'; - - /* prepend path to given command */ - snprintf(command, 255, "%s/%s", tmp, data->args[0].u.str); - - if ((stat(command, &st) != -1) - && (st.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR)) - && (st.st_mode & S_IFREG)) { - data->args[0].u.str = strdup(command); - data->free_command = 1; - specter_log(SPECTER_DEBUG, "Command \"%s\" prepared.\n", - data->args[0].u.str); - return data; - } - - if (t) - tmp = t+1; - else - break; - } - } else { - if (!(st.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR)) || !(st.st_mode & S_IFREG)) { - specter_log(SPECTER_FATAL, "\"%s\" isn't an executable.\n", - data->args[0].u.str); - return NULL; - } else { /* everything's fine */ - specter_log(SPECTER_DEBUG, "Command \"%s\" prepared.\n", - data->args[0].u.str); - return data; - } - } - - /* strerror() will return error from last stat() */ - specter_log(SPECTER_FATAL, "Couldn't find executable \"%s\" in $PATH: %s.\n", - data->args[0].u.str, strerror(errno)); - return NULL; + if (data->args[0].type != ARG_TYPE_STRING) { + specter_log(SPECTER_FATAL, "First argument of command should be a plain string.\n"); + return NULL; + } + + /* Handle child signals right away to prevent creation of zombie processes. */ + application_name = data->args[0].u.str; + signal(SIGCHLD, &sigchld_hanlder); + + /* check if file exists and is an executable */ + if (stat(data->args[0].u.str, &st) == -1) { + tmp = getenv("PATH"); + while (1) { + char command[256]; + char *t = strchr(tmp, ':'); + if (t) + *t = '\0'; + + /* prepend path to given command */ + snprintf(command, 255, "%s/%s", tmp, data->args[0].u.str); + + if ((stat(command, &st) != -1) + && (st.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR)) + && (st.st_mode & S_IFREG)) { + data->args[0].u.str = strdup(command); + data->free_command = 1; + specter_log(SPECTER_DEBUG, "Command \"%s\" prepared.\n", + data->args[0].u.str); + return data; + } + + if (t) + tmp = t+1; + else + break; + } + } else { + if (!(st.st_mode & (S_IXOTH|S_IXGRP|S_IXUSR)) || !(st.st_mode & S_IFREG)) { + specter_log(SPECTER_FATAL, "\"%s\" isn't an executable.\n", + data->args[0].u.str); + return NULL; + } else { /* everything's fine */ + specter_log(SPECTER_DEBUG, "Command \"%s\" prepared.\n", + data->args[0].u.str); + return data; + } + } + + /* strerror() will return error from last stat() */ + specter_log(SPECTER_FATAL, "Couldn't find executable \"%s\" in $PATH: %s.\n", + data->args[0].u.str, strerror(errno)); + return NULL; } @@ -468,172 +481,161 @@ static int exec_output(config_entry_t *ce, void *data) { - static char buff[LOCAL_RET_NUM][EXEC_ARG_SPACE]; - static char *argv[EXEC_MAX_ARGS+1]; - char *curr_buf = buff[0]; - int ctr, status, ret, use_buf; - int buff_ctr, argv_ctr; - struct my_data *md = data; - - /* first check if any previously executed children returned */ - while ((ret = waitpid(-1, &status, WNOHANG)) > 0) { - check_status(md->args[0].u.str, ret, status); - } - - /* resolve tags */ - buff_ctr = argv_ctr = use_buf = 0; - curr_buf = buff[0]; - for (ctr = 0; md->args[ctr].type != ARG_TYPE_NONE; ctr++) { - - if (buff_space_left <= 0) { - specter_log(SPECTER_ERROR, "Argument too long.\n"); - return 0; - } - - if (md->args[ctr].type & ARG_TYPE_IRET) { - specter_iret_t *iret; - - if (buff_ctr == LOCAL_RET_NUM) { - specter_log(SPECTER_ERROR, "No space for arguments.\n"); - return -1; - } - - if ((iret = find_tag(md->args[ctr].u.c)) == NULL) { - /* should never happen due to checks in exec_init() */ - specter_log(SPECTER_ERROR, - "Unknown tag: %c.\n", md->args[ctr].u.c); - return -1; - } - - if ((ret = fill_arg(curr_buf, iret, buff_space_left)) == -1) { - if (GET_CE(ce,2)->u.value) { - strncat(curr_buf, "invalid", buff_space_left); - curr_buf += 7; - } else { - specter_log(SPECTER_DEBUG, "Required key \"%s\" invalid.\n", - iret->name); - return 0; - } - } else { - curr_buf += ret; - } - - use_buf = 1; - } else if (md->args[ctr].type & ARG_TYPE_STRING) { - if ((md->args[ctr-1].type & ATT_FLAG) - || (md->args[ctr].type & ATT_FLAG)) { - strncpy(curr_buf, md->args[ctr].u.str, buff_space_left); - curr_buf += strlen(md->args[ctr].u.str); - } - else { - argv[argv_ctr++] = md->args[ctr].u.str; - } - } - - if (!(md->args[ctr].type & ATT_FLAG) && use_buf) { - argv[argv_ctr++] = buff[buff_ctr]; - curr_buf = buff[++buff_ctr]; - use_buf = 0; - } - } - - specter_log(SPECTER_DEBUG, "Executing command \"%s\".\n", argv[0]); - - /* execute */ - ret = fork(); - if (ret == -1) { - specter_log(SPECTER_ERROR, "Couldn't fork(): %s.\n", - strerror(errno)); - return 0; - } else if (ret) { /* parent */ - if (GET_CE(ce,1)->u.value) { - if (waitpid(ret, &status, 0x0) != -1) - check_status(argv[0], ret, status); - } - } else { /* child */ - static char *envp[] = { NULL }; - int fd; - - /* delete specter's signal handlers */ - signal(SIGTERM, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGHUP, SIG_DFL); - - /* handle redirections */ - if (md->stdin.file[0] != '\0') { - if ((fd = open(md->stdin.file, md->stdin.flags)) == -1) { - specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", - md->stdin.file, strerror(errno)); - exit(1); - } - if (dup2(fd, 0) == -1) { - specter_log(SPECTER_ERROR, "Error redirecting stdin stream: %s.\n", - strerror(errno)); - exit(1); - } - } - if (md->stdout.file[0] != '\0') { - if ((fd = open(md->stdout.file, md->stdout.flags, S_IRUSR|S_IWUSR)) == -1) { - specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", - md->stdout.file, strerror(errno)); - exit(1); - } - if (dup2(fd, 1) == -1) { - specter_log(SPECTER_ERROR, "Error redirecting stdout stream: %s.\n", - strerror(errno)); - exit(1); - } - } - if (md->stderr.file[0] != '\0') { - if ((fd = open(md->stderr.file, md->stderr.flags, S_IRUSR|S_IWUSR)) == -1) { - specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", - md->stderr.file, strerror(errno)); - exit(1); - } - if (dup2(fd, 2) == -1) { - specter_log(SPECTER_ERROR, "Error redirecting stderr stream: %s.\n", - strerror(errno)); - exit(1); - } - } - - /* finally execute command */ - if (GET_CE(ce,3)->u.value) { - if (execve(argv[0], argv, environ) == -1) { - specter_log(SPECTER_ERROR, "Couldn't execve(): %s.\n", - strerror(errno)); - exit(1); - } - } else { - if (execve(argv[0], argv, envp) == -1) { - specter_log(SPECTER_ERROR, "Couldn't execve(): %s.\n", - strerror(errno)); - exit(1); - } - } - } - - return 0; + static char buff[LOCAL_RET_NUM][EXEC_ARG_SPACE]; + static char *argv[EXEC_MAX_ARGS+1]; + char *curr_buf = buff[0]; + int ctr, status, ret, use_buf; + int buff_ctr, argv_ctr; + struct my_data *md = data; + + /* resolve tags */ + buff_ctr = argv_ctr = use_buf = 0; + curr_buf = buff[0]; + for (ctr = 0; md->args[ctr].type != ARG_TYPE_NONE; ctr++) { + + if (buff_space_left <= 0) { + specter_log(SPECTER_ERROR, "Argument too long.\n"); + return 0; + } + + if (md->args[ctr].type & ARG_TYPE_IRET) { + specter_iret_t *iret; + + if (buff_ctr == LOCAL_RET_NUM) { + specter_log(SPECTER_ERROR, "No space for arguments.\n"); + return -1; + } + + if ((iret = find_tag(md->args[ctr].u.c)) == NULL) { + /* should never happen due to checks in exec_init() */ + specter_log(SPECTER_ERROR, + "Unknown tag: %c.\n", md->args[ctr].u.c); + return -1; + } + + if ((ret = fill_arg(curr_buf, iret, buff_space_left)) == -1) { + if (GET_CE(ce,2)->u.value) { + strncat(curr_buf, "invalid", buff_space_left); + curr_buf += 7; + } else { + specter_log(SPECTER_DEBUG, "Required key \"%s\" invalid.\n", + iret->name); + return 0; + } + } else { + curr_buf += ret; + } + + use_buf = 1; + } else if (md->args[ctr].type & ARG_TYPE_STRING) { + if ((md->args[ctr-1].type & ATT_FLAG) + || (md->args[ctr].type & ATT_FLAG)) { + strncpy(curr_buf, md->args[ctr].u.str, buff_space_left); + curr_buf += strlen(md->args[ctr].u.str); + } + else { + argv[argv_ctr++] = md->args[ctr].u.str; + } + } + + if (!(md->args[ctr].type & ATT_FLAG) && use_buf) { + argv[argv_ctr++] = buff[buff_ctr]; + curr_buf = buff[++buff_ctr]; + use_buf = 0; + } + } + + specter_log(SPECTER_DEBUG, "Executing command \"%s\".\n", argv[0]); + + /* execute */ + ret = fork(); + if (ret == -1) { + specter_log(SPECTER_ERROR, "Couldn't fork(): %s.\n", + strerror(errno)); + return 0; + } else if (ret == 0) { /* child */ + static char *envp[] = { NULL }; + int fd; + + /* delete specter's signal handlers */ + signal(SIGTERM, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGHUP, SIG_DFL); + + /* handle redirections */ + if (md->stdin.file[0] != '\0') { + if ((fd = open(md->stdin.file, md->stdin.flags)) == -1) { + specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", + md->stdin.file, strerror(errno)); + exit(1); + } + if (dup2(fd, 0) == -1) { + specter_log(SPECTER_ERROR, "Error redirecting stdin stream: %s.\n", + strerror(errno)); + exit(1); + } + } + if (md->stdout.file[0] != '\0') { + if ((fd = open(md->stdout.file, md->stdout.flags, S_IRUSR|S_IWUSR)) == -1) { + specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", + md->stdout.file, strerror(errno)); + exit(1); + } + if (dup2(fd, 1) == -1) { + specter_log(SPECTER_ERROR, "Error redirecting stdout stream: %s.\n", + strerror(errno)); + exit(1); + } + } + if (md->stderr.file[0] != '\0') { + if ((fd = open(md->stderr.file, md->stderr.flags, S_IRUSR|S_IWUSR)) == -1) { + specter_log(SPECTER_ERROR, "Error opening file \"%s\": %s.\n", + md->stderr.file, strerror(errno)); + exit(1); + } + if (dup2(fd, 2) == -1) { + specter_log(SPECTER_ERROR, "Error redirecting stderr stream: %s.\n", + strerror(errno)); + exit(1); + } + } + + /* finally execute command */ + if (GET_CE(ce,3)->u.value) { + if (execve(argv[0], argv, environ) == -1) { + specter_log(SPECTER_ERROR, "Couldn't execve(): %s.\n", + strerror(errno)); + exit(1); + } + } else { + if (execve(argv[0], argv, envp) == -1) { + specter_log(SPECTER_ERROR, "Couldn't execve(): %s.\n", + strerror(errno)); + exit(1); + } + } + } + + return 0; } #undef buff_space_left static specter_output_t exec_op = { - .name = "exec", - .ce_base = my_config, - .ce_num = 4, - .init = &exec_init, - .fini = &exec_fini, - .output = &exec_output, + .name = "exec", + .ce_base = my_config, + .ce_num = 4, + .init = &exec_init, + .fini = &exec_fini, + .output = &exec_output, }; void _init(void) { - if (register_output(&exec_op, 0) == -1) { - specter_log(SPECTER_FATAL, "Can't register.\n"); - exit(EXIT_FAILURE); - } + if (register_output(&exec_op, 0) == -1) { + specter_log(SPECTER_FATAL, "Can't register.\n"); + exit(EXIT_FAILURE); + } } -