mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
ask-password-api: add support for querying pws from unpriv agents
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "inotify-util.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "keyring-util.h"
|
||||
@@ -86,6 +87,28 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ask_password_directory_for_flags(AskPasswordFlags flags, char **ret) {
|
||||
if (FLAGS_SET(flags, ASK_PASSWORD_USER))
|
||||
return acquire_user_ask_password_directory(ret);
|
||||
|
||||
return strdup_to_full(ret, "/run/systemd/ask-password/"); /* Returns 1, indicating there's a suitable directory */
|
||||
}
|
||||
|
||||
static int touch_ask_password_directory(AskPasswordFlags flags) {
|
||||
int r;
|
||||
|
||||
_cleanup_free_ char *p = NULL;
|
||||
r = get_ask_password_directory_for_flags(flags, &p);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = touch(p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1; /* did something */
|
||||
}
|
||||
|
||||
static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
|
||||
_cleanup_strv_free_erase_ char **l = NULL;
|
||||
_cleanup_(erase_and_freep) char *p = NULL;
|
||||
@@ -130,7 +153,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
|
||||
log_debug_errno(errno, "Failed to adjust kernel keyring key timeout: %m");
|
||||
|
||||
/* Tell everyone to check the keyring */
|
||||
(void) touch("/run/systemd/ask-password");
|
||||
(void) touch_ask_password_directory(flags);
|
||||
|
||||
log_debug("Added key to kernel keyring as %" PRIi32 ".", serial);
|
||||
|
||||
@@ -416,8 +439,21 @@ int ask_password_tty(
|
||||
if (r != -ENOKEY)
|
||||
return r;
|
||||
|
||||
if (inotify_add_watch(inotify_fd, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */) < 0)
|
||||
return -errno;
|
||||
/* Let's watch the askpw directory for mtime changes, which we issue above whenever the
|
||||
* keyring changes */
|
||||
_cleanup_free_ char *watch_path = NULL;
|
||||
r = get_ask_password_directory_for_flags(flags, &watch_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
_cleanup_close_ int watch_fd = open_mkdir(watch_path, O_CLOEXEC|O_RDONLY, 0755);
|
||||
if (watch_fd < 0)
|
||||
return watch_fd;
|
||||
|
||||
r = inotify_add_watch_fd(inotify_fd, watch_fd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
CLEANUP_ERASE(passphrase);
|
||||
@@ -658,20 +694,21 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int create_socket(char **ret) {
|
||||
static int create_socket(const char *askpwdir, char **ret) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
union sockaddr_union sa;
|
||||
socklen_t sa_len;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(askpwdir);
|
||||
assert(ret);
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (asprintf(&path, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()) < 0)
|
||||
if (asprintf(&path, "%s/sck.%" PRIx64, askpwdir, random_u64()) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sockaddr_un_set_path(&sa.un, path);
|
||||
@@ -697,10 +734,9 @@ int ask_password_agent(
|
||||
AskPasswordFlags flags,
|
||||
char ***ret) {
|
||||
|
||||
_cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, inotify_fd = -EBADF, fd = -EBADF;
|
||||
char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
|
||||
char final[sizeof(temp)] = "";
|
||||
_cleanup_close_ int socket_fd = -EBADF, signal_fd = -EBADF, inotify_fd = -EBADF, dfd = -EBADF;
|
||||
_cleanup_(unlink_and_freep) char *socket_name = NULL;
|
||||
_cleanup_free_ char *temp = NULL, *final = NULL;
|
||||
_cleanup_strv_free_erase_ char **l = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
sigset_t mask, oldmask;
|
||||
@@ -718,7 +754,20 @@ int ask_password_agent(
|
||||
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
|
||||
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
|
||||
|
||||
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
|
||||
_cleanup_free_ char *askpwdir = NULL;
|
||||
r = get_ask_password_directory_for_flags(flags, &askpwdir);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0) {
|
||||
r = -ENXIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dfd = open_mkdir(askpwdir, O_RDONLY|O_CLOEXEC, 0755);
|
||||
if (dfd < 0) {
|
||||
r = log_debug_errno(dfd, "Failed to open directory '%s': %m", askpwdir);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, ASK_PASSWORD_ACCEPT_CACHED) && req && req->keyring) {
|
||||
r = ask_password_keyring(req, flags, ret);
|
||||
@@ -734,24 +783,19 @@ int ask_password_agent(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = RET_NERRNO(inotify_add_watch(inotify_fd, "/run/systemd/ask-password", IN_ATTRIB /* for mtime */));
|
||||
r = inotify_add_watch_fd(inotify_fd, dfd, IN_ONLYDIR|IN_ATTRIB /* for mtime */);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fd = mkostemp_safe(temp);
|
||||
if (fd < 0) {
|
||||
r = fd;
|
||||
if (asprintf(&final, "ask.%" PRIu64, random_u64()) < 0) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
(void) fchmod(fd, 0644);
|
||||
|
||||
f = take_fdopen(&fd, "w");
|
||||
if (!f) {
|
||||
r = -errno;
|
||||
r = fopen_temporary_at(dfd, final, &f, &temp);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||
if (signal_fd < 0) {
|
||||
@@ -759,7 +803,7 @@ int ask_password_agent(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
socket_fd = create_socket(&socket_name);
|
||||
socket_fd = create_socket(askpwdir, &socket_name);
|
||||
if (socket_fd < 0) {
|
||||
r = socket_fd;
|
||||
goto finish;
|
||||
@@ -791,19 +835,21 @@ int ask_password_agent(
|
||||
fprintf(f, "Id=%s\n", req->id);
|
||||
}
|
||||
|
||||
if (fchmod(fileno(f), 0644) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
memcpy(final, temp, sizeof(temp));
|
||||
|
||||
final[sizeof(final)-11] = 'a';
|
||||
final[sizeof(final)-10] = 's';
|
||||
final[sizeof(final)-9] = 'k';
|
||||
|
||||
r = RET_NERRNO(rename(temp, final));
|
||||
if (r < 0)
|
||||
if (renameat(dfd, temp, dfd, final) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
temp = mfree(temp);
|
||||
|
||||
enum {
|
||||
POLL_SOCKET,
|
||||
@@ -908,8 +954,8 @@ int ask_password_agent(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ucred->uid != 0) {
|
||||
log_debug("Got request from unprivileged user. Ignoring.");
|
||||
if (ucred->uid != getuid() && ucred->uid != 0) {
|
||||
log_debug("Got response from bad user. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -948,10 +994,13 @@ int ask_password_agent(
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
(void) unlink(temp);
|
||||
|
||||
if (final[0])
|
||||
(void) unlink(final);
|
||||
if (temp) {
|
||||
assert(dfd >= 0);
|
||||
(void) unlinkat(dfd, temp, 0);
|
||||
} else if (final) {
|
||||
assert(dfd >= 0);
|
||||
(void) unlinkat(dfd, final, 0);
|
||||
}
|
||||
|
||||
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
|
||||
return r;
|
||||
|
||||
@@ -6,16 +6,17 @@
|
||||
#include "time-util.h"
|
||||
|
||||
typedef enum AskPasswordFlags {
|
||||
ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */
|
||||
ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */
|
||||
ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */
|
||||
ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */
|
||||
ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */
|
||||
ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
|
||||
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
|
||||
ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
|
||||
ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */
|
||||
ASK_PASSWORD_HEADLESS = 1 << 9, /* headless mode: never query interactively */
|
||||
ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */
|
||||
ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */
|
||||
ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */
|
||||
ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */
|
||||
ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */
|
||||
ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
|
||||
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
|
||||
ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
|
||||
ASK_PASSWORD_HIDE_EMOJI = 1 << 8, /* hide the lock and key emoji */
|
||||
ASK_PASSWORD_HEADLESS = 1 << 9, /* headless mode: never query interactively */
|
||||
ASK_PASSWORD_USER = 1 << 10, /* query only our own agents, not any system password agents */
|
||||
} AskPasswordFlags;
|
||||
|
||||
/* Encapsulates the mostly static fields of a password query */
|
||||
|
||||
Reference in New Issue
Block a user