Systemd requires console query to be forwarded using its own
tool.
Signed-off-by: Frederic Crozat <fcrozat@suse.com>
Acked-by: David Sommerseth <davids@redhat.com>
URL: http://thread.gmane.org/gmane.network.openvpn.devel/5073/focus=5277
Signed-off-by: David Sommerseth <davids@redhat.com>
... | ... |
@@ -223,6 +223,12 @@ AC_ARG_ENABLE(selinux, |
223 | 223 |
[SELINUX="yes"] |
224 | 224 |
) |
225 | 225 |
|
226 |
+AC_ARG_ENABLE(systemd, |
|
227 |
+ [ --enable-systemd Enable systemd suppport], |
|
228 |
+ [SYSTEMD="$enableval"], |
|
229 |
+ [SYSTEMD="no"] |
|
230 |
+) |
|
231 |
+ |
|
226 | 232 |
AC_ARG_WITH(ssl-headers, |
227 | 233 |
[ --with-ssl-headers=DIR Crypto/SSL Include files location], |
228 | 234 |
[CS_HDR_DIR="$withval"] |
... | ... |
@@ -930,6 +936,11 @@ if test "$PASSWORD_SAVE" = "yes"; then |
930 | 930 |
AC_DEFINE(ENABLE_PASSWORD_SAVE, 1, [Allow --askpass and --auth-user-pass passwords to be read from a file]) |
931 | 931 |
fi |
932 | 932 |
|
933 |
+dnl enable systemd support |
|
934 |
+if test "$SYSTEMD" = "yes"; then |
|
935 |
+ AC_DEFINE(ENABLE_SYSTEMD, 1, [Enable systemd support]) |
|
936 |
+fi |
|
937 |
+ |
|
933 | 938 |
dnl |
934 | 939 |
dnl check for SELinux library and headers |
935 | 940 |
dnl |
... | ... |
@@ -36,6 +36,7 @@ |
36 | 36 |
#include "crypto.h" |
37 | 37 |
#include "route.h" |
38 | 38 |
#include "win32.h" |
39 |
+#include <unistd.h> |
|
39 | 40 |
|
40 | 41 |
#include "memdbg.h" |
41 | 42 |
|
... | ... |
@@ -610,6 +611,73 @@ openvpn_system (const char *command, const struct env_set *es, unsigned int flag |
610 | 610 |
} |
611 | 611 |
|
612 | 612 |
/* |
613 |
+ * Run execve() inside a fork(), duping stdout. Designed to replicate the semantics of popen() but |
|
614 |
+ * in a safer way that doesn't require the invocation of a shell or the risks |
|
615 |
+ * assocated with formatting and parsing a command line. |
|
616 |
+ */ |
|
617 |
+int |
|
618 |
+openvpn_popen (const struct argv *a, const struct env_set *es) |
|
619 |
+{ |
|
620 |
+ struct gc_arena gc = gc_new (); |
|
621 |
+ int ret = -1; |
|
622 |
+ static bool warn_shown = false; |
|
623 |
+ |
|
624 |
+ if (a && a->argv[0]) |
|
625 |
+ { |
|
626 |
+#if defined(ENABLE_EXECVE) |
|
627 |
+ if (script_security >= SSEC_BUILT_IN) |
|
628 |
+ { |
|
629 |
+ const char *cmd = a->argv[0]; |
|
630 |
+ char *const *argv = a->argv; |
|
631 |
+ char *const *envp = (char *const *)make_env_array (es, true, &gc); |
|
632 |
+ pid_t pid; |
|
633 |
+ int pipe_stdout[2]; |
|
634 |
+ |
|
635 |
+ if (pipe (pipe_stdout) == 0) { |
|
636 |
+ pid = fork (); |
|
637 |
+ if (pid == (pid_t)0) /* child side */ |
|
638 |
+ { |
|
639 |
+ close (pipe_stdout[0]); |
|
640 |
+ dup2 (pipe_stdout[1],1); |
|
641 |
+ execve (cmd, argv, envp); |
|
642 |
+ exit (127); |
|
643 |
+ } |
|
644 |
+ else if (pid < (pid_t)0) /* fork failed */ |
|
645 |
+ { |
|
646 |
+ msg (M_ERR, "openvpn_popen: unable to fork"); |
|
647 |
+ } |
|
648 |
+ else /* parent side */ |
|
649 |
+ { |
|
650 |
+ ret=pipe_stdout[0]; |
|
651 |
+ close (pipe_stdout[1]); |
|
652 |
+ } |
|
653 |
+ } |
|
654 |
+ else { |
|
655 |
+ msg (M_WARN, "openvpn_popen: unable to create stdout pipe"); |
|
656 |
+ ret = -1; |
|
657 |
+ } |
|
658 |
+ } |
|
659 |
+ else if (!warn_shown && (script_security < SSEC_SCRIPTS)) |
|
660 |
+ { |
|
661 |
+ msg (M_WARN, SCRIPT_SECURITY_WARNING); |
|
662 |
+ warn_shown = true; |
|
663 |
+ } |
|
664 |
+#else |
|
665 |
+ msg (M_WARN, "openvpn_popen: execve function not available"); |
|
666 |
+#endif |
|
667 |
+ } |
|
668 |
+ else |
|
669 |
+ { |
|
670 |
+ msg (M_FATAL, "openvpn_popen: called with empty argv"); |
|
671 |
+ } |
|
672 |
+ |
|
673 |
+ gc_free (&gc); |
|
674 |
+ return ret; |
|
675 |
+} |
|
676 |
+ |
|
677 |
+ |
|
678 |
+ |
|
679 |
+/* |
|
613 | 680 |
* Initialize random number seed. random() is only used |
614 | 681 |
* when "weak" random numbers are acceptable. |
615 | 682 |
* OpenSSL routines are always used when cryptographically |
... | ... |
@@ -1328,6 +1396,56 @@ close_tty (FILE *fp) |
1328 | 1328 |
#endif |
1329 | 1329 |
|
1330 | 1330 |
/* |
1331 |
+ * is systemd running |
|
1332 |
+ */ |
|
1333 |
+ |
|
1334 |
+#if defined(TARGET_LINUX) && defined(ENABLE_SYSTEMD) |
|
1335 |
+bool |
|
1336 |
+check_systemd_running () |
|
1337 |
+{ |
|
1338 |
+ struct stat a, b; |
|
1339 |
+ |
|
1340 |
+ /* We simply test whether the systemd cgroup hierarchy is |
|
1341 |
+ * mounted */ |
|
1342 |
+ |
|
1343 |
+ return (lstat("/sys/fs/cgroup", &a) == 0) |
|
1344 |
+ && (lstat("/sys/fs/cgroup/systemd", &b) == 0) |
|
1345 |
+ && (a.st_dev != b.st_dev); |
|
1346 |
+ |
|
1347 |
+} |
|
1348 |
+ |
|
1349 |
+bool |
|
1350 |
+get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity) |
|
1351 |
+{ |
|
1352 |
+ int std_out; |
|
1353 |
+ char cmd[256]; |
|
1354 |
+ bool ret = false; |
|
1355 |
+ struct argv argv; |
|
1356 |
+ |
|
1357 |
+ argv_init (&argv); |
|
1358 |
+ argv_printf (&argv, "/bin/systemd-ask-password"); |
|
1359 |
+ argv_printf_cat (&argv, "%s", prompt); |
|
1360 |
+ |
|
1361 |
+ if ((std_out = openvpn_popen (&argv, NULL)) < 0) { |
|
1362 |
+ return false; |
|
1363 |
+ } |
|
1364 |
+ CLEAR (*input); |
|
1365 |
+ if (read (std_out, input, capacity) != 0) |
|
1366 |
+ { |
|
1367 |
+ chomp (input); |
|
1368 |
+ ret = true; |
|
1369 |
+ } |
|
1370 |
+ close (std_out); |
|
1371 |
+ |
|
1372 |
+ argv_reset (&argv); |
|
1373 |
+ |
|
1374 |
+ return ret; |
|
1375 |
+} |
|
1376 |
+ |
|
1377 |
+ |
|
1378 |
+#endif |
|
1379 |
+ |
|
1380 |
+/* |
|
1331 | 1381 |
* Get input from console |
1332 | 1382 |
*/ |
1333 | 1383 |
bool |
... | ... |
@@ -1339,6 +1457,11 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c |
1339 | 1339 |
ASSERT (capacity > 0); |
1340 | 1340 |
input[0] = '\0'; |
1341 | 1341 |
|
1342 |
+#if defined(TARGET_LINUX) && defined(ENABLE_SYSTEMD) |
|
1343 |
+ if (check_systemd_running ()) |
|
1344 |
+ return get_console_input_systemd (prompt, echo, input, capacity); |
|
1345 |
+#endif |
|
1346 |
+ |
|
1342 | 1347 |
#if defined(WIN32) |
1343 | 1348 |
return get_console_input_win32 (prompt, echo, input, capacity); |
1344 | 1349 |
#elif defined(HAVE_GETPASS) |