286 lines
10 KiB
Diff
286 lines
10 KiB
Diff
---
|
|
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;
|
|
}
|