From 9449e6a9eba30c9ed054f57d630a88c9f087080f Mon Sep 17 00:00:00 2001 From: Frederic Crozat Date: Mon, 31 Oct 2011 15:51:53 +0100 Subject: Add support to forward console query to systemd Systemd requires console query to be forwarded using its own tool. Signed-off-by: Frederic Crozat Acked-by: David Sommerseth URL: http://thread.gmane.org/gmane.network.openvpn.devel/5073/focus=5277 Signed-off-by: David Sommerseth --- configure.ac | 11 ++++++ misc.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/configure.ac b/configure.ac index a4d68e6..7143cc5 100644 --- a/configure.ac +++ b/configure.ac @@ -223,6 +223,12 @@ AC_ARG_ENABLE(selinux, [SELINUX="yes"] ) +AC_ARG_ENABLE(systemd, + [ --enable-systemd Enable systemd suppport], + [SYSTEMD="$enableval"], + [SYSTEMD="no"] +) + AC_ARG_WITH(ssl-headers, [ --with-ssl-headers=DIR Crypto/SSL Include files location], [CS_HDR_DIR="$withval"] @@ -930,6 +936,11 @@ if test "$PASSWORD_SAVE" = "yes"; then AC_DEFINE(ENABLE_PASSWORD_SAVE, 1, [Allow --askpass and --auth-user-pass passwords to be read from a file]) fi +dnl enable systemd support +if test "$SYSTEMD" = "yes"; then + AC_DEFINE(ENABLE_SYSTEMD, 1, [Enable systemd support]) +fi + dnl dnl check for SELinux library and headers dnl diff --git a/misc.c b/misc.c index 99e5bc5..9ac2877 100644 --- a/misc.c +++ b/misc.c @@ -36,6 +36,7 @@ #include "crypto.h" #include "route.h" #include "win32.h" +#include #include "memdbg.h" @@ -609,6 +610,73 @@ openvpn_system (const char *command, const struct env_set *es, unsigned int flag #endif } +/* + * Run execve() inside a fork(), duping stdout. Designed to replicate the semantics of popen() but + * in a safer way that doesn't require the invocation of a shell or the risks + * assocated with formatting and parsing a command line. + */ +int +openvpn_popen (const struct argv *a, const struct env_set *es) +{ + struct gc_arena gc = gc_new (); + int ret = -1; + static bool warn_shown = false; + + if (a && a->argv[0]) + { +#if defined(ENABLE_EXECVE) + if (script_security >= SSEC_BUILT_IN) + { + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array (es, true, &gc); + pid_t pid; + int pipe_stdout[2]; + + if (pipe (pipe_stdout) == 0) { + pid = fork (); + if (pid == (pid_t)0) /* child side */ + { + close (pipe_stdout[0]); + dup2 (pipe_stdout[1],1); + execve (cmd, argv, envp); + exit (127); + } + else if (pid < (pid_t)0) /* fork failed */ + { + msg (M_ERR, "openvpn_popen: unable to fork"); + } + else /* parent side */ + { + ret=pipe_stdout[0]; + close (pipe_stdout[1]); + } + } + else { + msg (M_WARN, "openvpn_popen: unable to create stdout pipe"); + ret = -1; + } + } + else if (!warn_shown && (script_security < SSEC_SCRIPTS)) + { + msg (M_WARN, SCRIPT_SECURITY_WARNING); + warn_shown = true; + } +#else + msg (M_WARN, "openvpn_popen: execve function not available"); +#endif + } + else + { + msg (M_FATAL, "openvpn_popen: called with empty argv"); + } + + gc_free (&gc); + return ret; +} + + + /* * Initialize random number seed. random() is only used * when "weak" random numbers are acceptable. @@ -1325,6 +1393,56 @@ close_tty (FILE *fp) fclose (fp); } +#endif + +/* + * is systemd running + */ + +#if defined(TARGET_LINUX) && defined(ENABLE_SYSTEMD) +bool +check_systemd_running () +{ + struct stat a, b; + + /* We simply test whether the systemd cgroup hierarchy is + * mounted */ + + return (lstat("/sys/fs/cgroup", &a) == 0) + && (lstat("/sys/fs/cgroup/systemd", &b) == 0) + && (a.st_dev != b.st_dev); + +} + +bool +get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity) +{ + int std_out; + char cmd[256]; + bool ret = false; + struct argv argv; + + argv_init (&argv); + argv_printf (&argv, "/bin/systemd-ask-password"); + argv_printf_cat (&argv, "%s", prompt); + + if ((std_out = openvpn_popen (&argv, NULL)) < 0) { + return false; + } + CLEAR (*input); + if (read (std_out, input, capacity) != 0) + { + chomp (input); + ret = true; + } + close (std_out); + + argv_reset (&argv); + + return ret; +} + + #endif /* @@ -1339,6 +1457,11 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c ASSERT (capacity > 0); input[0] = '\0'; +#if defined(TARGET_LINUX) && defined(ENABLE_SYSTEMD) + if (check_systemd_running ()) + return get_console_input_systemd (prompt, echo, input, capacity); +#endif + #if defined(WIN32) return get_console_input_win32 (prompt, echo, input, capacity); #elif defined(HAVE_GETPASS) -- cgit