From: Lennart Poettering Date: Fri, 13 Sep 2024 11:53:35 +0000 (+0200) Subject: ask-password-api: add support for querying pws from unpriv agents X-Git-Tag: v257-rc1~175^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4dd2748b659387ec607fe5c5304b356de53d3b59;p=thirdparty%2Fsystemd.git ask-password-api: add support for querying pws from unpriv agents --- diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index cd68c5c90f2..1c4f357fbe4 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -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; diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 9b197230e96..b3cb407e51c 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -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 */