mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-08-30 05:50:12 +03:00
Merge pull request #3247 from fbuihuu/ask-passowrd-on-all-consoles
ask-password: ask for passphrases not only on the first console
This commit is contained in:
@ -50,6 +50,7 @@
|
|||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
#include "strv.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -708,6 +709,64 @@ char *resolve_dev_console(char **active) {
|
|||||||
return tty;
|
return tty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_kernel_consoles(char ***consoles) {
|
||||||
|
_cleanup_strv_free_ char **con = NULL;
|
||||||
|
_cleanup_free_ char *line = NULL;
|
||||||
|
const char *active;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(consoles);
|
||||||
|
|
||||||
|
r = read_one_line_file("/sys/class/tty/console/active", &line);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
active = line;
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *tty = NULL;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
r = extract_first_word(&active, &tty, NULL, 0);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (streq(tty, "tty0")) {
|
||||||
|
tty = mfree(tty);
|
||||||
|
r = read_one_line_file("/sys/class/tty/tty0/active", &tty);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = strappend("/dev/", tty);
|
||||||
|
if (!path)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (access(path, F_OK) < 0) {
|
||||||
|
log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path);
|
||||||
|
free(path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strv_consume(&con, path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strv_isempty(con)) {
|
||||||
|
log_debug("No devices found for system console");
|
||||||
|
|
||||||
|
r = strv_extend(&con, "/dev/console");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
*consoles = con;
|
||||||
|
con = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool tty_is_vc_resolve(const char *tty) {
|
bool tty_is_vc_resolve(const char *tty) {
|
||||||
_cleanup_free_ char *active = NULL;
|
_cleanup_free_ char *active = NULL;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
|
|||||||
int vt_disallocate(const char *name);
|
int vt_disallocate(const char *name);
|
||||||
|
|
||||||
char *resolve_dev_console(char **active);
|
char *resolve_dev_console(char **active);
|
||||||
|
int get_kernel_consoles(char ***consoles);
|
||||||
bool tty_is_vc(const char *tty);
|
bool tty_is_vc(const char *tty);
|
||||||
bool tty_is_vc_resolve(const char *tty);
|
bool tty_is_vc_resolve(const char *tty);
|
||||||
bool tty_is_console(const char *tty) _pure_;
|
bool tty_is_console(const char *tty) _pure_;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
This file is part of systemd.
|
This file is part of systemd.
|
||||||
|
|
||||||
Copyright 2010 Lennart Poettering
|
Copyright 2010 Lennart Poettering
|
||||||
|
Copyright 2015 Werner Fink
|
||||||
|
|
||||||
systemd is free software; you can redistribute it and/or modify it
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
under the terms of the GNU Lesser General Public License as published by
|
under the terms of the GNU Lesser General Public License as published by
|
||||||
@ -21,12 +22,15 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -35,8 +39,12 @@
|
|||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
|
#include "exit-status.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
|
#include "hashmap.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
#include "macro.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
@ -57,6 +65,7 @@ static enum {
|
|||||||
|
|
||||||
static bool arg_plymouth = false;
|
static bool arg_plymouth = false;
|
||||||
static bool arg_console = false;
|
static bool arg_console = false;
|
||||||
|
static const char *arg_device = NULL;
|
||||||
|
|
||||||
static int ask_password_plymouth(
|
static int ask_password_plymouth(
|
||||||
const char *message,
|
const char *message,
|
||||||
@ -354,7 +363,9 @@ static int parse_password(const char *filename, char **wall) {
|
|||||||
int tty_fd = -1;
|
int tty_fd = -1;
|
||||||
|
|
||||||
if (arg_console) {
|
if (arg_console) {
|
||||||
tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
|
const char *con = arg_device ? arg_device : "/dev/console";
|
||||||
|
|
||||||
|
tty_fd = acquire_terminal(con, false, false, false, USEC_INFINITY);
|
||||||
if (tty_fd < 0)
|
if (tty_fd < 0)
|
||||||
return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
|
return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
|
||||||
|
|
||||||
@ -586,14 +597,14 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
{ "version", no_argument, NULL, ARG_VERSION },
|
||||||
{ "list", no_argument, NULL, ARG_LIST },
|
{ "list", no_argument, NULL, ARG_LIST },
|
||||||
{ "query", no_argument, NULL, ARG_QUERY },
|
{ "query", no_argument, NULL, ARG_QUERY },
|
||||||
{ "watch", no_argument, NULL, ARG_WATCH },
|
{ "watch", no_argument, NULL, ARG_WATCH },
|
||||||
{ "wall", no_argument, NULL, ARG_WALL },
|
{ "wall", no_argument, NULL, ARG_WALL },
|
||||||
{ "plymouth", no_argument, NULL, ARG_PLYMOUTH },
|
{ "plymouth", no_argument, NULL, ARG_PLYMOUTH },
|
||||||
{ "console", no_argument, NULL, ARG_CONSOLE },
|
{ "console", optional_argument, NULL, ARG_CONSOLE },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -635,6 +646,15 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
|
|
||||||
case ARG_CONSOLE:
|
case ARG_CONSOLE:
|
||||||
arg_console = true;
|
arg_console = true;
|
||||||
|
if (optarg) {
|
||||||
|
|
||||||
|
if (isempty(optarg)) {
|
||||||
|
log_error("Empty console device path is not allowed.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_device = optarg;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
@ -649,9 +669,171 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_plymouth || arg_console) {
|
||||||
|
|
||||||
|
if (!IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH)) {
|
||||||
|
log_error("Options --query and --watch conflict.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_plymouth && arg_console) {
|
||||||
|
log_error("Options --plymouth and --console conflict.");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To be able to ask on all terminal devices of /dev/console
|
||||||
|
* the devices are collected. If more than one device is found,
|
||||||
|
* then on each of the terminals a inquiring task is forked.
|
||||||
|
* Every task has its own session and its own controlling terminal.
|
||||||
|
* If one of the tasks does handle a password, the remaining tasks
|
||||||
|
* will be terminated.
|
||||||
|
*/
|
||||||
|
static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv[]) {
|
||||||
|
struct sigaction sig = {
|
||||||
|
.sa_handler = nop_signal_handler,
|
||||||
|
.sa_flags = SA_NOCLDSTOP | SA_RESTART,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
|
||||||
|
|
||||||
|
assert_se(sigemptyset(&sig.sa_mask) >= 0);
|
||||||
|
assert_se(sigaction(SIGCHLD, &sig, NULL) >= 0);
|
||||||
|
|
||||||
|
sig.sa_handler = SIG_DFL;
|
||||||
|
assert_se(sigaction(SIGHUP, &sig, NULL) >= 0);
|
||||||
|
|
||||||
|
*pid = fork();
|
||||||
|
if (*pid < 0)
|
||||||
|
return log_error_errno(errno, "Failed to fork process: %m");
|
||||||
|
|
||||||
|
if (*pid == 0) {
|
||||||
|
int ac;
|
||||||
|
|
||||||
|
assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0);
|
||||||
|
|
||||||
|
reset_signal_mask();
|
||||||
|
reset_all_signal_handlers();
|
||||||
|
|
||||||
|
for (ac = 0; ac < argc; ac++) {
|
||||||
|
if (streq(argv[ac], "--console")) {
|
||||||
|
argv[ac] = strjoina("--console=", tty, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(ac < argc);
|
||||||
|
|
||||||
|
execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void terminate_agents(Set *pids) {
|
||||||
|
struct timespec ts;
|
||||||
|
siginfo_t status = {};
|
||||||
|
sigset_t set;
|
||||||
|
Iterator i;
|
||||||
|
void *p;
|
||||||
|
int r, signum;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Request termination of the remaining processes as those
|
||||||
|
* are not required anymore.
|
||||||
|
*/
|
||||||
|
SET_FOREACH(p, pids, i)
|
||||||
|
(void) kill(PTR_TO_PID(p), SIGTERM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collect the processes which have go away.
|
||||||
|
*/
|
||||||
|
assert_se(sigemptyset(&set) >= 0);
|
||||||
|
assert_se(sigaddset(&set, SIGCHLD) >= 0);
|
||||||
|
timespec_store(&ts, 50 * USEC_PER_MSEC);
|
||||||
|
|
||||||
|
while (!set_isempty(pids)) {
|
||||||
|
|
||||||
|
zero(status);
|
||||||
|
r = waitid(P_ALL, 0, &status, WEXITED|WNOHANG);
|
||||||
|
if (r < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (r == 0 && status.si_pid > 0) {
|
||||||
|
set_remove(pids, PID_TO_PTR(status.si_pid));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
signum = sigtimedwait(&set, NULL, &ts);
|
||||||
|
if (signum < 0) {
|
||||||
|
if (errno != EAGAIN)
|
||||||
|
log_error_errno(errno, "sigtimedwait() failed: %m");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assert(signum == SIGCHLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kill hanging processes.
|
||||||
|
*/
|
||||||
|
SET_FOREACH(p, pids, i) {
|
||||||
|
log_warning("Failed to terminate child %d, killing it", PTR_TO_PID(p));
|
||||||
|
(void) kill(PTR_TO_PID(p), SIGKILL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ask_on_consoles(int argc, char *argv[]) {
|
||||||
|
_cleanup_set_free_ Set *pids = NULL;
|
||||||
|
_cleanup_strv_free_ char **consoles = NULL;
|
||||||
|
siginfo_t status = {};
|
||||||
|
char **tty;
|
||||||
|
pid_t pid;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = get_kernel_consoles(&consoles);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine devices of /dev/console: %m");
|
||||||
|
|
||||||
|
pids = set_new(NULL);
|
||||||
|
if (!pids)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
/* Start an agent on each console. */
|
||||||
|
STRV_FOREACH(tty, consoles) {
|
||||||
|
r = ask_on_this_console(*tty, &pid, argc, argv);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (set_put(pids, PID_TO_PTR(pid)) < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for an agent to exit. */
|
||||||
|
for (;;) {
|
||||||
|
zero(status);
|
||||||
|
|
||||||
|
if (waitid(P_ALL, 0, &status, WEXITED) < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return log_error_errno(errno, "waitid() failed: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_remove(pids, PID_TO_PTR(status.si_pid));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_clean_exit(status.si_code, status.si_status, NULL))
|
||||||
|
log_error("Password agent failed with: %d", status.si_status);
|
||||||
|
|
||||||
|
terminate_agents(pids);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -665,15 +847,28 @@ int main(int argc, char *argv[]) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
if (arg_console) {
|
if (arg_console && !arg_device)
|
||||||
(void) setsid();
|
/*
|
||||||
(void) release_terminal();
|
* Spawn for each console device a separate process.
|
||||||
}
|
*/
|
||||||
|
r = ask_on_consoles(argc, argv);
|
||||||
|
else {
|
||||||
|
|
||||||
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
|
if (arg_device) {
|
||||||
r = watch_passwords();
|
/*
|
||||||
else
|
* Later on, a controlling terminal will be acquired,
|
||||||
r = show_passwords();
|
* therefore the current process has to become a session
|
||||||
|
* leader and should not have a controlling terminal already.
|
||||||
|
*/
|
||||||
|
(void) setsid();
|
||||||
|
(void) release_terminal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
|
||||||
|
r = watch_passwords();
|
||||||
|
else
|
||||||
|
r = show_passwords();
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
|
Reference in New Issue
Block a user