2015-09-25 16:21:57 +02:00
|
|
|
From 633a5904c1c4e363a7147f47e2d9fdb1925f7b9f Mon Sep 17 00:00:00 2001
|
|
|
|
From: Werner Fink <werner@suse.de>
|
|
|
|
Date: Fri, 25 Sep 2015 14:28:58 +0200
|
|
|
|
Subject: [PATCH] Ask for passphrases not only on the first console of
|
|
|
|
/dev/console
|
|
|
|
|
|
|
|
but also on all other consoles. This does help on e.g. mainframes
|
|
|
|
where often a serial console together with other consoles are
|
|
|
|
used. Even rack based servers attachted to both a serial console
|
|
|
|
as well as having a virtual console do sometimes miss a connected
|
|
|
|
monitor.
|
2015-02-16 12:36:25 +01:00
|
|
|
---
|
2015-09-25 16:21:57 +02:00
|
|
|
src/tty-ask-password-agent/tty-ask-password-agent.c | 191 ++++++++++++++++++++-
|
|
|
|
1 file changed, 186 insertions(+), 5 deletions(-)
|
2015-02-16 12:36:25 +01:00
|
|
|
|
2015-09-25 16:21:57 +02:00
|
|
|
diff --git src/tty-ask-password-agent/tty-ask-password-agent.c src/tty-ask-password-agent/tty-ask-password-agent.c
|
|
|
|
index 82cbf95..928a5e8 100644
|
|
|
|
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
|
|
|
|
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
|
2015-02-16 12:36:25 +01:00
|
|
|
@@ -31,6 +31,10 @@
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <sys/signalfd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
+#include <sys/prctl.h>
|
|
|
|
+#include <signal.h>
|
|
|
|
+#include <sys/wait.h>
|
|
|
|
+#include <sys/mman.h>
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
#include "mkdir.h"
|
2015-07-03 13:19:08 +02:00
|
|
|
@@ -45,6 +49,8 @@
|
2015-06-23 14:56:50 +02:00
|
|
|
#include "process-util.h"
|
|
|
|
#include "terminal-util.h"
|
|
|
|
#include "signal-util.h"
|
2015-07-03 13:19:08 +02:00
|
|
|
+#include "fileio.h"
|
|
|
|
+#include "macro.h"
|
|
|
|
|
|
|
|
static enum {
|
|
|
|
ACTION_LIST,
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -53,6 +59,19 @@ static enum {
|
2015-02-16 12:36:25 +01:00
|
|
|
ACTION_WALL
|
|
|
|
} arg_action = ACTION_QUERY;
|
|
|
|
|
|
|
|
+struct console {
|
|
|
|
+ pid_t pid;
|
2015-09-25 16:21:57 +02:00
|
|
|
+ char *tty;
|
2015-02-16 12:36:25 +01:00
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static volatile unsigned long *usemask;
|
|
|
|
+static volatile sig_atomic_t sigchild;
|
|
|
|
+static void chld_handler(int sig)
|
|
|
|
+{
|
|
|
|
+ (void)sig;
|
|
|
|
+ ++sigchild;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static bool arg_plymouth = false;
|
|
|
|
static bool arg_console = false;
|
|
|
|
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -210,6 +229,69 @@ static int ask_password_plymouth(
|
2015-02-16 12:36:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-25 16:21:57 +02:00
|
|
|
+static void free_consoles(struct console *con, const unsigned int num) {
|
|
|
|
+ unsigned int n;
|
|
|
|
+ if (!con || !num)
|
|
|
|
+ return;
|
|
|
|
+ for (n = 0; n < num; n++)
|
|
|
|
+ free(con[n].tty);
|
|
|
|
+ free(con);
|
|
|
|
+}
|
|
|
|
+
|
2015-02-16 12:36:25 +01:00
|
|
|
+static const char *current_dev = "/dev/console";
|
2015-09-25 16:21:57 +02:00
|
|
|
+static struct console* collect_consoles(unsigned int * num) {
|
2015-02-16 12:36:25 +01:00
|
|
|
+ _cleanup_free_ char *active = NULL;
|
|
|
|
+ const char *word, *state;
|
2015-07-03 13:19:08 +02:00
|
|
|
+ struct console *con = NULL;
|
2015-09-25 16:21:57 +02:00
|
|
|
+ size_t con_len = 0, len;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ assert(num);
|
|
|
|
+ assert(*num == 0);
|
2015-02-16 12:36:25 +01:00
|
|
|
+
|
|
|
|
+ ret = read_one_line_file("/sys/class/tty/console/active", &active);
|
|
|
|
+ if (ret < 0)
|
2015-07-03 13:19:08 +02:00
|
|
|
+ return con;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ FOREACH_WORD(word, len, active, state) {
|
|
|
|
+ _cleanup_free_ char *tty = NULL;
|
|
|
|
+
|
|
|
|
+ if (strneq(word, "tty0", len) &&
|
|
|
|
+ read_one_line_file("/sys/class/tty/tty0/active", &tty) >= 0) {
|
|
|
|
+ word = tty;
|
|
|
|
+ len = strlen(tty);
|
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ con = greedy_realloc((void**)&con, &con_len, 1+(*num), sizeof(struct console));
|
2015-02-16 12:36:25 +01:00
|
|
|
+ if (con == NULL) {
|
|
|
|
+ log_oom();
|
2015-09-25 16:21:57 +02:00
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ if (asprintf(&con[*num].tty, "/dev/%.*s", (int)len, word) < 0) {
|
|
|
|
+ free_consoles(con, *num);
|
|
|
|
+ log_oom();
|
|
|
|
+ *num = 0;
|
|
|
|
+ return NULL;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ con[*num].pid = 0;
|
|
|
|
+ (*num)++;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
2015-07-03 13:19:08 +02:00
|
|
|
+ if (con == NULL) {
|
|
|
|
+ con = greedy_realloc((void**)&con, &con_len, 1, sizeof(struct console));
|
2015-02-16 12:36:25 +01:00
|
|
|
+ if (con == NULL) {
|
|
|
|
+ log_oom();
|
2015-09-25 16:21:57 +02:00
|
|
|
+ return NULL;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ con[0].tty = strdup(current_dev);
|
|
|
|
+ if (con[0].tty == NULL) {
|
|
|
|
+ free_consoles(con, 1);
|
|
|
|
+ log_oom();
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ con[0].pid = 0;
|
|
|
|
+ (*num)++;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
2015-07-03 13:19:08 +02:00
|
|
|
+ return con;
|
2015-02-16 12:36:25 +01:00
|
|
|
+}
|
|
|
|
+
|
|
|
|
static int parse_password(const char *filename, char **wall) {
|
|
|
|
_cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL;
|
|
|
|
uint64_t not_after = 0;
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -310,7 +392,7 @@ static int parse_password(const char *filename, char **wall) {
|
2015-02-16 12:36:25 +01:00
|
|
|
_cleanup_free_ char *password = NULL;
|
|
|
|
|
|
|
|
if (arg_console) {
|
|
|
|
- tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
|
|
|
|
+ tty_fd = acquire_terminal(current_dev, false, false, false, USEC_INFINITY);
|
|
|
|
if (tty_fd < 0)
|
|
|
|
return tty_fd;
|
|
|
|
}
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -614,8 +696,90 @@ static int parse_argv(int argc, char *argv[]) {
|
2015-02-16 12:36:25 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-25 16:21:57 +02:00
|
|
|
+static unsigned int wfa_child(const struct console * con, const unsigned int id)
|
|
|
|
+{
|
|
|
|
+ setsid();
|
|
|
|
+ release_terminal();
|
|
|
|
+ *usemask |= 1 << id; /* shared memory area */
|
|
|
|
+ current_dev = con[id].tty;
|
|
|
|
+ return id;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned int wait_for_answer(void)
|
2015-02-16 12:36:25 +01:00
|
|
|
+{
|
2015-07-03 13:19:08 +02:00
|
|
|
+ struct console *consoles;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ struct sigaction sig = {
|
|
|
|
+ .sa_handler = chld_handler,
|
|
|
|
+ .sa_flags = SA_NOCLDSTOP | SA_RESTART,
|
|
|
|
+ };
|
|
|
|
+ struct sigaction oldsig;
|
|
|
|
+ sigset_t set, oldset;
|
2015-09-25 16:21:57 +02:00
|
|
|
+ unsigned int num = 0, id;
|
|
|
|
+ int status = 0, ret;
|
2015-02-16 12:36:25 +01:00
|
|
|
+ pid_t job;
|
|
|
|
+
|
2015-07-03 13:19:08 +02:00
|
|
|
+ consoles = collect_consoles(&num);
|
|
|
|
+ if (!consoles) {
|
|
|
|
+ log_error("Failed to query password: %m");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ if (num < 2)
|
|
|
|
+ return wfa_child(consoles, 0);
|
2015-02-16 12:36:25 +01:00
|
|
|
+
|
|
|
|
+ assert_se(sigemptyset(&set) == 0);
|
|
|
|
+ assert_se(sigaddset(&set, SIGHUP) == 0);
|
|
|
|
+ assert_se(sigaddset(&set, SIGCHLD) == 0);
|
|
|
|
+ assert_se(sigemptyset(&sig.sa_mask) == 0);
|
|
|
|
+ assert_se(sigprocmask(SIG_UNBLOCK, &set, &oldset) == 0);
|
|
|
|
+ assert_se(sigaction(SIGCHLD, &sig, &oldsig) == 0);
|
|
|
|
+ sig.sa_handler = SIG_DFL;
|
|
|
|
+ assert_se(sigaction(SIGHUP, &sig, NULL) == 0);
|
|
|
|
+
|
2015-09-25 16:21:57 +02:00
|
|
|
+ for (id = 0; id < num; id++) {
|
|
|
|
+ consoles[id].pid = fork();
|
2015-07-03 13:19:08 +02:00
|
|
|
+
|
2015-09-25 16:21:57 +02:00
|
|
|
+ if (consoles[id].pid < 0) {
|
2015-07-03 13:19:08 +02:00
|
|
|
+ log_error("Failed to query password: %m");
|
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
|
+ }
|
|
|
|
+
|
2015-09-25 16:21:57 +02:00
|
|
|
+ if (consoles[id].pid == 0) {
|
2015-02-16 12:36:25 +01:00
|
|
|
+ if (prctl(PR_SET_PDEATHSIG, SIGHUP) < 0)
|
|
|
|
+ _exit(EXIT_FAILURE);
|
|
|
|
+ zero(sig);
|
|
|
|
+ assert_se(sigprocmask(SIG_UNBLOCK, &oldset, NULL) == 0);
|
|
|
|
+ assert_se(sigaction(SIGCHLD, &oldsig, NULL) == 0);
|
2015-09-25 16:21:57 +02:00
|
|
|
+ return wfa_child(consoles, id);
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = 0;
|
|
|
|
+ while ((job = wait(&status)) != 0) {
|
|
|
|
+ if (job < 0) {
|
|
|
|
+ if (errno != EINTR)
|
|
|
|
+ break;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ for (id = 0; id < num; id++) {
|
|
|
|
+ if (consoles[id].pid == job || kill(consoles[id].pid, 0) < 0) {
|
|
|
|
+ *usemask &= ~(1 << id); /* shared memory area */
|
2015-02-16 12:36:25 +01:00
|
|
|
+ continue;
|
|
|
|
+ }
|
2015-09-25 16:21:57 +02:00
|
|
|
+ if (*usemask & (1 << id)) /* shared memory area */
|
2015-02-16 12:36:25 +01:00
|
|
|
+ continue;
|
2015-09-25 16:21:57 +02:00
|
|
|
+ kill(consoles[id].pid, SIGHUP);
|
2015-02-16 12:36:25 +01:00
|
|
|
+ usleep(50000);
|
2015-09-25 16:21:57 +02:00
|
|
|
+ kill(consoles[id].pid, SIGKILL);
|
2015-02-16 12:36:25 +01:00
|
|
|
+ }
|
|
|
|
+ if (WIFEXITED(status) && ret == 0)
|
|
|
|
+ ret = WEXITSTATUS(status);
|
|
|
|
+ }
|
2015-07-03 13:19:08 +02:00
|
|
|
+ free_consoles(consoles, num);
|
2015-02-16 12:36:25 +01:00
|
|
|
+ exit(ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS); /* parent */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
- int r;
|
|
|
|
+ int r, id = 0;
|
|
|
|
|
|
|
|
log_set_target(LOG_TARGET_AUTO);
|
|
|
|
log_parse_environment();
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -627,11 +791,27 @@ int main(int argc, char *argv[]) {
|
2015-02-16 12:36:25 +01:00
|
|
|
if (r <= 0)
|
|
|
|
goto finish;
|
|
|
|
|
2015-07-03 13:19:08 +02:00
|
|
|
+ /*
|
|
|
|
+ * Use this shared memory area to be able to synchronize the
|
|
|
|
+ * workers asking for password with the main process.
|
|
|
|
+ * This allows to continue if one of the consoles had been
|
|
|
|
+ * used as afterwards the remaining asking processes will
|
|
|
|
+ * be terminated. The wait_for_terminate() does not help
|
|
|
|
+ * for this use case.
|
|
|
|
+ */
|
2015-02-16 12:36:25 +01:00
|
|
|
+ usemask = mmap(NULL, sizeof(*usemask), PROT_READ | PROT_WRITE,
|
|
|
|
+ MAP_ANONYMOUS | MAP_SHARED, -1, 0);
|
|
|
|
+ assert_se(usemask != NULL);
|
|
|
|
+
|
|
|
|
if (arg_console) {
|
|
|
|
- setsid();
|
|
|
|
- release_terminal();
|
2015-09-25 16:21:57 +02:00
|
|
|
+ if (!arg_plymouth &&
|
|
|
|
+ !IN_SET(arg_action, ACTION_WALL, ACTION_LIST)) {
|
2015-07-03 13:19:08 +02:00
|
|
|
+ id = wait_for_answer();
|
2015-02-16 12:36:25 +01:00
|
|
|
+ } else {
|
|
|
|
+ setsid();
|
|
|
|
+ release_terminal();
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
-
|
|
|
|
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
|
|
|
|
r = watch_passwords();
|
|
|
|
else
|
2015-09-25 16:21:57 +02:00
|
|
|
@@ -640,6 +820,7 @@ int main(int argc, char *argv[]) {
|
2015-02-16 12:36:25 +01:00
|
|
|
if (r < 0)
|
|
|
|
log_error_errno(r, "Error: %m");
|
|
|
|
|
2015-09-25 16:21:57 +02:00
|
|
|
+ *usemask &= ~(1 << id); /* shared memory area */
|
2015-02-16 12:36:25 +01:00
|
|
|
finish:
|
|
|
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
|
|
}
|
2015-09-25 16:21:57 +02:00
|
|
|
--
|
|
|
|
2.2.0
|
|
|
|
|