37#include <sys/socket.h>
45#include <openvpn-plugin.h>
47#define DEBUG(verb) ((verb) >= 7)
50#define COMMAND_RUN_SCRIPT 1
54#define RESPONSE_INIT_SUCCEEDED 10
55#define RESPONSE_INIT_FAILED 11
56#define RESPONSE_SCRIPT_SUCCEEDED 12
57#define RESPONSE_SCRIPT_FAILED 13
86get_env(
const char *name,
const char *envp[])
90 const size_t namelen = strlen(name);
91 for (
int i = 0; envp[
i]; ++
i)
93 if (!strncmp(envp[
i], name, namelen))
95 const char *cp = envp[
i] + namelen;
131 const ssize_t size =
read(fd, &c,
sizeof(c));
132 if (size ==
sizeof(c))
145 unsigned char c = (
unsigned char)code;
146 const ssize_t size =
write(fd, &c,
sizeof(c));
147 if (size ==
sizeof(c))
165 const char *daemon_string =
get_env(
"daemon", envp);
166 if (daemon_string && daemon_string[0] ==
'1')
168 const char *log_redirect =
get_env(
"daemon_log_redirect", envp);
170 if (log_redirect && log_redirect[0] ==
'1')
174#if defined(__APPLE__) && defined(__clang__)
175#pragma clang diagnostic push
176#pragma clang diagnostic ignored "-Wdeprecated-declarations"
180 warn(
"DOWN-ROOT: daemonization failed");
182#if defined(__APPLE__) && defined(__clang__)
183#pragma clang diagnostic pop
208 for (
i = 3;
i <= 100; ++
i)
224 signal(SIGTERM, SIG_DFL);
226 signal(SIGINT, SIG_IGN);
227 signal(SIGHUP, SIG_IGN);
228 signal(SIGUSR1, SIG_IGN);
229 signal(SIGUSR2, SIG_IGN);
230 signal(SIGPIPE, SIG_IGN);
259 err(127,
"DOWN-ROOT: Failed execute: %s",
argv[0]);
261 else if (pid < (pid_t)0)
263 warn(
"DOWN-ROOT: Failed to fork child to run %s",
argv[0]);
268 if (waitpid(pid, &ret, 0) != pid)
271 fprintf(stderr,
"DOWN-ROOT: waitpid() failed, don't know exit code of child (%s)\n",
279OPENVPN_EXPORT openvpn_plugin_handle_t
290 warn(
"DOWN-ROOT: Could not allocate memory for plug-in context");
298 *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN);
306 fprintf(stderr,
"DOWN-ROOT: need down script command\n");
316 warn(
"DOWN-ROOT: Could not allocate memory for command array");
330 const char *verb_string =
get_env(
"verb", envp);
333 context->verb = atoi(verb_string);
337 return (openvpn_plugin_handle_t)
context;
350 if (type == OPENVPN_PLUGIN_UP
351 &&
context->foreground_fd == -1)
360 if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
362 warn(
"DOWN-ROOT: socketpair call failed");
363 return OPENVPN_PLUGIN_FUNC_ERROR;
386 if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0)
388 warn(
"DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed");
395 context->foreground_fd = fd[0];
396 return OPENVPN_PLUGIN_FUNC_SUCCESS;
422 else if (type == OPENVPN_PLUGIN_DOWN &&
context->foreground_fd >= 0)
426 warn(
"DOWN-ROOT: Error sending script execution signal to background process");
433 return OPENVPN_PLUGIN_FUNC_SUCCESS;
438 "DOWN-ROOT: Error receiving script execution confirmation from background process");
442 return OPENVPN_PLUGIN_FUNC_ERROR;
452 fprintf(stderr,
"DOWN-ROOT: close\n");
455 if (
context->foreground_fd >= 0)
460 warn(
"DOWN-ROOT: Error signalling background process to exit");
464 if (
context->background_pid > 0)
466 waitpid(
context->background_pid, NULL, 0);
501 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: INIT command='%s'\n",
argv[0]);
509 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [1]");
526 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code);
529 switch (command_code)
536 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [2]");
542 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n",
argv[0],
546 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [3]");
556 warn(
"DOWN-ROOT: BACKGROUND: read error on command channel");
560 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n",
569 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: EXIT\n");
int daemon(int nochdir, int noclose)
OPENVPN_EXPORT int openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
static void set_signals(void)
OPENVPN_EXPORT void openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
#define COMMAND_RUN_SCRIPT
static ssize_t send_control(int fd, int code)
static void free_context(struct down_root_context *context)
#define RESPONSE_SCRIPT_FAILED
static int run_script(char *const *argv, char *const *envp)
#define RESPONSE_INIT_SUCCEEDED
static void daemonize(const char *envp[])
static size_t string_array_len(const char *array[])
#define RESPONSE_SCRIPT_SUCCEEDED
static void down_root_server(const int fd, char *const *argv, char *const *envp, const int verb)
OPENVPN_EXPORT openvpn_plugin_handle_t openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
static const char * get_env(const char *name, const char *envp[])
OPENVPN_EXPORT void openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle)
static int recv_control(int fd)
static void close_fds_except(int keep)
static SERVICE_STATUS status
Contains all state information for one tunnel.