diff options
Diffstat (limited to 'src/plugins/down-root/down-root.c')
-rw-r--r-- | src/plugins/down-root/down-root.c | 260 |
1 files changed, 144 insertions, 116 deletions
diff --git a/src/plugins/down-root/down-root.c b/src/plugins/down-root/down-root.c index 6931bec..ae85ecb 100644 --- a/src/plugins/down-root/down-root.c +++ b/src/plugins/down-root/down-root.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2013 David Sommerseth <davids@redhat.com> * * This program is free software; you can redistribute it and/or modify @@ -59,7 +59,7 @@ #define RESPONSE_SCRIPT_FAILED 13 /* Background process function */ -static void down_root_server (const int fd, char * const * argv, char * const *envp, const int verb); +static void down_root_server(const int fd, char *const *argv, char *const *envp, const int verb); /* * Plugin state, used by foreground @@ -85,19 +85,21 @@ struct down_root_context * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { if (envp) { int i; - const int namelen = strlen (name); + const int namelen = strlen(name); for (i = 0; envp[i]; ++i) { - if (!strncmp (envp[i], name, namelen)) + if (!strncmp(envp[i], name, namelen)) { const char *cp = envp[i] + namelen; if (*cp == '=') + { return cp + 1; + } } } } @@ -108,7 +110,7 @@ get_env (const char *name, const char *envp[]) * Return the length of a string array */ static int -string_array_len (const char *array[]) +string_array_len(const char *array[]) { int i = 0; if (array) @@ -124,25 +126,33 @@ string_array_len (const char *array[]) */ static int -recv_control (int fd) +recv_control(int fd) { unsigned char c; - const ssize_t size = read (fd, &c, sizeof (c)); - if (size == sizeof (c)) + const ssize_t size = read(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { return c; + } else + { return -1; + } } static int -send_control (int fd, int code) +send_control(int fd, int code) { unsigned char c = (unsigned char) code; - const ssize_t size = write (fd, &c, sizeof (c)); - if (size == sizeof (c)) + const ssize_t size = write(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { return (int) size; + } else + { return -1; + } } /* @@ -151,23 +161,25 @@ send_control (int fd, int code) * "daemon_log_redirect" env var is true. */ static void -daemonize (const char *envp[]) +daemonize(const char *envp[]) { - const char *daemon_string = get_env ("daemon", envp); + const char *daemon_string = get_env("daemon", envp); if (daemon_string && daemon_string[0] == '1') { - const char *log_redirect = get_env ("daemon_log_redirect", envp); + const char *log_redirect = get_env("daemon_log_redirect", envp); int fd = -1; if (log_redirect && log_redirect[0] == '1') - fd = dup (2); - if (daemon (0, 0) < 0) { - warn ("DOWN-ROOT: daemonization failed"); + fd = dup(2); + } + if (daemon(0, 0) < 0) + { + warn("DOWN-ROOT: daemonization failed"); } else if (fd >= 3) { - dup2 (fd, 2); - close (fd); + dup2(fd, 2); + close(fd); } } } @@ -183,14 +195,16 @@ daemonize (const char *envp[]) * fds from crossing a fork(). */ static void -close_fds_except (int keep) +close_fds_except(int keep) { int i; - closelog (); + closelog(); for (i = 3; i <= 100; ++i) { if (i != keep) - close (i); + { + close(i); + } } } @@ -199,28 +213,28 @@ close_fds_except (int keep) * deal with them. */ static void -set_signals (void) +set_signals(void) { - signal (SIGTERM, SIG_DFL); + signal(SIGTERM, SIG_DFL); - signal (SIGINT, SIG_IGN); - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - signal (SIGPIPE, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); } static void -free_context (struct down_root_context *context) +free_context(struct down_root_context *context) { if (context) { if (context->command) { - free (context->command); + free(context->command); } - free (context); + free(context); } } @@ -229,7 +243,7 @@ free_context (struct down_root_context *context) * calling execve() */ static int -run_script(char * const *argv, char * const *envp) +run_script(char *const *argv, char *const *envp) { pid_t pid; int ret = 0; @@ -241,14 +255,14 @@ run_script(char * const *argv, char * const *envp) /* If execve() fails to run, exit child with exit code 127 */ err(127, "DOWN-ROOT: Failed execute: %s", argv[0]); } - else if (pid < (pid_t)0 ) + else if (pid < (pid_t)0) { - warn ("DOWN-ROOT: Failed to fork child to run %s", argv[0]); + warn("DOWN-ROOT: Failed to fork child to run %s", argv[0]); return -1; } else /* parent side */ { - if( waitpid (pid, &ret, 0) != pid ) + if (waitpid(pid, &ret, 0) != pid) { /* waitpid does not return error information via errno */ fprintf(stderr, "DOWN-ROOT: waitpid() failed, don't know exit code of child (%s)\n", argv[0]); @@ -259,7 +273,7 @@ run_script(char * const *argv, char * const *envp) } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { struct down_root_context *context; int i = 0; @@ -267,10 +281,10 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char /* * Allocate our context */ - context = (struct down_root_context *) calloc (1, sizeof (struct down_root_context)); + context = (struct down_root_context *) calloc(1, sizeof(struct down_root_context)); if (!context) { - warn ("DOWN-ROOT: Could not allocate memory for plug-in context"); + warn("DOWN-ROOT: Could not allocate memory for plug-in context"); goto error; } context->foreground_fd = -1; @@ -278,15 +292,15 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char /* * Intercept the --up and --down callbacks */ - *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN); + *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN); /* * Make sure we have two string arguments: the first is the .so name, * the second is the script command. */ - if (string_array_len (argv) < 2) + if (string_array_len(argv) < 2) { - fprintf (stderr, "DOWN-ROOT: need down script command\n"); + fprintf(stderr, "DOWN-ROOT: need down script command\n"); goto error; } @@ -296,7 +310,7 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char context->command = calloc(string_array_len(argv), sizeof(char *)); if (!context->command) { - warn ("DOWN-ROOT: Could not allocate memory for command array"); + warn("DOWN-ROOT: Could not allocate memory for command array"); goto error; } @@ -310,20 +324,22 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char * Get verbosity level from environment */ { - const char *verb_string = get_env ("verb", envp); + const char *verb_string = get_env("verb", envp); if (verb_string) - context->verb = atoi (verb_string); + { + context->verb = atoi(verb_string); + } } return (openvpn_plugin_handle_t) context; error: - free_context (context); + free_context(context); return NULL; } OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { struct down_root_context *context = (struct down_root_context *) handle; @@ -336,9 +352,9 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch * Make a socket for foreground and background processes * to communicate. */ - if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1) + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1) { - warn ("DOWN-ROOT: socketpair call failed"); + warn("DOWN-ROOT: socketpair call failed"); return OPENVPN_PLUGIN_FUNC_ERROR; } @@ -346,7 +362,7 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch * Fork off the privileged process. It will remain privileged * even after the foreground process drops its privileges. */ - pid = fork (); + pid = fork(); if (pid) { @@ -359,16 +375,16 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch context->background_pid = pid; /* close our copy of child's socket */ - close (fd[1]); + close(fd[1]); /* don't let future subprocesses inherit child socket */ - if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0) + if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) { - warn ("DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed"); + warn("DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed"); } /* wait for background child process to initialize */ - status = recv_control (fd[0]); + status = recv_control(fd[0]); if (status == RESPONSE_INIT_SUCCEEDED) { context->foreground_fd = fd[0]; @@ -382,36 +398,38 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch */ /* close all parent fds except our socket back to parent */ - close_fds_except (fd[1]); + close_fds_except(fd[1]); /* Ignore most signals (the parent will receive them) */ - set_signals (); + set_signals(); /* Daemonize if --daemon option is set. */ - daemonize (envp); + daemonize(envp); /* execute the event loop */ - down_root_server (fd[1], context->command, (char * const *) envp, context->verb); + down_root_server(fd[1], context->command, (char *const *) envp, context->verb); - close (fd[1]); - exit (0); + close(fd[1]); + exit(0); return 0; /* NOTREACHED */ } } else if (type == OPENVPN_PLUGIN_DOWN && context->foreground_fd >= 0) { - if (send_control (context->foreground_fd, COMMAND_RUN_SCRIPT) == -1) + if (send_control(context->foreground_fd, COMMAND_RUN_SCRIPT) == -1) { - warn ("DOWN-ROOT: Error sending script execution signal to background process"); + warn("DOWN-ROOT: Error sending script execution signal to background process"); } else { - const int status = recv_control (context->foreground_fd); + const int status = recv_control(context->foreground_fd); if (status == RESPONSE_SCRIPT_SUCCEEDED) + { return OPENVPN_PLUGIN_FUNC_SUCCESS; + } if (status == -1) { - warn ("DOWN-ROOT: Error receiving script execution confirmation from background process"); + warn("DOWN-ROOT: Error receiving script execution confirmation from background process"); } } } @@ -419,42 +437,46 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { struct down_root_context *context = (struct down_root_context *) handle; - if (DEBUG (context->verb)) - fprintf (stderr, "DOWN-ROOT: close\n"); + if (DEBUG(context->verb)) + { + fprintf(stderr, "DOWN-ROOT: close\n"); + } if (context->foreground_fd >= 0) { /* tell background process to exit */ - if (send_control (context->foreground_fd, COMMAND_EXIT) == -1) + if (send_control(context->foreground_fd, COMMAND_EXIT) == -1) { - warn ("DOWN-ROOT: Error signalling background process to exit"); + warn("DOWN-ROOT: Error signalling background process to exit"); } /* wait for background process to exit */ if (context->background_pid > 0) - waitpid (context->background_pid, NULL, 0); + { + waitpid(context->background_pid, NULL, 0); + } - close (context->foreground_fd); + close(context->foreground_fd); context->foreground_fd = -1; } - free_context (context); + free_context(context); } OPENVPN_EXPORT void -openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle) { struct down_root_context *context = (struct down_root_context *) handle; if (context && context->foreground_fd >= 0) { /* tell background process to exit */ - send_control (context->foreground_fd, COMMAND_EXIT); - close (context->foreground_fd); + send_control(context->foreground_fd, COMMAND_EXIT); + close(context->foreground_fd); context->foreground_fd = -1; } } @@ -463,20 +485,22 @@ openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) * Background process -- runs with privilege. */ static void -down_root_server (const int fd, char * const *argv, char * const *envp, const int verb) +down_root_server(const int fd, char *const *argv, char *const *envp, const int verb) { /* * Do initialization */ - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", argv[0]); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", argv[0]); + } /* * Tell foreground that we initialized successfully */ - if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1) + if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1) { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [1]"); + warn("DOWN-ROOT: BACKGROUND: write error on response socket [1]"); goto done; } @@ -489,59 +513,63 @@ down_root_server (const int fd, char * const *argv, char * const *envp, const in int exit_code = -1; /* get a command from foreground process */ - command_code = recv_control (fd); + command_code = recv_control(fd); - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code); + } switch (command_code) { - case COMMAND_RUN_SCRIPT: - if ( (exit_code = run_script(argv, envp)) == 0 ) /* Succeeded */ - { - if (send_control (fd, RESPONSE_SCRIPT_SUCCEEDED) == -1) + case COMMAND_RUN_SCRIPT: + if ( (exit_code = run_script(argv, envp)) == 0) /* Succeeded */ { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [2]"); - goto done; + if (send_control(fd, RESPONSE_SCRIPT_SUCCEEDED) == -1) + { + warn("DOWN-ROOT: BACKGROUND: write error on response socket [2]"); + goto done; + } } - } - else /* Failed */ - { - fprintf(stderr, "DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n", argv[0], exit_code); - if (send_control (fd, RESPONSE_SCRIPT_FAILED) == -1) + else /* Failed */ { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [3]"); - goto done; + fprintf(stderr, "DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n", argv[0], exit_code); + if (send_control(fd, RESPONSE_SCRIPT_FAILED) == -1) + { + warn("DOWN-ROOT: BACKGROUND: write error on response socket [3]"); + goto done; + } } - } - break; + break; - case COMMAND_EXIT: - goto done; + case COMMAND_EXIT: + goto done; - case -1: - warn ("DOWN-ROOT: BACKGROUND: read error on command channel"); - goto done; + case -1: + warn("DOWN-ROOT: BACKGROUND: read error on command channel"); + goto done; - default: - fprintf (stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n", - command_code); - goto done; + default: + fprintf(stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n", + command_code); + goto done; } } done: - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: EXIT\n"); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: EXIT\n"); + } return; } /* -Local variables: -c-file-style: "bsd" -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ + * Local variables: + * c-file-style: "bsd" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ |