mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
cryptsetup: hook up tool with ask-password
This commit is contained in:
parent
5a1e99375d
commit
7f4e08056d
18
Makefile.am
18
Makefile.am
@ -118,12 +118,16 @@ rootlibexec_PROGRAMS = \
|
||||
systemd-user-sessions \
|
||||
systemd-fsck \
|
||||
systemd-quotacheck \
|
||||
systemd-cryptsetup \
|
||||
systemd-timestamp \
|
||||
systemd-ac-power
|
||||
|
||||
if HAVE_LIBCRYPTSETUP
|
||||
rootlibexec_PROGRAMS += \
|
||||
systemd-cryptsetup
|
||||
|
||||
systemgenerator_PROGRAMS = \
|
||||
systemd-cryptsetup-generator
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
test-engine \
|
||||
@ -467,7 +471,8 @@ EXTRA_DIST += \
|
||||
src/build.h \
|
||||
src/shutdownd.h \
|
||||
src/umount.h \
|
||||
src/readahead-common.h
|
||||
src/readahead-common.h \
|
||||
src/ask-password-api.h
|
||||
|
||||
MANPAGES = \
|
||||
man/systemd.1 \
|
||||
@ -746,12 +751,15 @@ systemd_ac_power_LDADD = \
|
||||
$(UDEV_LIBS)
|
||||
|
||||
systemd_cryptsetup_SOURCES = \
|
||||
src/cryptsetup.c
|
||||
src/cryptsetup.c \
|
||||
src/ask-password-api.c
|
||||
|
||||
systemd_cryptsetup_CFLAGS = \
|
||||
$(LIBCRYPTSETUP_CFLAGS) \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
systemd_cryptsetup_LDADD = \
|
||||
$(LIBCRYPTSETUP_LIBS) \
|
||||
libsystemd-basic.la
|
||||
|
||||
systemd_cryptsetup_generator_SOURCES = \
|
||||
@ -844,7 +852,8 @@ systemd_notify_LDADD = \
|
||||
libsystemd-basic.la
|
||||
|
||||
systemd_ask_password_SOURCES = \
|
||||
src/ask-password.c
|
||||
src/ask-password.c \
|
||||
src/ask-password-api.c
|
||||
|
||||
systemd_ask_password_LDADD = \
|
||||
libsystemd-basic.la
|
||||
@ -940,6 +949,7 @@ systemd_gnome_ask_password_agent_LDADD = \
|
||||
|
||||
systemd_tty_ask_password_agent_SOURCES = \
|
||||
src/tty-ask-password-agent.c \
|
||||
src/ask-password-api.c \
|
||||
src/utmp-wtmp.c
|
||||
|
||||
systemd_tty_ask_password_agent_LDADD = \
|
||||
|
14
configure.ac
14
configure.ac
@ -229,6 +229,19 @@ else
|
||||
fi
|
||||
AC_SUBST(AUDIT_LIBS)
|
||||
|
||||
have_libcryptsetup=no
|
||||
AC_ARG_ENABLE(libcryptsetup, AS_HELP_STRING([--disable-libcryptsetup], [disable libcryptsetup tools]))
|
||||
if test "x$enable_libcryptsetup" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBCRYPTSETUP, [ libcryptsetup ],
|
||||
[AC_DEFINE(HAVE_LIBCRYPTSETUP, 1, [Define if libcryptsetup is available]) have_libcryptsetup=yes], have_libcryptsetup=no)
|
||||
AC_SUBST(LIBCRYPTSETUP_CFLAGS)
|
||||
AC_SUBST(LIBCRYPTSETUP_LIBS)
|
||||
if test "x$have_libcryptsetup" = xno -a "x$enable_libcryptsetup" = xyes; then
|
||||
AC_MSG_ERROR([*** libcryptsetup support requested but libraries not found])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBCRYPTSETUP, [test "$have_libcryptsetup" = "yes"])
|
||||
|
||||
have_gtk=no
|
||||
AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools]))
|
||||
if test "x$enable_gtk" != "xno"; then
|
||||
@ -444,6 +457,7 @@ echo "
|
||||
SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH}
|
||||
Syslog service: ${SPECIAL_SYSLOG_SERVICE}
|
||||
Gtk: ${have_gtk}
|
||||
libcryptsetup: ${have_libcryptsetup}
|
||||
tcpwrap: ${have_tcpwrap}
|
||||
PAM: ${have_pam}
|
||||
AUDIT: ${have_audit}
|
||||
|
482
src/ask-password-api.c
Normal file
482
src/ask-password-api.c
Normal file
@ -0,0 +1,482 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "ask-password-api.h"
|
||||
|
||||
int ask_password_tty(
|
||||
const char *message,
|
||||
usec_t until,
|
||||
const char *flag_file,
|
||||
char **_passphrase) {
|
||||
|
||||
struct termios old_termios, new_termios;
|
||||
char passphrase[LINE_MAX];
|
||||
size_t p = 0;
|
||||
int r, ttyfd = -1, notify = -1;
|
||||
struct pollfd pollfd[2];
|
||||
bool reset_tty = false;
|
||||
enum {
|
||||
POLL_TTY,
|
||||
POLL_INOTIFY
|
||||
};
|
||||
|
||||
assert(message);
|
||||
assert(_passphrase);
|
||||
|
||||
if (flag_file) {
|
||||
if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) {
|
||||
|
||||
if (tcgetattr(ttyfd, &old_termios) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
loop_write(ttyfd, "\x1B[1m", 4, false);
|
||||
loop_write(ttyfd, message, strlen(message), false);
|
||||
loop_write(ttyfd, ": ", 2, false);
|
||||
loop_write(ttyfd, "\x1B[0m", 4, false);
|
||||
|
||||
new_termios = old_termios;
|
||||
new_termios.c_lflag &= ~(ICANON|ECHO);
|
||||
new_termios.c_cc[VMIN] = 1;
|
||||
new_termios.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
reset_tty = true;
|
||||
}
|
||||
|
||||
zero(pollfd);
|
||||
|
||||
pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
|
||||
pollfd[POLL_TTY].events = POLLIN;
|
||||
pollfd[POLL_INOTIFY].fd = notify;
|
||||
pollfd[POLL_INOTIFY].events = POLLIN;
|
||||
|
||||
for (;;) {
|
||||
char c;
|
||||
int sleep_for = -1, k;
|
||||
ssize_t n;
|
||||
|
||||
if (until > 0) {
|
||||
usec_t y;
|
||||
|
||||
y = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (y > until) {
|
||||
r = -ETIMEDOUT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
if (flag_file)
|
||||
if (access(flag_file, F_OK) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) {
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
} else if (k == 0) {
|
||||
r = -ETIMEDOUT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
|
||||
flush_fd(notify);
|
||||
|
||||
if (pollfd[POLL_TTY].revents == 0)
|
||||
continue;
|
||||
|
||||
if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) {
|
||||
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
|
||||
} else if (n == 0)
|
||||
break;
|
||||
|
||||
if (c == '\n')
|
||||
break;
|
||||
else if (c == 21) {
|
||||
|
||||
while (p > 0) {
|
||||
p--;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\b \b", 3, false);
|
||||
}
|
||||
|
||||
} else if (c == '\b' || c == 127) {
|
||||
if (p > 0) {
|
||||
p--;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\b \b", 3, false);
|
||||
}
|
||||
} else {
|
||||
passphrase[p++] = c;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "*", 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\n", 1, false);
|
||||
|
||||
passphrase[p] = 0;
|
||||
|
||||
if (!(*_passphrase = strdup(passphrase))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (notify >= 0)
|
||||
close_nointr_nofail(notify);
|
||||
|
||||
if (ttyfd >= 0) {
|
||||
if (reset_tty)
|
||||
tcsetattr(ttyfd, TCSADRAIN, &old_termios);
|
||||
|
||||
close_nointr_nofail(ttyfd);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int create_socket(char **name) {
|
||||
int fd;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_un un;
|
||||
} sa;
|
||||
int one = 1, r;
|
||||
char *c;
|
||||
|
||||
assert(name);
|
||||
|
||||
if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
|
||||
log_error("socket() failed: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
zero(sa);
|
||||
sa.un.sun_family = AF_UNIX;
|
||||
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/dev/.systemd/ask-password/sck.%llu", random_ull());
|
||||
|
||||
if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
|
||||
r = -errno;
|
||||
log_error("bind() failed: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
|
||||
r = -errno;
|
||||
log_error("SO_PASSCRED failed: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(c = strdup(sa.un.sun_path))) {
|
||||
r = -ENOMEM;
|
||||
log_error("Out of memory");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*name = c;
|
||||
return fd;
|
||||
|
||||
fail:
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int ask_password_agent(
|
||||
const char *message,
|
||||
const char *icon,
|
||||
usec_t until,
|
||||
char **_passphrase) {
|
||||
|
||||
enum {
|
||||
FD_SOCKET,
|
||||
FD_SIGNAL,
|
||||
_FD_MAX
|
||||
};
|
||||
|
||||
char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX";
|
||||
char final[sizeof(temp)] = "";
|
||||
int fd = -1, r;
|
||||
FILE *f = NULL;
|
||||
char *socket_name = NULL;
|
||||
int socket_fd = -1, signal_fd = -1;
|
||||
sigset_t mask;
|
||||
struct pollfd pollfd[_FD_MAX];
|
||||
|
||||
mkdir_p("/dev/.systemd/ask-password", 0755);
|
||||
|
||||
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
|
||||
log_error("Failed to create password file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fchmod(fd, 0644);
|
||||
|
||||
if (!(f = fdopen(fd, "w"))) {
|
||||
log_error("Failed to allocate FILE: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((socket_fd = create_socket(&socket_name)) < 0) {
|
||||
r = socket_fd;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fprintf(f,
|
||||
"[Ask]\n"
|
||||
"PID=%lu\n"
|
||||
"Socket=%s\n"
|
||||
"NotAfter=%llu\n",
|
||||
(unsigned long) getpid(),
|
||||
socket_name,
|
||||
(unsigned long long) until);
|
||||
|
||||
if (message)
|
||||
fprintf(f, "Message=%s\n", message);
|
||||
|
||||
if (icon)
|
||||
fprintf(f, "Icon=%s\n", icon);
|
||||
|
||||
fflush(f);
|
||||
|
||||
if (ferror(f)) {
|
||||
log_error("Failed to write query file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
memcpy(final, temp, sizeof(temp));
|
||||
|
||||
final[sizeof(final)-11] = 'a';
|
||||
final[sizeof(final)-10] = 's';
|
||||
final[sizeof(final)-9] = 'k';
|
||||
|
||||
if (rename(temp, final) < 0) {
|
||||
log_error("Failed to rename query file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(pollfd);
|
||||
pollfd[FD_SOCKET].fd = socket_fd;
|
||||
pollfd[FD_SOCKET].events = POLLIN;
|
||||
pollfd[FD_SIGNAL].fd = signal_fd;
|
||||
pollfd[FD_SIGNAL].events = POLLIN;
|
||||
|
||||
for (;;) {
|
||||
char passphrase[LINE_MAX+1];
|
||||
struct msghdr msghdr;
|
||||
struct iovec iovec;
|
||||
struct ucred *ucred;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
||||
} control;
|
||||
ssize_t n;
|
||||
int k;
|
||||
usec_t t;
|
||||
|
||||
t = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (until <= t) {
|
||||
log_notice("Timed out");
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((k = poll(pollfd, _FD_MAX, until-t/USEC_PER_MSEC)) < 0) {
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("poll() failed: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (k <= 0) {
|
||||
log_notice("Timed out");
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SIGNAL].revents & POLLIN)
|
||||
break;
|
||||
|
||||
if (pollfd[FD_SOCKET].revents != POLLIN) {
|
||||
log_error("Unexpected poll() event.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(iovec);
|
||||
iovec.iov_base = passphrase;
|
||||
iovec.iov_len = sizeof(passphrase)-1;
|
||||
|
||||
zero(control);
|
||||
zero(msghdr);
|
||||
msghdr.msg_iov = &iovec;
|
||||
msghdr.msg_iovlen = 1;
|
||||
msghdr.msg_control = &control;
|
||||
msghdr.msg_controllen = sizeof(control);
|
||||
|
||||
if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) {
|
||||
|
||||
if (errno == EAGAIN ||
|
||||
errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("recvmsg() failed: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
log_error("Message too short");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
|
||||
control.cmsghdr.cmsg_level != SOL_SOCKET ||
|
||||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
|
||||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
|
||||
log_warning("Received message without credentials. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
|
||||
if (ucred->uid != 0) {
|
||||
log_warning("Got request from unprivileged user. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passphrase[0] == '+') {
|
||||
passphrase[n] = 0;
|
||||
|
||||
if (!(*_passphrase = strdup(passphrase+1))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else if (passphrase[0] == '-') {
|
||||
r = -ECANCELED;
|
||||
goto finish;
|
||||
} else {
|
||||
log_error("Invalid packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (fd >= 0)
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
if (socket_name) {
|
||||
unlink(socket_name);
|
||||
free(socket_name);
|
||||
}
|
||||
|
||||
if (socket_fd >= 0)
|
||||
close_nointr_nofail(socket_fd);
|
||||
|
||||
if (signal_fd >= 0)
|
||||
close_nointr_nofail(signal_fd);
|
||||
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
unlink(temp);
|
||||
|
||||
if (final[0])
|
||||
unlink(final);
|
||||
|
||||
return r;
|
||||
}
|
31
src/ask-password-api.h
Normal file
31
src/ask-password-api.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooaskpasswordapihfoo
|
||||
#define fooaskpasswordapihfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "util.h"
|
||||
|
||||
int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
|
||||
|
||||
int ask_password_agent(const char *message, const char *icon, usec_t until, char **_passphrase);
|
||||
|
||||
#endif
|
@ -38,59 +38,13 @@
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "ask-password-api.h"
|
||||
|
||||
static const char *arg_icon = NULL;
|
||||
static const char *arg_message = NULL;
|
||||
static bool arg_use_tty = true;
|
||||
static usec_t arg_timeout = 60 * USEC_PER_SEC;
|
||||
|
||||
static int create_socket(char **name) {
|
||||
int fd;
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_un un;
|
||||
} sa;
|
||||
int one = 1, r;
|
||||
char *c;
|
||||
|
||||
assert(name);
|
||||
|
||||
if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
|
||||
log_error("socket() failed: %m");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
zero(sa);
|
||||
sa.un.sun_family = AF_UNIX;
|
||||
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/dev/.systemd/ask-password/sck.%llu", random_ull());
|
||||
|
||||
if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
|
||||
r = -errno;
|
||||
log_error("bind() failed: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
|
||||
r = -errno;
|
||||
log_error("SO_PASSCRED failed: %m");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(c = strdup(sa.un.sun_path))) {
|
||||
r = -ENOMEM;
|
||||
log_error("Out of memory");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*name = c;
|
||||
return fd;
|
||||
|
||||
fail:
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
|
||||
printf("%s [OPTIONS...] MESSAGE\n\n"
|
||||
@ -166,222 +120,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ask_agent(void) {
|
||||
enum {
|
||||
FD_SOCKET,
|
||||
FD_SIGNAL,
|
||||
_FD_MAX
|
||||
};
|
||||
|
||||
char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX";
|
||||
char final[sizeof(temp)] = "";
|
||||
int fd = -1, r;
|
||||
FILE *f = NULL;
|
||||
char *socket_name = NULL;
|
||||
int socket_fd = -1, signal_fd = -1;
|
||||
sigset_t mask;
|
||||
usec_t not_after;
|
||||
struct pollfd pollfd[_FD_MAX];
|
||||
|
||||
mkdir_p("/dev/.systemd/ask-password", 0755);
|
||||
|
||||
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
|
||||
log_error("Failed to create password file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fchmod(fd, 0644);
|
||||
|
||||
if (!(f = fdopen(fd, "w"))) {
|
||||
log_error("Failed to allocate FILE: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((socket_fd = create_socket(&socket_name)) < 0) {
|
||||
r = socket_fd;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
not_after = now(CLOCK_MONOTONIC) + arg_timeout;
|
||||
|
||||
fprintf(f,
|
||||
"[Ask]\n"
|
||||
"PID=%lu\n"
|
||||
"Socket=%s\n"
|
||||
"NotAfter=%llu\n",
|
||||
(unsigned long) getpid(),
|
||||
socket_name,
|
||||
(unsigned long long) not_after);
|
||||
|
||||
if (arg_message)
|
||||
fprintf(f, "Message=%s\n", arg_message);
|
||||
|
||||
if (arg_icon)
|
||||
fprintf(f, "Icon=%s\n", arg_icon);
|
||||
|
||||
fflush(f);
|
||||
|
||||
if (ferror(f)) {
|
||||
log_error("Failed to write query file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
memcpy(final, temp, sizeof(temp));
|
||||
|
||||
final[sizeof(final)-11] = 'a';
|
||||
final[sizeof(final)-10] = 's';
|
||||
final[sizeof(final)-9] = 'k';
|
||||
|
||||
if (rename(temp, final) < 0) {
|
||||
log_error("Failed to rename query file: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(pollfd);
|
||||
pollfd[FD_SOCKET].fd = socket_fd;
|
||||
pollfd[FD_SOCKET].events = POLLIN;
|
||||
pollfd[FD_SIGNAL].fd = signal_fd;
|
||||
pollfd[FD_SIGNAL].events = POLLIN;
|
||||
|
||||
for (;;) {
|
||||
char passphrase[LINE_MAX+1];
|
||||
struct msghdr msghdr;
|
||||
struct iovec iovec;
|
||||
struct ucred *ucred;
|
||||
union {
|
||||
struct cmsghdr cmsghdr;
|
||||
uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
|
||||
} control;
|
||||
ssize_t n;
|
||||
int k;
|
||||
|
||||
if ((k = poll(pollfd, _FD_MAX, arg_timeout/USEC_PER_MSEC)) < 0) {
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("poll() failed: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (k <= 0) {
|
||||
log_notice("Timed out");
|
||||
r = -ETIME;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (pollfd[FD_SIGNAL].revents & POLLIN)
|
||||
break;
|
||||
|
||||
if (pollfd[FD_SOCKET].revents != POLLIN) {
|
||||
log_error("Unexpected poll() event.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
zero(iovec);
|
||||
iovec.iov_base = passphrase;
|
||||
iovec.iov_len = sizeof(passphrase)-1;
|
||||
|
||||
zero(control);
|
||||
zero(msghdr);
|
||||
msghdr.msg_iov = &iovec;
|
||||
msghdr.msg_iovlen = 1;
|
||||
msghdr.msg_control = &control;
|
||||
msghdr.msg_controllen = sizeof(control);
|
||||
|
||||
if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) {
|
||||
|
||||
if (errno == EAGAIN ||
|
||||
errno == EINTR)
|
||||
continue;
|
||||
|
||||
log_error("recvmsg() failed: %m");
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
log_error("Message too short");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
|
||||
control.cmsghdr.cmsg_level != SOL_SOCKET ||
|
||||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
|
||||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
|
||||
log_warning("Received message without credentials. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
|
||||
if (ucred->uid != 0) {
|
||||
log_warning("Got request from unprivileged user. Ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passphrase[0] == '+') {
|
||||
passphrase[n] = 0;
|
||||
fputs(passphrase+1, stdout);
|
||||
fflush(stdout);
|
||||
} else if (passphrase[0] == '-') {
|
||||
r = -ECANCELED;
|
||||
goto finish;
|
||||
} else {
|
||||
log_error("Invalid packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (fd >= 0)
|
||||
close_nointr_nofail(fd);
|
||||
|
||||
if (socket_name) {
|
||||
unlink(socket_name);
|
||||
free(socket_name);
|
||||
}
|
||||
|
||||
if (socket_fd >= 0)
|
||||
close_nointr_nofail(socket_fd);
|
||||
|
||||
if (signal_fd >= 0)
|
||||
close_nointr_nofail(signal_fd);
|
||||
|
||||
if (f)
|
||||
fclose(f);
|
||||
|
||||
unlink(temp);
|
||||
|
||||
if (final[0])
|
||||
unlink(final);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
char *password = NULL;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
@ -389,18 +130,18 @@ int main(int argc, char *argv[]) {
|
||||
if ((r = parse_argv(argc, argv)) <= 0)
|
||||
goto finish;
|
||||
|
||||
if (arg_use_tty && isatty(STDIN_FILENO)) {
|
||||
char *password = NULL;
|
||||
if (arg_use_tty && isatty(STDIN_FILENO))
|
||||
r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password);
|
||||
else
|
||||
r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, &password);
|
||||
|
||||
if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) {
|
||||
fputs(password, stdout);
|
||||
fflush(stdout);
|
||||
free(password);
|
||||
}
|
||||
|
||||
} else
|
||||
r = ask_agent();
|
||||
if (r >= 0) {
|
||||
fputs(password, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
finish:
|
||||
free(password);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ static int create_disk(
|
||||
"DefaultDependencies=no\n"
|
||||
"BindTo=%s\n"
|
||||
"After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
|
||||
"Before=dev-mapper-%%f.device shutdown.target\n",
|
||||
"Before=dev-mapper-%%i.device shutdown.target\n",
|
||||
d, d);
|
||||
|
||||
if (password && (streq(password, "/dev/urandom") ||
|
||||
@ -116,8 +116,8 @@ static int create_disk(
|
||||
"Type=oneshot\n"
|
||||
"RemainAfterExit=yes\n"
|
||||
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " %s '%s' '%s' '%s' '%s'\n"
|
||||
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " remove '%s'\n",
|
||||
options && has_option(options, "swap") ? "format" : "create",
|
||||
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
|
||||
options && has_option(options, "swap") ? "format-and-attach" : "attach",
|
||||
name, u, strempty(password), strempty(options),
|
||||
name);
|
||||
|
||||
|
202
src/cryptsetup.c
202
src/cryptsetup.c
@ -20,12 +20,134 @@
|
||||
***/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libcryptsetup.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "ask-password-api.h"
|
||||
|
||||
static unsigned opt_tries = 0;
|
||||
static char *opt_cipher = NULL;
|
||||
static unsigned opt_size = 0;
|
||||
static char *opt_hash = NULL;
|
||||
static bool opt_readonly = false;
|
||||
static bool opt_verify = false;
|
||||
static usec_t arg_timeout = 0;
|
||||
|
||||
static int parse_one_option(const char *option) {
|
||||
assert(option);
|
||||
|
||||
/* Handled outside of this tool */
|
||||
if (streq(option, "swap") ||
|
||||
streq(option, "tmp") ||
|
||||
streq(option, "noauto"))
|
||||
return 0;
|
||||
|
||||
if (startswith(option, "cipher=")) {
|
||||
char *t;
|
||||
|
||||
if (!(t = strdup(option+7)))
|
||||
return -ENOMEM;
|
||||
|
||||
free(opt_cipher);
|
||||
opt_cipher = t;
|
||||
|
||||
} else if (startswith(option, "size=")) {
|
||||
|
||||
if (safe_atou(option+5, &opt_size) < 0) {
|
||||
log_error("size= parse failure, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (startswith(option, "hash=")) {
|
||||
char *t;
|
||||
|
||||
if (!(t = strdup(option+5)))
|
||||
return -ENOMEM;
|
||||
|
||||
free(opt_hash);
|
||||
opt_hash = t;
|
||||
|
||||
} else if (startswith(option, "tries=")) {
|
||||
|
||||
if (safe_atou(option+6, &opt_tries) < 0) {
|
||||
log_error("tries= parse failure, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (streq(option, "readonly"))
|
||||
opt_readonly = true;
|
||||
else if (streq(option, "verify"))
|
||||
opt_verify = true;
|
||||
else if (startswith(option, "timeout=")) {
|
||||
|
||||
if (parse_usec(option+8, &arg_timeout) < 0) {
|
||||
log_error("timeout= parse failure, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else
|
||||
log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_options(const char *options) {
|
||||
char *state;
|
||||
char *w;
|
||||
size_t l;
|
||||
|
||||
assert(options);
|
||||
|
||||
FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
|
||||
char *o;
|
||||
int r;
|
||||
|
||||
if (!(o = strndup(w, l)))
|
||||
return -ENOMEM;
|
||||
|
||||
r = parse_one_option(o);
|
||||
free(o);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void log_glue(int level, const char *msg, void *usrptr) {
|
||||
|
||||
log_full(level == CRYPT_LOG_ERROR ? LOG_ERR :
|
||||
level == CRYPT_LOG_VERBOSE ? LOG_INFO :
|
||||
level == CRYPT_LOG_DEBUG ? LOG_DEBUG :
|
||||
LOG_NOTICE,
|
||||
"%s", msg);
|
||||
}
|
||||
|
||||
static int password_glue(const char *msg, char *buf, size_t length, void *usrptr) {
|
||||
usec_t until;
|
||||
char *password = NULL;
|
||||
int k;
|
||||
|
||||
until = now(CLOCK_MONOTONIC) + (arg_timeout > 0 ? arg_timeout : 60 * USEC_PER_SEC);
|
||||
|
||||
if ((k = ask_password_agent(msg, "drive-harddisk", until, &password)) < 0)
|
||||
return k;
|
||||
|
||||
strncpy(buf, password, length-1);
|
||||
buf[length-1] = 0;
|
||||
|
||||
free(password);
|
||||
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = EXIT_SUCCESS;
|
||||
int r = EXIT_FAILURE;
|
||||
struct crypt_device *cd = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
log_error("This program requires at least two arguments.");
|
||||
@ -36,18 +158,90 @@ int main(int argc, char *argv[]) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
if (streq(argv[1], "create")) {
|
||||
if (streq(argv[1], "attach") ||
|
||||
streq(argv[1], "format-and-attach")) {
|
||||
uint32_t flags = 0;
|
||||
int k;
|
||||
const char *key_file = NULL;
|
||||
|
||||
} else if (streq(argv[1], "format")) {
|
||||
if (argc < 4) {
|
||||
log_error("attach requires at least two arguments.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (argc >= 5 && argv[4][0] && !streq(argv[4], "-")) {
|
||||
|
||||
} else if (streq(argv[1], "remove")) {
|
||||
if (!path_is_absolute(argv[4]))
|
||||
log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
|
||||
else
|
||||
key_file = argv[4];
|
||||
}
|
||||
|
||||
if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
|
||||
parse_options(argv[5]);
|
||||
|
||||
if ((k = crypt_init(&cd, argv[3]))) {
|
||||
log_error("crypt_init() failed: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
crypt_set_password_callback(cd, password_glue, NULL);
|
||||
|
||||
if (streq(argv[1], "format-and-attach")) {
|
||||
|
||||
/* Format with random key and attach */
|
||||
|
||||
log_error("Formatting not yet supported.");
|
||||
goto finish;
|
||||
|
||||
} else if ((k = crypt_load(cd, CRYPT_LUKS1, NULL))) {
|
||||
log_error("crypt_load() failed: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (opt_readonly)
|
||||
flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (key_file) {
|
||||
crypt_set_password_retry(cd, 1);
|
||||
k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, 0, flags);
|
||||
} else {
|
||||
crypt_set_password_retry(cd, opt_tries > 0 ? opt_tries : 3);
|
||||
k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, NULL, 0, flags);
|
||||
}
|
||||
|
||||
if (k < 0) {
|
||||
log_error("Failed to activate: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else if (streq(argv[1], "detach")) {
|
||||
int k;
|
||||
|
||||
if ((k = crypt_init_by_name(&cd, argv[2]))) {
|
||||
log_error("crypt_init() failed: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
|
||||
if ((k = crypt_deactivate(cd, argv[2])) < 0) {
|
||||
log_error("Failed to deactivate: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else {
|
||||
log_error("Unknown verb %s.", argv[1]);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = EXIT_SUCCESS;
|
||||
|
||||
finish:
|
||||
|
||||
if (cd)
|
||||
crypt_free(cd);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -2842,6 +2842,8 @@ void manager_run_generators(Manager *m) {
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_debug("Spawned generator %s as %lu", path, (unsigned long) pid);
|
||||
|
||||
if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
|
||||
log_error("Failed to add PID to set: %s", strerror(-k));
|
||||
free(path);
|
||||
@ -2868,7 +2870,8 @@ void manager_run_generators(Manager *m) {
|
||||
log_error("%s exited with exit status %i.", path, si.si_status);
|
||||
else
|
||||
log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
|
||||
}
|
||||
} else
|
||||
log_debug("Generator %s exited successfully.", path);
|
||||
|
||||
free(path);
|
||||
}
|
||||
@ -2894,6 +2897,8 @@ void manager_run_generators(Manager *m) {
|
||||
|
||||
strv_free(m->lookup_paths.unit_path);
|
||||
m->lookup_paths.unit_path = l;
|
||||
|
||||
log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
|
||||
}
|
||||
|
||||
finish:
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "conf-parser.h"
|
||||
#include "utmp-wtmp.h"
|
||||
#include "socket-util.h"
|
||||
#include "ask-password-api.h"
|
||||
|
||||
static enum {
|
||||
ACTION_LIST,
|
||||
|
164
src/util.c
164
src/util.c
@ -3373,170 +3373,6 @@ int signal_from_string_try_harder(const char *s) {
|
||||
return signo;
|
||||
}
|
||||
|
||||
int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase) {
|
||||
struct termios old_termios, new_termios;
|
||||
char passphrase[LINE_MAX];
|
||||
size_t p = 0;
|
||||
int r, ttyfd = -1, notify = -1;
|
||||
struct pollfd pollfd[2];
|
||||
bool reset_tty = false;
|
||||
enum {
|
||||
POLL_TTY,
|
||||
POLL_INOTIFY
|
||||
};
|
||||
|
||||
assert(message);
|
||||
assert(_passphrase);
|
||||
|
||||
if (flag_file) {
|
||||
if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) {
|
||||
|
||||
if (tcgetattr(ttyfd, &old_termios) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
loop_write(ttyfd, "\x1B[1m", 4, false);
|
||||
loop_write(ttyfd, message, strlen(message), false);
|
||||
loop_write(ttyfd, ": ", 2, false);
|
||||
loop_write(ttyfd, "\x1B[0m", 4, false);
|
||||
|
||||
new_termios = old_termios;
|
||||
new_termios.c_lflag &= ~(ICANON|ECHO);
|
||||
new_termios.c_cc[VMIN] = 1;
|
||||
new_termios.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
reset_tty = true;
|
||||
}
|
||||
|
||||
zero(pollfd);
|
||||
|
||||
pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
|
||||
pollfd[POLL_TTY].events = POLLIN;
|
||||
pollfd[POLL_INOTIFY].fd = notify;
|
||||
pollfd[POLL_INOTIFY].events = POLLIN;
|
||||
|
||||
for (;;) {
|
||||
char c;
|
||||
int sleep_for = -1, k;
|
||||
ssize_t n;
|
||||
|
||||
if (until > 0) {
|
||||
usec_t y;
|
||||
|
||||
y = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (y > until) {
|
||||
r = -ETIMEDOUT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
if (flag_file)
|
||||
if (access(flag_file, F_OK) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) {
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
} else if (k == 0) {
|
||||
r = -ETIMEDOUT;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
|
||||
flush_fd(notify);
|
||||
|
||||
if (pollfd[POLL_TTY].revents == 0)
|
||||
continue;
|
||||
|
||||
if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) {
|
||||
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
r = -errno;
|
||||
goto finish;
|
||||
|
||||
} else if (n == 0)
|
||||
break;
|
||||
|
||||
if (c == '\n')
|
||||
break;
|
||||
else if (c == 21) {
|
||||
|
||||
while (p > 0) {
|
||||
p--;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\b \b", 3, false);
|
||||
}
|
||||
|
||||
} else if (c == '\b' || c == 127) {
|
||||
if (p > 0) {
|
||||
p--;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\b \b", 3, false);
|
||||
}
|
||||
} else {
|
||||
passphrase[p++] = c;
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "*", 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (ttyfd >= 0)
|
||||
loop_write(ttyfd, "\n", 1, false);
|
||||
|
||||
passphrase[p] = 0;
|
||||
|
||||
if (!(*_passphrase = strdup(passphrase))) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (notify >= 0)
|
||||
close_nointr_nofail(notify);
|
||||
|
||||
if (ttyfd >= 0) {
|
||||
if (reset_tty)
|
||||
tcsetattr(ttyfd, TCSADRAIN, &old_termios);
|
||||
|
||||
close_nointr_nofail(ttyfd);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
|
||||
|
||||
assert(f);
|
||||
|
@ -365,8 +365,6 @@ bool null_or_empty(struct stat *st);
|
||||
|
||||
DIR *xopendirat(int dirfd, const char *name);
|
||||
|
||||
int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
|
||||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
|
||||
void dual_timestamp_deserialize(const char *value, dual_timestamp *t);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user