Merge pull request #13632 from fbuihuu/ask-password-some-reworks

Ask password some reworks
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-10-08 09:20:40 +02:00 committed by GitHub
commit e0a0c64cb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 347 additions and 283 deletions

View file

@ -660,6 +660,21 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r; return r;
} }
int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
if (inotify_add_watch(fd, pathname, mask) < 0) {
const char *reason;
if (errno == ENOSPC)
reason = "inotify watch limit reached";
else
reason = strerror_safe(errno);
return log_error_errno(errno, "Failed to add a watch for %s: %s", pathname, reason);
}
return 0;
}
static bool unsafe_transition(const struct stat *a, const struct stat *b) { static bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files

View file

@ -72,6 +72,7 @@ union inotify_event_buffer {
}; };
int inotify_add_watch_fd(int fd, int what, uint32_t mask); int inotify_add_watch_fd(int fd, int what, uint32_t mask);
int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask);
enum { enum {
CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */ CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */

View file

@ -295,10 +295,12 @@ static int manager_check_ask_password(Manager *m) {
if (m->ask_password_inotify_fd < 0) if (m->ask_password_inotify_fd < 0)
return log_error_errno(errno, "Failed to create inotify object: %m"); return log_error_errno(errno, "Failed to create inotify object: %m");
if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) { r = inotify_add_watch_and_warn(m->ask_password_inotify_fd,
log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m"); "/run/systemd/ask-password",
IN_CREATE|IN_DELETE|IN_MOVE);
if (r < 0) {
manager_close_ask_password(m); manager_close_ask_password(m);
return -errno; return r;
} }
r = sd_event_add_io(m->event, &m->ask_password_event_source, r = sd_event_add_io(m->event, &m->ask_password_event_source,

View file

@ -89,24 +89,29 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
break; break;
} }
r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror_safe(r)); /* This second call to inotify_add_watch() should fail like the previous
if (cut) * one and is done for logging the error in a comprehensive way. */
*cut = tmp; r = inotify_add_watch_and_warn(s->inotify_fd, s->path, flags);
goto fail; if (r < 0) {
} else { if (cut)
exists = true; *cut = tmp;
goto fail;
/* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
(void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
/* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
} }
/* Hmm, we succeeded in adding the watch this time... let's continue. */
}
exists = true;
/* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
(void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
/* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
} }
if (cut) if (cut)

View file

@ -34,6 +34,7 @@
#include "memory-util.h" #include "memory-util.h"
#include "missing.h" #include "missing.h"
#include "mkdir.h" #include "mkdir.h"
#include "plymouth-util.h"
#include "process-util.h" #include "process-util.h"
#include "random-util.h" #include "random-util.h"
#include "signal-util.h" #include "signal-util.h"
@ -211,6 +212,186 @@ static int backspace_string(int ttyfd, const char *str) {
return backspace_chars(ttyfd, m); return backspace_chars(ttyfd, m);
} }
int ask_password_plymouth(
const char *message,
usec_t until,
AskPasswordFlags flags,
const char *flag_file,
char ***ret) {
static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -1, notify = -1;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
struct pollfd pollfd[2] = {};
char buffer[LINE_MAX];
size_t p = 0;
enum {
POLL_SOCKET,
POLL_INOTIFY
};
assert(ret);
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
if (notify < 0)
return -errno;
r = inotify_add_watch(notify, flag_file, IN_ATTRIB); /* for the link count */
if (r < 0)
return -errno;
}
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
packet = strdup("c");
n = 1;
} else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
packet = NULL;
if (!packet)
return -ENOMEM;
r = loop_write(fd, packet, n + 1, true);
if (r < 0)
return r;
pollfd[POLL_SOCKET].fd = fd;
pollfd[POLL_SOCKET].events = POLLIN;
pollfd[POLL_INOTIFY].fd = notify;
pollfd[POLL_INOTIFY].events = POLLIN;
for (;;) {
int sleep_for = -1, j;
if (until > 0) {
usec_t y;
y = now(CLOCK_MONOTONIC);
if (y > until) {
r = -ETIME;
goto finish;
}
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
}
if (flag_file && access(flag_file, F_OK) < 0) {
r = -errno;
goto finish;
}
j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (j < 0) {
if (errno == EINTR)
continue;
r = -errno;
goto finish;
} else if (j == 0) {
r = -ETIME;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
(void) flush_fd(notify);
if (pollfd[POLL_SOCKET].revents == 0)
continue;
k = read(fd, buffer + p, sizeof(buffer) - p);
if (k < 0) {
if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
goto finish;
} else if (k == 0) {
r = -EIO;
goto finish;
}
p += k;
if (p < 1)
continue;
if (buffer[0] == 5) {
if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
/* Hmm, first try with cached
* passwords failed, so let's retry
* with a normal password request */
packet = mfree(packet);
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
r = -ENOMEM;
goto finish;
}
r = loop_write(fd, packet, n+1, true);
if (r < 0)
goto finish;
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
p = 0;
continue;
}
/* No password, because UI not shown */
r = -ENOENT;
goto finish;
} else if (IN_SET(buffer[0], 2, 9)) {
uint32_t size;
char **l;
/* One or more answers */
if (p < 5)
continue;
memcpy(&size, buffer+1, sizeof(size));
size = le32toh(size);
if (size + 5 > sizeof(buffer)) {
r = -EIO;
goto finish;
}
if (p-5 < size)
continue;
l = strv_parse_nulstr(buffer + 5, size);
if (!l) {
r = -ENOMEM;
goto finish;
}
*ret = l;
break;
} else {
/* Unknown packet */
r = -EIO;
goto finish;
}
}
r = 0;
finish:
explicit_bzero_safe(buffer, sizeof(buffer));
return r;
}
int ask_password_tty( int ask_password_tty(
int ttyfd, int ttyfd,
const char *message, const char *message,
@ -371,6 +552,13 @@ int ask_password_tty(
if (n == 0 || c == '\n' || c == 0) if (n == 0 || c == '\n' || c == 0)
break; break;
if (c == 4) { /* C-d also known as EOT */
if (ttyfd >= 0)
(void) loop_write(ttyfd, "(skipped)", 9, false);
goto skipped;
}
if (c == 21) { /* C-u */ if (c == 21) { /* C-u */
if (!(flags & ASK_PASSWORD_SILENT)) if (!(flags & ASK_PASSWORD_SILENT))
@ -467,6 +655,7 @@ int ask_password_tty(
if (r < 0) if (r < 0)
goto finish; goto finish;
skipped:
if (keyname) if (keyname)
(void) add_to_keyring_and_log(keyname, flags, l); (void) add_to_keyring_and_log(keyname, flags, l);

View file

@ -16,5 +16,6 @@ typedef enum AskPasswordFlags {
} AskPasswordFlags; } AskPasswordFlags;
int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret); int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
int ask_password_plymouth(const char *message, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);

View file

@ -225,9 +225,9 @@ static int run(int argc, char * argv[]) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create notify event source: %m"); return log_error_errno(r, "Failed to create notify event source: %m");
r = inotify_add_watch(state.inotify_fd, "/run/systemd/", IN_CREATE); r = inotify_add_watch_and_warn(state.inotify_fd, "/run/systemd/", IN_CREATE);
if (r < 0) if (r < 0)
return log_error_errno(errno, "Failed to watch /run/systemd/: %m"); return r;
state.run_systemd_wd = r; state.run_systemd_wd = r;

View file

@ -11,7 +11,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <sys/inotify.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -29,6 +28,7 @@
#include "exit-status.h" #include "exit-status.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "io-util.h" #include "io-util.h"
#include "macro.h" #include "macro.h"
@ -36,7 +36,6 @@
#include "memory-util.h" #include "memory-util.h"
#include "mkdir.h" #include "mkdir.h"
#include "path-util.h" #include "path-util.h"
#include "plymouth-util.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "process-util.h" #include "process-util.h"
#include "set.h" #include "set.h"
@ -58,186 +57,6 @@ static bool arg_plymouth = false;
static bool arg_console = false; static bool arg_console = false;
static const char *arg_device = NULL; static const char *arg_device = NULL;
static int ask_password_plymouth(
const char *message,
usec_t until,
AskPasswordFlags flags,
const char *flag_file,
char ***ret) {
static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -1, notify = -1;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
struct pollfd pollfd[2] = {};
char buffer[LINE_MAX];
size_t p = 0;
enum {
POLL_SOCKET,
POLL_INOTIFY
};
assert(ret);
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
if (notify < 0)
return -errno;
r = inotify_add_watch(notify, flag_file, IN_ATTRIB); /* for the link count */
if (r < 0)
return -errno;
}
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
packet = strdup("c");
n = 1;
} else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
packet = NULL;
if (!packet)
return -ENOMEM;
r = loop_write(fd, packet, n + 1, true);
if (r < 0)
return r;
pollfd[POLL_SOCKET].fd = fd;
pollfd[POLL_SOCKET].events = POLLIN;
pollfd[POLL_INOTIFY].fd = notify;
pollfd[POLL_INOTIFY].events = POLLIN;
for (;;) {
int sleep_for = -1, j;
if (until > 0) {
usec_t y;
y = now(CLOCK_MONOTONIC);
if (y > until) {
r = -ETIME;
goto finish;
}
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
}
if (flag_file && access(flag_file, F_OK) < 0) {
r = -errno;
goto finish;
}
j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (j < 0) {
if (errno == EINTR)
continue;
r = -errno;
goto finish;
} else if (j == 0) {
r = -ETIME;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
(void) flush_fd(notify);
if (pollfd[POLL_SOCKET].revents == 0)
continue;
k = read(fd, buffer + p, sizeof(buffer) - p);
if (k < 0) {
if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
goto finish;
} else if (k == 0) {
r = -EIO;
goto finish;
}
p += k;
if (p < 1)
continue;
if (buffer[0] == 5) {
if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
/* Hmm, first try with cached
* passwords failed, so let's retry
* with a normal password request */
packet = mfree(packet);
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
r = -ENOMEM;
goto finish;
}
r = loop_write(fd, packet, n+1, true);
if (r < 0)
goto finish;
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
p = 0;
continue;
}
/* No password, because UI not shown */
r = -ENOENT;
goto finish;
} else if (IN_SET(buffer[0], 2, 9)) {
uint32_t size;
char **l;
/* One or more answers */
if (p < 5)
continue;
memcpy(&size, buffer+1, sizeof(size));
size = le32toh(size);
if (size + 5 > sizeof(buffer)) {
r = -EIO;
goto finish;
}
if (p-5 < size)
continue;
l = strv_parse_nulstr(buffer + 5, size);
if (!l) {
r = -ENOMEM;
goto finish;
}
*ret = l;
break;
} else {
/* Unknown packet */
r = -EIO;
goto finish;
}
}
r = 0;
finish:
explicit_bzero_safe(buffer, sizeof(buffer));
return r;
}
static int send_passwords(const char *socket_name, char **passwords) { static int send_passwords(const char *socket_name, char **passwords) {
_cleanup_(erase_and_freep) char *packet = NULL; _cleanup_(erase_and_freep) char *packet = NULL;
_cleanup_close_ int socket_fd = -1; _cleanup_close_ int socket_fd = -1;
@ -318,7 +137,40 @@ static bool wall_tty_match(const char *path, void *userdata) {
return 0; return 0;
} }
static int parse_password(const char *filename) { static int agent_ask_password_tty(
const char *message,
usec_t until,
AskPasswordFlags flags,
const char *flag_file,
char ***ret) {
int tty_fd = -1;
int r;
if (arg_console) {
const char *con = arg_device ?: "/dev/console";
tty_fd = acquire_terminal(con, ACQUIRE_TERMINAL_WAIT, USEC_INFINITY);
if (tty_fd < 0)
return log_error_errno(tty_fd, "Failed to acquire %s: %m", con);
r = reset_terminal_fd(tty_fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
r = ask_password_tty(tty_fd, message, NULL, until, flags, flag_file, ret);
if (arg_console) {
tty_fd = safe_close(tty_fd);
release_terminal();
}
return 0;
}
static int process_one_password_file(const char *filename) {
_cleanup_free_ char *socket_name = NULL, *message = NULL; _cleanup_free_ char *socket_name = NULL, *message = NULL;
bool accept_cached = false, echo = false; bool accept_cached = false, echo = false;
uint64_t not_after = 0; uint64_t not_after = 0;
@ -355,25 +207,28 @@ static int parse_password(const char *filename) {
if (pid > 0 && !pid_is_alive(pid)) if (pid > 0 && !pid_is_alive(pid))
return 0; return 0;
if (arg_action == ACTION_LIST) switch (arg_action) {
case ACTION_LIST:
printf("'%s' (PID %u)\n", message, pid); printf("'%s' (PID %u)\n", message, pid);
return 0;
else if (arg_action == ACTION_WALL) { case ACTION_WALL: {
_cleanup_free_ char *wall = NULL; _cleanup_free_ char *wall = NULL;
if (asprintf(&wall, if (asprintf(&wall,
"Password entry required for \'%s\' (PID %u).\r\n" "Password entry required for \'%s\' (PID %u).\r\n"
"Please enter password with the systemd-tty-ask-password-agent tool.", "Please enter password with the systemd-tty-ask-password-agent tool.",
message, message,
pid) < 0) pid) < 0)
return log_oom(); return log_oom();
(void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL); (void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
return 0;
} else { }
case ACTION_QUERY:
case ACTION_WATCH: {
_cleanup_strv_free_erase_ char **passwords = NULL; _cleanup_strv_free_erase_ char **passwords = NULL;
AskPasswordFlags flags = 0;
assert(IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH));
if (access(socket_name, W_OK) < 0) { if (access(socket_name, W_OK) < 0) {
if (arg_action == ACTION_QUERY) if (arg_action == ACTION_QUERY)
@ -382,44 +237,31 @@ static int parse_password(const char *filename) {
return 0; return 0;
} }
SET_FLAG(flags, ASK_PASSWORD_ACCEPT_CACHED, accept_cached);
SET_FLAG(flags, ASK_PASSWORD_CONSOLE_COLOR, arg_console);
SET_FLAG(flags, ASK_PASSWORD_ECHO, echo);
if (arg_plymouth) if (arg_plymouth)
r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords); r = ask_password_plymouth(message, not_after, flags, filename, &passwords);
else { else
int tty_fd = -1; r = agent_ask_password_tty(message, not_after, flags, filename, &passwords);
if (arg_console) { if (r < 0) {
const char *con = arg_device ?: "/dev/console"; /* If the query went away, that's OK */
if (IN_SET(r, -ETIME, -ENOENT))
return 0;
tty_fd = acquire_terminal(con, ACQUIRE_TERMINAL_WAIT, USEC_INFINITY); return log_error_errno(r, "Failed to query password: %m");
if (tty_fd < 0)
return log_error_errno(tty_fd, "Failed to acquire %s: %m", con);
r = reset_terminal_fd(tty_fd, true);
if (r < 0)
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
r = ask_password_tty(tty_fd, message, NULL, not_after,
(echo ? ASK_PASSWORD_ECHO : 0) |
(arg_console ? ASK_PASSWORD_CONSOLE_COLOR : 0),
filename, &passwords);
if (arg_console) {
tty_fd = safe_close(tty_fd);
release_terminal();
}
} }
/* If the query went away, that's OK */ if (strv_isempty(passwords))
if (IN_SET(r, -ETIME, -ENOENT)) return -ECANCELED;
return 0;
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
r = send_passwords(socket_name, passwords); r = send_passwords(socket_name, passwords);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to send: %m"); return log_error_errno(r, "Failed to send: %m");
break;
}
} }
return 0; return 0;
@ -449,7 +291,7 @@ static int wall_tty_block(void) {
return fd; return fd;
} }
static int show_passwords(void) { static int process_password_files(void) {
_cleanup_closedir_ DIR *d; _cleanup_closedir_ DIR *d;
struct dirent *de; struct dirent *de;
int r = 0; int r = 0;
@ -462,7 +304,7 @@ static int show_passwords(void) {
return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m"); return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m");
} }
FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) { FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read directory: %m")) {
_cleanup_free_ char *p = NULL; _cleanup_free_ char *p = NULL;
int q; int q;
@ -472,9 +314,6 @@ static int show_passwords(void) {
if (de->d_type != DT_REG) if (de->d_type != DT_REG)
continue; continue;
if (hidden_or_backup_file(de->d_name))
continue;
if (!startswith(de->d_name, "ask.")) if (!startswith(de->d_name, "ask."))
continue; continue;
@ -482,7 +321,7 @@ static int show_passwords(void) {
if (!p) if (!p)
return log_oom(); return log_oom();
q = parse_password(p); q = process_one_password_file(p);
if (q < 0 && r == 0) if (q < 0 && r == 0)
r = q; r = q;
} }
@ -490,10 +329,10 @@ static int show_passwords(void) {
return r; return r;
} }
static int watch_passwords(void) { static int process_and_watch_password_files(bool watch) {
enum { enum {
FD_INOTIFY,
FD_SIGNAL, FD_SIGNAL,
FD_INOTIFY,
_FD_MAX _FD_MAX
}; };
@ -506,36 +345,51 @@ static int watch_passwords(void) {
(void) mkdir_p_label("/run/systemd/ask-password", 0755); (void) mkdir_p_label("/run/systemd/ask-password", 0755);
notify = inotify_init1(IN_CLOEXEC);
if (notify < 0)
return log_error_errno(errno, "Failed to allocate directory watch: %m");
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
if (errno == ENOSPC)
return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: inotify watch limit reached");
else
return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
}
assert_se(sigemptyset(&mask) >= 0); assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0); assert_se(sigset_add_many(&mask, SIGTERM, -1) >= 0);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) >= 0); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) >= 0);
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); if (watch) {
if (signal_fd < 0) signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
return log_error_errno(errno, "Failed to allocate signal file descriptor: %m"); if (signal_fd < 0)
return log_error_errno(errno, "Failed to allocate signal file descriptor: %m");
pollfd[FD_INOTIFY].fd = notify; pollfd[FD_SIGNAL].fd = signal_fd;
pollfd[FD_INOTIFY].events = POLLIN; pollfd[FD_SIGNAL].events = POLLIN;
pollfd[FD_SIGNAL].fd = signal_fd;
pollfd[FD_SIGNAL].events = POLLIN; notify = inotify_init1(IN_CLOEXEC);
if (notify < 0)
return log_error_errno(errno, "Failed to allocate directory watch: %m");
r = inotify_add_watch_and_warn(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO);
if (r < 0)
return r;
pollfd[FD_INOTIFY].fd = notify;
pollfd[FD_INOTIFY].events = POLLIN;
}
for (;;) { for (;;) {
r = show_passwords(); int timeout = -1;
if (r < 0)
log_error_errno(r, "Failed to show password: %m");
if (poll(pollfd, _FD_MAX, -1) < 0) { r = process_password_files();
if (r < 0) {
if (r == -ECANCELED)
/* Disable poll() timeout since at least one password has
* been skipped and therefore one file remains and is
* unlikely to trigger any events. */
timeout = 0;
else
/* FIXME: we should do something here since otherwise the service
* requesting the password won't notice the error and will wait
* indefinitely. */
log_error_errno(r, "Failed to process password: %m");
}
if (!watch)
break;
if (poll(pollfd, watch ? _FD_MAX : _FD_MAX-1, timeout) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
@ -856,10 +710,7 @@ static int run(int argc, char *argv[]) {
(void) release_terminal(); (void) release_terminal();
} }
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL)) return process_and_watch_password_files(arg_action != ACTION_QUERY);
return watch_passwords();
else
return show_passwords();
} }
DEFINE_MAIN_FUNCTION(run); DEFINE_MAIN_FUNCTION(run);