38#include <sys/socket.h>
46#include <openvpn-plugin.h>
48#define DEBUG(verb) ((verb) >= 7)
51#define COMMAND_RUN_SCRIPT 1
55#define RESPONSE_INIT_SUCCEEDED 10
56#define RESPONSE_INIT_FAILED 11
57#define RESPONSE_SCRIPT_SUCCEEDED 12
58#define RESPONSE_SCRIPT_FAILED 13
87get_env(
const char *name,
const char *envp[])
92 const int namelen = strlen(name);
93 for (i = 0; envp[i]; ++i)
95 if (!strncmp(envp[i], name, namelen))
97 const char *cp = envp[i] + namelen;
133 const ssize_t size =
read(fd, &c,
sizeof(c));
134 if (size ==
sizeof(c))
147 unsigned char c = (
unsigned char) code;
148 const ssize_t size =
write(fd, &c,
sizeof(c));
149 if (size ==
sizeof(c))
167 const char *daemon_string =
get_env(
"daemon", envp);
168 if (daemon_string && daemon_string[0] ==
'1')
170 const char *log_redirect =
get_env(
"daemon_log_redirect", envp);
172 if (log_redirect && log_redirect[0] ==
'1')
176#if defined(__APPLE__) && defined(__clang__)
177#pragma clang diagnostic push
178#pragma clang diagnostic ignored "-Wdeprecated-declarations"
182 warn(
"DOWN-ROOT: daemonization failed");
184#if defined(__APPLE__) && defined(__clang__)
185#pragma clang diagnostic pop
210 for (i = 3; i <= 100; ++i)
226 signal(SIGTERM, SIG_DFL);
228 signal(SIGINT, SIG_IGN);
229 signal(SIGHUP, SIG_IGN);
230 signal(SIGUSR1, SIG_IGN);
231 signal(SIGUSR2, SIG_IGN);
232 signal(SIGPIPE, SIG_IGN);
261 err(127,
"DOWN-ROOT: Failed execute: %s",
argv[0]);
263 else if (pid < (pid_t)0)
265 warn(
"DOWN-ROOT: Failed to fork child to run %s",
argv[0]);
270 if (waitpid(pid, &ret, 0) != pid)
273 fprintf(stderr,
"DOWN-ROOT: waitpid() failed, don't know exit code of child (%s)\n",
argv[0]);
280OPENVPN_EXPORT openvpn_plugin_handle_t
292 warn(
"DOWN-ROOT: Could not allocate memory for plug-in context");
300 *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN);
308 fprintf(stderr,
"DOWN-ROOT: need down script command\n");
318 warn(
"DOWN-ROOT: Could not allocate memory for command array");
332 const char *verb_string =
get_env(
"verb", envp);
335 context->verb = atoi(verb_string);
339 return (openvpn_plugin_handle_t)
context;
351 if (type == OPENVPN_PLUGIN_UP &&
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;
437 warn(
"DOWN-ROOT: Error receiving script execution confirmation from background process");
441 return OPENVPN_PLUGIN_FUNC_ERROR;
451 fprintf(stderr,
"DOWN-ROOT: close\n");
454 if (
context->foreground_fd >= 0)
459 warn(
"DOWN-ROOT: Error signalling background process to exit");
463 if (
context->background_pid > 0)
465 waitpid(
context->background_pid, NULL, 0);
500 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: INIT command='%s'\n",
argv[0]);
508 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [1]");
525 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code);
528 switch (command_code)
535 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [2]");
541 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n",
argv[0], exit_code);
544 warn(
"DOWN-ROOT: BACKGROUND: write error on response socket [3]");
554 warn(
"DOWN-ROOT: BACKGROUND: read error on command channel");
558 fprintf(stderr,
"DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n",
567 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)
static int string_array_len(const char *array[])
#define COMMAND_RUN_SCRIPT
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[])
#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 int send_control(int fd, int code)
static void close_fds_except(int keep)
static SERVICE_STATUS status
Contains all state information for one tunnel.