systemd/tty-ask-password-agent-on-console.patch

286 lines
10 KiB
Diff
Raw Normal View History

---
src/tty-ask-password-agent/tty-ask-password-agent.c | 190 +++++++++++++++++++-
1 file changed, 185 insertions(+), 5 deletions(-)
--- systemd-210/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ systemd-210/src/tty-ask-password-agent/tty-ask-password-agent.c 2014-07-30 10:48:43.602052750 +0000
@@ -28,8 +28,12 @@
#include <sys/poll.h>
#include <sys/inotify.h>
#include <unistd.h>
+#include <sys/prctl.h>
#include <getopt.h>
+#include <signal.h>
+#include <sys/wait.h>
#include <sys/signalfd.h>
+#include <sys/mman.h>
#include <fcntl.h>
#include "util.h"
@@ -41,6 +45,9 @@
#include "ask-password-api.h"
#include "strv.h"
#include "build.h"
+#include "fileio.h"
+#include "macro.h"
+#include "list.h"
static enum {
ACTION_LIST,
@@ -49,6 +56,21 @@ static enum {
ACTION_WALL
} arg_action = ACTION_QUERY;
+struct console {
+ LIST_FIELDS(struct console, handle);
+ char *tty;
+ pid_t pid;
+ int id;
+};
+
+static volatile uint32_t *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;
@@ -246,12 +268,77 @@ finish:
return r;
}
+static const char *current_dev = "/dev/console";
+static LIST_HEAD(struct console, consoles);
+static int collect_consoles(void) {
+ _cleanup_free_ char *active = NULL;
+ char *w, *state;
+ struct console *c;
+ size_t l;
+ int id;
+ int r;
+
+ r = read_one_line_file("/sys/class/tty/console/active", &active);
+ if (r < 0)
+ return r;
+
+ id = 0;
+ FOREACH_WORD(w, l, active, state) {
+ _cleanup_free_ char *tty = NULL;
+
+ if (strneq(w, "tty0", l)) {
+ if (read_one_line_file("/sys/class/tty/tty0/active", &tty) >= 0) {
+ w = tty;
+ l = strlen(tty);
+ }
+ }
+
+ c = malloc0(sizeof(struct console)+5+l+1);
+ if (!c) {
+ log_oom();
+ continue;
+ }
+
+ c->tty = ((char*)c)+sizeof(struct console);
+ stpncpy(stpcpy(c->tty, "/dev/"),w,l);
+ c->id = id++;
+
+ LIST_PREPEND(handle, consoles, c);
+ }
+
+ if (!consoles) {
+
+ c = malloc0(sizeof(struct console));
+ if (!c) {
+ log_oom();
+ return -ENOMEM;
+ }
+
+ c->tty = (char *)current_dev;
+ c->id = id++;
+
+ LIST_PREPEND(handle, consoles, c);
+ }
+
+ return 0;
+}
+
+static void free_consoles(void) {
+ struct console *c;
+ LIST_FOREACH(handle, c, consoles) {
+ LIST_REMOVE(handle, consoles, c);
+ free(c);
+ }
+ LIST_HEAD_INIT(consoles);
+}
+
static int parse_password(const char *filename, char **wall) {
char *socket_name = NULL, *message = NULL, *packet = NULL;
uint64_t not_after = 0;
unsigned pid = 0;
int socket_fd = -1;
bool accept_cached = false;
+ size_t packet_length = 0;
const ConfigTableItem items[] = {
{ "Ask", "Socket", config_parse_string, 0, &socket_name },
@@ -323,7 +410,6 @@ static int parse_password(const char *fi
struct sockaddr sa;
struct sockaddr_un un;
} sa = {};
- size_t packet_length = 0;
assert(arg_action == ACTION_QUERY ||
arg_action == ACTION_WATCH);
@@ -365,7 +451,7 @@ static int parse_password(const char *fi
char *password = NULL;
if (arg_console)
- if ((tty_fd = acquire_terminal("/dev/console", false, false, false, (usec_t) -1)) < 0) {
+ if ((tty_fd = acquire_terminal(current_dev, false, false, true, (usec_t) -1)) < 0) {
r = tty_fd;
goto finish;
}
@@ -386,6 +472,7 @@ static int parse_password(const char *fi
strcpy(packet+1, password);
}
+ memset(password, 0, strlen(password));
free(password);
}
}
@@ -423,6 +510,7 @@ finish:
if (socket_fd >= 0)
close_nointr_nofail(socket_fd);
+ memset(packet, 0, packet_length);
free(packet);
free(socket_name);
free(message);
@@ -726,8 +814,10 @@ static int parse_argv(int argc, char *ar
}
int main(int argc, char *argv[]) {
+ int id = 0;
int r;
+ LIST_HEAD_INIT(consoles);
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
@@ -737,11 +827,99 @@ int main(int argc, char *argv[]) {
if ((r = parse_argv(argc, argv)) <= 0)
goto finish;
+ usemask = (uint32_t*) mmap(NULL, sizeof(uint32_t), PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_SHARED, -1, 0);
+
if (arg_console) {
- setsid();
- release_terminal();
- }
+ if (!arg_plymouth && arg_action != ACTION_WALL &&
+ arg_action != ACTION_LIST) {
+ struct console *c;
+ struct sigaction sig = {
+ .sa_handler = chld_handler,
+ .sa_flags = SA_NOCLDSTOP|SA_RESTART,
+ };
+ struct sigaction oldsig;
+ sigset_t set, oldset;
+ int status = 0;
+ pid_t job;
+
+ collect_consoles();
+
+ if (!consoles->handle_next) {
+ consoles->pid = 0;
+ c = consoles;
+ goto nofork;
+ }
+ 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);
+ LIST_FOREACH(handle, c, consoles) {
+
+ switch ((c->pid = fork())) {
+ case 0:
+ 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);
+ /* fall through */
+ nofork:
+ setsid();
+ release_terminal();
+ id = c->id;
+ *usemask |= (1<<id);
+ current_dev = c->tty;
+ goto forked; /* child */
+ case -1:
+ log_error("Failed to query password: %s", strerror(errno));
+ return EXIT_FAILURE;
+ default:
+ break;
+ }
+ }
+
+ r = 0;
+ while ((job = wait(&status))) {
+ if (job < 0) {
+ if (errno != EINTR)
+ break;
+ continue;
+ }
+ LIST_FOREACH(handle, c, consoles) {
+ if (c->pid == job) {
+ *usemask &= ~(1<<c->id);
+ continue;
+ }
+ if (kill(c->pid, 0) < 0) {
+ *usemask &= ~(1<<c->id);
+ continue;
+ }
+ if (*usemask & (1<<c->id))
+ continue;
+ kill(c->pid, SIGHUP);
+ usleep(50000);
+ kill(c->pid, SIGKILL);
+ }
+
+ if (WIFEXITED(status) && !r)
+ r = WEXITSTATUS(status);
+ }
+ free_consoles();
+ return r != 0 ? EXIT_FAILURE : EXIT_SUCCESS; /* parent */
+
+ } else {
+ setsid();
+ release_terminal();
+ }
+ }
+forked:
if (arg_action == ACTION_WATCH ||
arg_action == ACTION_WALL)
r = watch_passwords();
@@ -751,6 +929,8 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error("Error: %s", strerror(-r));
+ free_consoles();
+ *usemask &= ~(1<<id);
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}