cryptsetup: hook up tool with ask-password

This commit is contained in:
Lennart Poettering 2010-11-12 00:39:17 +01:00
parent 5a1e99375d
commit 7f4e08056d
11 changed files with 761 additions and 449 deletions

View File

@ -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 = \

View File

@ -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
View 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
View 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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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:

View File

@ -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,

View File

@ -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);

View File

@ -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);