summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README21
-rw-r--r--TODO6
-rw-r--r--src/ask-password-api.c55
-rw-r--r--src/ask-password-api.h4
-rw-r--r--src/ask-password.c68
-rw-r--r--src/cryptsetup.c56
-rw-r--r--src/strv.c42
-rw-r--r--src/strv.h2
-rw-r--r--src/test-env-replace.c8
-rw-r--r--src/tty-ask-password-agent.c103
10 files changed, 285 insertions, 80 deletions
diff --git a/README b/README
index b2a6dc3ecf..a183cb364f 100644
--- a/README
+++ b/README
@@ -27,7 +27,7 @@ AUTHOR:
Lennart Poettering with major support from Kay Sievers
REQUIREMENTS:
- Linux kernel >= 2.6.30 (with autofs4, devtmpfs, cgroups, ipv6)
+ Linux kernel >= 2.6.30 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6)
libudev >= 163
dbus >= 1.4.0
libcap
@@ -47,10 +47,27 @@ REQUIREMENTS:
automake
autoconf
libtool
+ make, gcc, and similar tools
During runtime you need the following dependencies:
util-linux > v2.18 (requires fsck -l, agetty -s)
- sulogin (from sysvinit-tools)
+ sulogin (from sysvinit-tools, optional but recommended)
plymouth (optional)
dracut (optional)
+
+WARNINGS:
+ systemd will warn you during boot if /etc/mtab is not a
+ symlink to /proc/mounts. Please ensure that /etc/mtab is a
+ proper symlink.
+
+ systemd will warn you during boot if /usr is on a different
+ file system than /. While in systemd itself very little will
+ break if /usr is on a seperate partition many of its
+ dependencies very likely will break sooner or later in one
+ form or another. For example udev rules tend to refer to
+ binaries in /usr, binaries that link to libraries in /usr or
+ binaries that refer to data files in /usr. Since these
+ breakages are not always directly visible systemd will warn
+ about this, since this kind of file system setup is not really
+ supported anymore by the basic set of Linux OS components.
diff --git a/TODO b/TODO
index 415eb76224..64f7ad7d3c 100644
--- a/TODO
+++ b/TODO
@@ -4,17 +4,11 @@ F15:
* isolate multi-user.target doesn't start a getty@tty1 if we run it from graphical.target
-* when plymouth is disabled the console password entry stuff seems to be borked
- https://bugzilla.redhat.com/show_bug.cgi?id=655538
-
* increase password timeout
https://bugzilla.redhat.com/show_bug.cgi?id=677962
* finish syslog socket stuff
-* support caching password questions in plymouth and on the console
- https://bugzilla.redhat.com/show_bug.cgi?id=677438
-
* load EnvironmentFile= when starting services, not when reloading configuration
https://bugzilla.redhat.com/show_bug.cgi?id=661282
diff --git a/src/ask-password-api.c b/src/ask-password-api.c
index 9f7023e328..cd663ae09c 100644
--- a/src/ask-password-api.c
+++ b/src/ask-password-api.c
@@ -32,6 +32,7 @@
#include <sys/signalfd.h>
#include "util.h"
+#include "strv.h"
#include "ask-password-api.h"
@@ -251,12 +252,12 @@ fail:
return r;
}
-
int ask_password_agent(
const char *message,
const char *icon,
usec_t until,
- char **_passphrase) {
+ bool accept_cached,
+ char ***_passphrases) {
enum {
FD_SOCKET,
@@ -273,6 +274,8 @@ int ask_password_agent(
sigset_t mask;
struct pollfd pollfd[_FD_MAX];
+ assert(_passphrases);
+
mkdir_p("/dev/.systemd/ask-password", 0755);
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
@@ -310,9 +313,11 @@ int ask_password_agent(
"[Ask]\n"
"PID=%lu\n"
"Socket=%s\n"
+ "AcceptCached=%i\n"
"NotAfter=%llu\n",
(unsigned long) getpid(),
socket_name,
+ accept_cached ? 1 : 0,
(unsigned long long) until);
if (message)
@@ -384,8 +389,10 @@ int ask_password_agent(
goto finish;
}
- if (pollfd[FD_SIGNAL].revents & POLLIN)
- break;
+ if (pollfd[FD_SIGNAL].revents & POLLIN) {
+ r = -EINTR;
+ goto finish;
+ }
if (pollfd[FD_SOCKET].revents != POLLIN) {
log_error("Unexpected poll() event.");
@@ -395,7 +402,7 @@ int ask_password_agent(
zero(iovec);
iovec.iov_base = passphrase;
- iovec.iov_len = sizeof(passphrase)-1;
+ iovec.iov_len = sizeof(passphrase);
zero(control);
zero(msghdr);
@@ -435,13 +442,21 @@ int ask_password_agent(
}
if (passphrase[0] == '+') {
- passphrase[n] = 0;
+ char **l;
- if (!(*_passphrase = strdup(passphrase+1))) {
+ if (!(l = strv_parse_nulstr(passphrase+1, n-1))) {
r = -ENOMEM;
goto finish;
}
+ if (strv_length(l) <= 0) {
+ strv_free(l);
+ log_error("Invalid packet");
+ continue;
+ }
+
+ *_passphrases = l;
+
} else if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
@@ -481,12 +496,26 @@ finish:
return r;
}
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase) {
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) {
assert(message);
- assert(_passphrase);
+ assert(_passphrases);
+
+ if (isatty(STDIN_FILENO)) {
+ int r;
+ char *s = NULL, **l = NULL;
+
+ if ((r = ask_password_tty(message, until, NULL, &s)) < 0)
+ return r;
+
+ l = strv_new(s, NULL);
+ free(s);
+
+ if (!l)
+ return -ENOMEM;
+
+ *_passphrases = l;
+ return r;
- if (isatty(STDIN_FILENO))
- return ask_password_tty(message, until, NULL, _passphrase);
- else
- return ask_password_agent(message, icon, until, _passphrase);
+ } else
+ return ask_password_agent(message, icon, until, accept_cached, _passphrases);
}
diff --git a/src/ask-password-api.h b/src/ask-password-api.h
index ec858bac78..fec8625a0f 100644
--- a/src/ask-password-api.h
+++ b/src/ask-password-api.h
@@ -26,8 +26,8 @@
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);
+int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase);
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
#endif
diff --git a/src/ask-password.c b/src/ask-password.c
index 596c8e08f0..c77376482e 100644
--- a/src/ask-password.c
+++ b/src/ask-password.c
@@ -38,21 +38,26 @@
#include "log.h"
#include "macro.h"
#include "util.h"
+#include "strv.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 bool arg_accept_cached = false;
+static bool arg_multiple = false;
static int help(void) {
printf("%s [OPTIONS...] MESSAGE\n\n"
"Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
- " -h --help Show this help\n"
- " --icon=NAME Icon name\n"
- " --timeout=SEC Timeout in sec\n"
- " --no-tty Ask question via agent even on TTY\n",
+ " -h --help Show this help\n"
+ " --icon=NAME Icon name\n"
+ " --timeout=SEC Timeout in sec\n"
+ " --no-tty Ask question via agent even on TTY\n"
+ " --accept-cached Accept cached passwords\n"
+ " --multiple List multiple passwords if available\n",
program_invocation_short_name);
return 0;
@@ -63,15 +68,19 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_ICON = 0x100,
ARG_TIMEOUT,
- ARG_NO_TTY
+ ARG_NO_TTY,
+ ARG_ACCEPT_CACHED,
+ ARG_MULTIPLE
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "icon", required_argument, NULL, ARG_ICON },
- { "timeout", required_argument, NULL, ARG_TIMEOUT },
- { "no-tty", no_argument, NULL, ARG_NO_TTY },
- { NULL, 0, NULL, 0 }
+ { "help", no_argument, NULL, 'h' },
+ { "icon", required_argument, NULL, ARG_ICON },
+ { "timeout", required_argument, NULL, ARG_TIMEOUT },
+ { "no-tty", no_argument, NULL, ARG_NO_TTY },
+ { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
+ { "multiple", no_argument, NULL, ARG_MULTIPLE },
+ { NULL, 0, NULL, 0 }
};
int c;
@@ -102,6 +111,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_use_tty = false;
break;
+ case ARG_ACCEPT_CACHED:
+ arg_accept_cached = true;
+ break;
+
+ case ARG_MULTIPLE:
+ arg_multiple = true;
+ break;
+
case '?':
return -EINVAL;
@@ -122,7 +139,6 @@ static int parse_argv(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
int r;
- char *password = NULL;
log_parse_environment();
log_open();
@@ -130,18 +146,32 @@ int main(int argc, char *argv[]) {
if ((r = parse_argv(argc, argv)) <= 0)
goto finish;
- 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 (arg_use_tty && isatty(STDIN_FILENO)) {
+ char *password = NULL;
+
+ if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) {
+ puts(password);
+ free(password);
+ }
+
+ } else {
+ char **l;
+
+ if ((r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, arg_accept_cached, &l)) >= 0) {
+ char **p;
+
+ STRV_FOREACH(p, l) {
+ puts(*p);
- if (r >= 0) {
- fputs(password, stdout);
- fflush(stdout);
+ if (!arg_multiple)
+ break;
+ }
+
+ strv_free(l);
+ }
}
finish:
- free(password);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index c80572aed9..f72a14abf6 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -28,6 +28,7 @@
#include "log.h"
#include "util.h"
+#include "strv.h"
#include "ask-password-api.h"
static const char *opt_type = NULL; /* LUKS1 or PLAIN */
@@ -179,7 +180,7 @@ finish:
int main(int argc, char *argv[]) {
int r = EXIT_FAILURE;
struct crypt_device *cd = NULL;
- char *password = NULL, *truncated_cipher = NULL;
+ char **passwords = NULL, *truncated_cipher = NULL;
const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
char *description = NULL;
@@ -268,18 +269,19 @@ int main(int argc, char *argv[]) {
for (try = 0; try < opt_tries; try++) {
bool pass_volume_key = false;
- free(password);
- password = NULL;
+ strv_free(passwords);
+ passwords = NULL;
if (!key_file) {
char *text;
+ char **p;
if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
log_error("Out of memory");
goto finish;
}
- k = ask_password_auto(text, "drive-harddisk", until, &password);
+ k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
free(text);
if (k < 0) {
@@ -288,14 +290,16 @@ int main(int argc, char *argv[]) {
}
if (opt_verify) {
- char *password2 = NULL;
+ char **passwords2 = NULL;
+
+ assert(strv_length(passwords) == 1);
if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
log_error("Out of memory");
goto finish;
}
- k = ask_password_auto(text, "drive-harddisk", until, &password2);
+ k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
free(text);
if (k < 0) {
@@ -303,28 +307,32 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (!streq(password, password2)) {
+ assert(strv_length(passwords2) == 1);
+
+ if (!streq(passwords[0], passwords2[0])) {
log_warning("Passwords did not match, retrying.");
- free(password2);
+ strv_free(passwords2);
continue;
}
- free(password2);
+ strv_free(passwords2);
}
- if (strlen(password)+1 < opt_key_size) {
+ STRV_FOREACH(p, passwords) {
char *c;
- /* Pad password if necessary */
+ if (strlen(*p)+1 >= opt_key_size)
+ continue;
+ /* Pad password if necessary */
if (!(c = new(char, opt_key_size))) {
log_error("Out of memory.");
goto finish;
}
- strncpy(c, password, opt_key_size);
- free(password);
- password = c;
+ strncpy(c, *p, opt_key_size);
+ free(*p);
+ *p = c;
}
}
@@ -367,10 +375,20 @@ int main(int argc, char *argv[]) {
if (key_file)
k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_key_size, flags);
- else if (pass_volume_key)
- k = crypt_activate_by_volume_key(cd, argv[2], password, opt_key_size, flags);
- else
- k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, password, strlen(password), flags);
+ else {
+ char **p;
+
+ STRV_FOREACH(p, passwords) {
+
+ if (pass_volume_key)
+ k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
+ else
+ k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
+
+ if (k >= 0)
+ break;
+ }
+ }
if (k >= 0)
break;
@@ -421,7 +439,7 @@ finish:
free(truncated_cipher);
- free(password);
+ strv_free(passwords);
free(description);
diff --git a/src/strv.c b/src/strv.c
index d1c7b2c32d..b1643b357f 100644
--- a/src/strv.c
+++ b/src/strv.c
@@ -577,3 +577,45 @@ char **strv_env_clean(char **l) {
return ret;
}
+
+char **strv_parse_nulstr(const char *s, size_t l) {
+ const char *p;
+ unsigned c = 0, i = 0;
+ char **v;
+
+ assert(s || l <= 0);
+
+ if (l <= 0)
+ return strv_new(NULL, NULL);
+
+ for (p = s; p < s + l; p++)
+ if (*p == 0)
+ c++;
+
+ if (s[l-1] != 0)
+ c++;
+
+ if (!(v = new0(char*, c+1)))
+ return NULL;
+
+ p = s;
+ while (p < s + l) {
+ const char *e;
+
+ e = memchr(p, 0, s + l - p);
+
+ if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) {
+ strv_free(v);
+ return NULL;
+ }
+
+ if (!e)
+ break;
+
+ p = e + 1;
+ }
+
+ assert(i == c);
+
+ return v;
+}
diff --git a/src/strv.h b/src/strv.h
index 5af84ee41f..064576ce1e 100644
--- a/src/strv.h
+++ b/src/strv.h
@@ -65,6 +65,8 @@ char *strv_env_get(char **x, const char *n);
char **strv_env_clean(char **l);
+char **strv_parse_nulstr(const char *s, size_t l);
+
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)
diff --git a/src/test-env-replace.c b/src/test-env-replace.c
index 4188c67dde..05dbacd7df 100644
--- a/src/test-env-replace.c
+++ b/src/test-env-replace.c
@@ -48,6 +48,14 @@ int main(int argc, char *argv[]) {
};
char **i, **r, *t, **a, **b;
+ const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+
+ a = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+
+ STRV_FOREACH(i, a)
+ printf("nulstr--%s\n", *i);
+
+ strv_free(a);
r = replace_env_argv((char**) line, (char**) env);
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index 655bfb9ff5..14b01486bd 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -37,6 +37,7 @@
#include "utmp-wtmp.h"
#include "socket-util.h"
#include "ask-password-api.h"
+#include "strv.h"
static enum {
ACTION_LIST,
@@ -48,7 +49,13 @@ static enum {
static bool arg_plymouth = false;
static bool arg_console = false;
-static int ask_password_plymouth(const char *message, usec_t until, const char *flag_file, char **_passphrase) {
+static int ask_password_plymouth(
+ const char *message,
+ usec_t until,
+ const char *flag_file,
+ bool accept_cached,
+ char ***_passphrases) {
+
int fd = -1, notify = -1;
union sockaddr_union sa;
char *packet = NULL;
@@ -62,6 +69,8 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
POLL_INOTIFY
};
+ assert(_passphrases);
+
if (flag_file) {
if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
r = -errno;
@@ -88,7 +97,13 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
goto finish;
}
- if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+ if (accept_cached) {
+ packet = strdup("c");
+ n = 1;
+ } else
+ asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n);
+
+ if (!packet) {
r = -ENOMEM;
goto finish;
}
@@ -155,15 +170,38 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
continue;
if (buffer[0] == 5) {
+
+ if (accept_cached) {
+ /* Hmm, first try with cached
+ * passwords failed, so let's retry
+ * with a normal password request */
+ free(packet);
+ packet = NULL;
+
+ if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
+ r = k < 0 ? (int) k : -EIO;
+ goto finish;
+ }
+
+ accept_cached = false;
+ p = 0;
+ continue;
+ }
+
/* No password, because UI not shown */
r = -ENOENT;
goto finish;
- } else if (buffer[0] == 2) {
+ } else if (buffer[0] == 2 || buffer[0] == 9) {
uint32_t size;
- char *s;
+ char **l;
- /* One answer */
+ /* One ore more answers */
if (p < 5)
continue;
@@ -176,13 +214,14 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
if (p-5 < size)
continue;
- if (!(s = strndup(buffer + 5, size))) {
+ if (!(l = strv_parse_nulstr(buffer + 5, size))) {
r = -ENOMEM;
goto finish;
}
- *_passphrase = s;
+ *_passphrases = l;
break;
+
} else {
/* Unknown packet */
r = -EIO;
@@ -209,12 +248,14 @@ static int parse_password(const char *filename, char **wall) {
uint64_t not_after = 0;
unsigned pid = 0;
int socket_fd = -1;
+ bool accept_cached = false;
const ConfigItem items[] = {
- { "Socket", config_parse_string, &socket_name, "Ask" },
- { "NotAfter", config_parse_uint64, &not_after, "Ask" },
- { "Message", config_parse_string, &message, "Ask" },
- { "PID", config_parse_unsigned, &pid, "Ask" },
+ { "Socket", config_parse_string, &socket_name, "Ask" },
+ { "NotAfter", config_parse_uint64, &not_after, "Ask" },
+ { "Message", config_parse_string, &message, "Ask" },
+ { "PID", config_parse_unsigned, &pid, "Ask" },
+ { "AcceptCached", config_parse_bool, &accept_cached, "Ask" },
{ NULL, NULL, NULL, NULL }
};
@@ -274,7 +315,7 @@ static int parse_password(const char *filename, char **wall) {
struct sockaddr sa;
struct sockaddr_un un;
} sa;
- char *password;
+ size_t packet_length;
assert(arg_action == ACTION_QUERY ||
arg_action == ACTION_WATCH);
@@ -288,10 +329,32 @@ static int parse_password(const char *filename, char **wall) {
goto finish;
}
- if (arg_plymouth)
- r = ask_password_plymouth(message, not_after, filename, &password);
- else {
+ if (arg_plymouth) {
+ char **passwords;
+
+ if ((r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords)) >= 0) {
+ char **p;
+
+ packet_length = 1;
+ STRV_FOREACH(p, passwords)
+ packet_length += strlen(*p) + 1;
+
+ if (!(packet = new(char, packet_length)))
+ r = -ENOMEM;
+ else {
+ char *d;
+
+ packet[0] = '+';
+ d = packet+1;
+
+ STRV_FOREACH(p, passwords)
+ d = stpcpy(d, *p) + 1;
+ }
+ }
+
+ } else {
int tty_fd = -1;
+ char *password;
if (arg_console)
if ((tty_fd = acquire_terminal("/dev/console", false, false, false)) < 0) {
@@ -305,6 +368,11 @@ static int parse_password(const char *filename, char **wall) {
close_nointr_nofail(tty_fd);
release_terminal();
}
+
+ asprintf(&packet, "+%s", password);
+ free(password);
+
+ packet_length = strlen(packet);
}
if (r < 0) {
@@ -312,9 +380,6 @@ static int parse_password(const char *filename, char **wall) {
goto finish;
}
- asprintf(&packet, "+%s", password);
- free(password);
-
if (!packet) {
log_error("Out of memory");
r = -ENOMEM;
@@ -331,7 +396,7 @@ static int parse_password(const char *filename, char **wall) {
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(socket_fd, packet, strlen(packet), MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
+ if (sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
log_error("Failed to send: %m");
r = -errno;
goto finish;