File: [local] / acopm / src / exec.c (download)
Revision 1.1.1.1 (vendor branch), Sat May 8 15:42:17 2021 UTC (3 years, 2 months ago) by bountyht
Branch: alphachat, MAIN
CVS Tags: start, HEAD Changes since 1.1: +0 -0 lines
Initial import
|
/*
* Copyright (C) 2017 Aaron M. D. Jones <aaronmdjones@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "acopm-common.h"
#include <assert.h> /* assert() */
#include <errno.h> /* errno */
#include <fcntl.h> /* open(), O_* */
#include <inttypes.h> /* PRIu16 */
#include <string.h> /* strerror() */
#include <unistd.h> /* close(), dup2(), execve(), fork(), STD*_FILENO */
#include <sys/stat.h> /* S_IWUSR, S_IRUSR */
#include <event2/event.h> /* struct event*, event_*() */
#include "exec.h" /* decls for own functions */
#include "vars.h" /* global variable definitions */
#include "proxy/client.h" /* enum acopm_proxy_type */
#include "utils/log.h" /* acopm_log_*() */
#define ARGV_MAX 2 /* program, plus null terminator */
#define ENVP_MAX 13 /* environment vars (max 7), plus 5 custom vars, plus null terminator */
#define EVAR_MIN 6 /* minimum length of environment var=value */
static int null_fd = -1;
static int log_fd = -1;
static inline bool acopm_attr_inline
acopm_exec_dup_one(FILE *const restrict file, const int from, const int guard, const int to)
{
if (from != to && guard != to)
{
(void) fflush(file);
(void) close(to);
if (dup2(from, to) == -1)
return false;
}
return true;
}
static bool
acopm_exec_dup_all(void)
{
if (! acopm_exec_dup_one(stdin, null_fd, log_fd, STDIN_FILENO))
return false;
if (! acopm_exec_dup_one(stdout, log_fd, null_fd, STDOUT_FILENO))
return false;
if (! acopm_exec_dup_one(stderr, log_fd, null_fd, STDERR_FILENO))
return false;
if (null_fd >= 3 && close(null_fd) == -1)
return false;
if (log_fd >= 3 && log_fd != null_fd && close(log_fd) == -1)
return false;
return true;
}
static bool
acopm_exec_add_env(char **const restrict envp, const size_t max,
const char *const restrict name, const char *restrict value)
{
if (! value && ! (value = getenv(name)))
return true;
if (! *value)
return true;
char var[ACOPM_EXE_EVAR_MAX];
if (snprintf(var, sizeof var, "%s=%s", name, value) < EVAR_MIN)
return false;
char *const dup = strdup(var);
if (! dup)
return false;
for (size_t x = 0; x < max; x++)
{
if (! envp[x])
{
envp[x] = dup;
return true;
}
}
(void) free(dup);
return false;
}
bool
acopm_exec_init(void)
{
assert(null_fd == -1);
assert(log_fd == -1);
(void) acopm_log_debug("%s: initialising execution subsystem", __func__);
if ((null_fd = open(NULL_PATH, O_RDWR | O_NOCTTY)) == -1)
{
(void) acopm_log_error("%s: open('%s'): %s", __func__, NULL_PATH, strerror(errno));
return false;
}
if (! *proxy_hit_log)
{
log_fd = null_fd;
}
else if ((log_fd = open(proxy_hit_log, O_APPEND | O_CREAT | O_NOCTTY, S_IWUSR | S_IRUSR)) == -1)
{
(void) acopm_log_error("%s: open('%s'): %s", __func__, proxy_hit_log, strerror(errno));
return false;
}
return true;
}
void
acopm_exec_free(void)
{
if (null_fd == -1 && log_fd == -1)
return;
(void) acopm_log_debug("%s: destroying execution subsystem", __func__);
if (null_fd != -1)
(void) close(null_fd);
if (log_fd != -1 && log_fd != null_fd)
(void) close(log_fd);
null_fd = -1;
log_fd = -1;
}
void
acopm_exec_proxy_program(const char *const restrict address, const uint16_t port, const enum acopm_proxy_type type)
{
(void) acopm_log_info("Executing external program for proxy hit");
(void) acopm_log_flush();
assert(address != NULL);
assert(*address != 0x00);
assert(port != 0);
assert(type != ACOPM_PROXY_TYPE_NONE);
char port_str[8];
(void) snprintf(port_str, sizeof port_str, "%" PRIu16, port);
assert(*port_str != 0x00);
const char *const type_str = acopm_proxy_type_str(type);
assert(type_str != NULL);
assert(*type_str != 0x00);
const pid_t pid = fork();
if (pid == -1)
{
(void) acopm_log_error("%s: fork: %s", __func__, strerror(errno));
return;
}
else if (pid != 0)
return;
char *argv[ARGV_MAX], *envp[ENVP_MAX];
(void) memset(argv, 0x00, sizeof argv);
(void) memset(envp, 0x00, sizeof envp);
if (! acopm_exec_dup_all())
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "HOME", NULL))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "PATH", NULL))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "SHELL", NULL))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "USER", NULL))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "ADDRESS", address))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "PORT", port_str))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "TYPE", type_str))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "CONFIG1", proxy_hit_var1))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "CONFIG2", proxy_hit_var2))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "CONFIG3", proxy_hit_var3))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "CONFIG4", proxy_hit_var4))
goto end;
if (! acopm_exec_add_env(envp, ENVP_MAX, "CONFIG5", proxy_hit_var5))
goto end;
argv[0] = proxy_hit_exe;
(void) execve(proxy_hit_exe, argv, envp);
end:
exit(EXIT_FAILURE);
}