mirror of
https://github.com/systemd/systemd
synced 2024-10-14 12:04:49 +00:00
Merge pull request #13632 from fbuihuu/ask-password-some-reworks
Ask password some reworks
This commit is contained in:
commit
e0a0c64cb9
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue