tty-ask-password-agent: modernization

This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2014-08-03 12:52:03 -04:00
parent 601185b43d
commit 1d749d044b
3 changed files with 91 additions and 155 deletions

View file

@ -1977,10 +1977,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "\0/org/freedesktop/plymouthd",
};
union sockaddr_union sa = PLYMOUTH_SOCKET;
int n = 0;
_cleanup_free_ char *message = NULL;

View file

@ -73,6 +73,11 @@
#define UNIX_USER_BUS_FMT "unix:path=%s/bus"
#define KERNEL_USER_BUS_FMT "kernel:path=/dev/kdbus/"UID_FMT"-user/bus"
#define PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
.un.sun_path = "\0/org/freedesktop/plymouthd", \
}
#ifndef TTY_GID
#define TTY_GID 5
#endif

View file

@ -41,6 +41,7 @@
#include "ask-password-api.h"
#include "strv.h"
#include "build.h"
#include "def.h"
static enum {
ACTION_LIST,
@ -59,9 +60,9 @@ static int ask_password_plymouth(
bool accept_cached,
char ***_passphrases) {
int fd = -1, notify = -1;
union sockaddr_union sa = {};
char *packet = NULL;
_cleanup_close_ int fd = -1, notify = -1;
union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
struct pollfd pollfd[2] = {};
@ -75,28 +76,23 @@ static int ask_password_plymouth(
assert(_passphrases);
if (flag_file) {
if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
r = -errno;
goto finish;
}
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
if (notify < 0)
return -errno;
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
r = -errno;
goto finish;
}
r = inotify_add_watch(notify, flag_file, IN_ATTRIB); /* for the link count */
if (r < 0)
return -errno;
}
if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
r = -errno;
goto finish;
}
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
sa.sa.sa_family = AF_UNIX;
strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
if (r < 0) {
log_error("Failed to connect to Plymouth: %m");
r = -errno;
goto finish;
return -errno;
}
if (accept_cached) {
@ -106,15 +102,12 @@ static int ask_password_plymouth(
message, &n) < 0)
packet = NULL;
if (!packet) {
r = -ENOMEM;
goto finish;
}
if (!packet)
return log_oom();
if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
r = k < 0 ? (int) k : -EIO;
goto finish;
}
k = loop_write(fd, packet, n + 1, true);
if (k != n + 1)
return k < 0 ? (int) k : -EIO;
pollfd[POLL_SOCKET].fd = fd;
pollfd[POLL_SOCKET].events = POLLIN;
@ -129,31 +122,23 @@ static int ask_password_plymouth(
y = now(CLOCK_MONOTONIC);
if (y > until) {
r = -ETIME;
goto finish;
}
if (y > until)
return -ETIME;
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
}
if (flag_file)
if (access(flag_file, F_OK) < 0) {
r = -errno;
goto finish;
}
if ((j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) {
if (flag_file && access(flag_file, F_OK) < 0)
return -errno;
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;
}
return -errno;
} else if (j == 0)
return -ETIME;
if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
@ -161,10 +146,9 @@ static int ask_password_plymouth(
if (pollfd[POLL_SOCKET].revents == 0)
continue;
if ((k = read(fd, buffer + p, sizeof(buffer) - p)) <= 0) {
r = k < 0 ? -errno : -EIO;
goto finish;
}
k = read(fd, buffer + p, sizeof(buffer) - p);
if (k <= 0)
return r = k < 0 ? -errno : -EIO;
p += k;
@ -180,15 +164,12 @@ static int ask_password_plymouth(
free(packet);
packet = NULL;
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
r = -ENOMEM;
goto finish;
}
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
return -ENOMEM;
if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
r = k < 0 ? (int) k : -EIO;
goto finish;
}
k = loop_write(fd, packet, n+1, true);
if (k != n + 1)
return k < 0 ? (int) k : -EIO;
accept_cached = false;
p = 0;
@ -196,8 +177,7 @@ static int ask_password_plymouth(
}
/* No password, because UI not shown */
r = -ENOENT;
goto finish;
return -ENOENT;
} else if (buffer[0] == 2 || buffer[0] == 9) {
uint32_t size;
@ -209,38 +189,25 @@ static int ask_password_plymouth(
memcpy(&size, buffer+1, sizeof(size));
size = le32toh(size);
if (size+5 > sizeof(buffer)) {
r = -EIO;
goto finish;
}
if (size + 5 > sizeof(buffer))
return -EIO;
if (p-5 < size)
continue;
if (!(l = strv_parse_nulstr(buffer + 5, size))) {
r = -ENOMEM;
goto finish;
}
l = strv_parse_nulstr(buffer + 5, size);
if (!l)
return -ENOMEM;
*_passphrases = l;
break;
} else {
} else
/* Unknown packet */
r = -EIO;
goto finish;
}
return -EIO;
}
r = 0;
finish:
safe_close(notify);
safe_close(fd);
free(packet);
return r;
return 0;
}
static int parse_password(const char *filename, char **wall) {
@ -255,7 +222,7 @@ static int parse_password(const char *filename, char **wall) {
{ "Ask", "Message", config_parse_string, 0, &message },
{ "Ask", "PID", config_parse_unsigned, 0, &pid },
{ "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached },
{ NULL, NULL, NULL, 0, NULL }
{}
};
int r;
@ -328,13 +295,12 @@ static int parse_password(const char *filename, char **wall) {
if (!packet)
r = -ENOMEM;
else {
char *d;
packet[0] = '+';
d = packet+1;
char *d = packet + 1;
STRV_FOREACH(p, passwords)
d = stpcpy(d, *p) + 1;
packet[0] = '+';
}
}
@ -367,7 +333,7 @@ static int parse_password(const char *filename, char **wall) {
}
}
if (r == -ETIME || r == -ENOENT)
if (IN_SET(r, -ETIME, -ENOENT))
/* If the query went away, that's OK */
return 0;
@ -397,7 +363,7 @@ static int parse_password(const char *filename, char **wall) {
}
static int wall_tty_block(void) {
char *p;
_cleanup_free_ char *p = NULL;
int fd, r;
dev_t devnr;
@ -412,8 +378,6 @@ static int wall_tty_block(void) {
mkfifo(p, 0600);
fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
free(p);
if (fd < 0)
return -errno;
@ -421,21 +385,15 @@ static int wall_tty_block(void) {
}
static bool wall_tty_match(const char *path) {
int fd, k;
char *p;
int fd, r;
struct stat st;
_cleanup_free_ char *p = NULL;
if (path_is_absolute(path))
k = lstat(path, &st);
else {
if (asprintf(&p, "/dev/%s", path) < 0)
return true;
if (!path_is_absolute(path))
path = strappenda("/dev/", path);
k = lstat(p, &st);
free(p);
}
if (k < 0)
r = lstat(path, &st);
if (r < 0)
return true;
if (!S_ISCHR(st.st_mode))
@ -453,8 +411,6 @@ static bool wall_tty_match(const char *path) {
return true;
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
free(p);
if (fd < 0)
return true;
@ -464,11 +420,12 @@ static bool wall_tty_match(const char *path) {
}
static int show_passwords(void) {
DIR *d;
_cleanup_closedir_ DIR *d;
struct dirent *de;
int r = 0;
if (!(d = opendir("/run/systemd/ask-password"))) {
d = opendir("/run/systemd/ask-password");
if (!d) {
if (errno == ENOENT)
return 0;
@ -477,9 +434,8 @@ static int show_passwords(void) {
}
while ((de = readdir(d))) {
char *p;
_cleanup_free_ char *p = NULL, *wall = NULL;
int q;
char *wall;
/* We only support /dev on tmpfs, hence we can rely on
* d_type to be reliable */
@ -493,27 +449,18 @@ static int show_passwords(void) {
if (!startswith(de->d_name, "ask."))
continue;
if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) {
r = log_oom();
goto finish;
}
p = strappend("/run/systemd/ask-password/", de->d_name);
if (!p)
return log_oom();
wall = NULL;
if ((q = parse_password(p, &wall)) < 0)
q = parse_password(p, &wall);
if (q < 0 && r == 0)
r = q;
free(p);
if (wall) {
if (wall)
utmp_wall(wall, NULL, wall_tty_match);
free(wall);
}
}
finish:
if (d)
closedir(d);
return r;
}
@ -524,7 +471,7 @@ static int watch_passwords(void) {
_FD_MAX
};
int notify = -1, signal_fd = -1, tty_block_fd = -1;
_cleanup_close_ int notify = -1, signal_fd = -1, tty_block_fd = -1;
struct pollfd pollfd[_FD_MAX] = {};
sigset_t mask;
int r;
@ -533,25 +480,20 @@ static int watch_passwords(void) {
mkdir_p_label("/run/systemd/ask-password", 0755);
if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
r = -errno;
goto finish;
}
notify = inotify_init1(IN_CLOEXEC);
if (notify < 0)
return -errno;
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
r = -errno;
goto finish;
}
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0)
return -errno;
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
log_error("signalfd(): %m");
r = -errno;
goto finish;
}
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0)
return -errno;
pollfd[FD_INOTIFY].fd = notify;
pollfd[FD_INOTIFY].events = POLLIN;
@ -559,16 +501,15 @@ static int watch_passwords(void) {
pollfd[FD_SIGNAL].events = POLLIN;
for (;;) {
if ((r = show_passwords()) < 0)
r = show_passwords();
if (r < 0)
log_error("Failed to show password: %s", strerror(-r));
if (poll(pollfd, _FD_MAX, -1) < 0) {
if (errno == EINTR)
continue;
r = -errno;
goto finish;
return -errno;
}
if (pollfd[FD_INOTIFY].revents != 0)
@ -578,14 +519,7 @@ static int watch_passwords(void) {
break;
}
r = 0;
finish:
safe_close(notify);
safe_close(signal_fd);
safe_close(tty_block_fd);
return r;
return 0;
}
static void help(void) {
@ -692,7 +626,8 @@ int main(int argc, char *argv[]) {
umask(0022);
if ((r = parse_argv(argc, argv)) <= 0)
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
if (arg_console) {
@ -700,8 +635,7 @@ int main(int argc, char *argv[]) {
release_terminal();
}
if (arg_action == ACTION_WATCH ||
arg_action == ACTION_WALL)
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
r = watch_passwords();
else
r = show_passwords();