#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"
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;
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);
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);
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);
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;
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);
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) {
goto finish;
}
- socket_fd = create_socket(&socket_name);
+ socket_fd = create_socket(askpwdir, &socket_name);
if (socket_fd < 0) {
r = socket_fd;
goto finish;
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,
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;
}
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;
#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 */