summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-03-31 10:35:17 +0200
committerGitHub <noreply@github.com>2021-03-31 10:35:17 +0200
commitf9d8325e69da7caf44a395446206a130939d6677 (patch)
treee40553a952bc3b7ca5b2dd65de724754033e9b75 /src
parent4c31bfdf55c8065478a0fb1648b15b28d359c0e0 (diff)
parent9f17a03ae8e3b3b9a0a4fe7470f35a46622627f6 (diff)
downloadsystemd-f9d8325e69da7caf44a395446206a130939d6677.tar.gz
Merge pull request #18971 from poettering/sysusers-creds
let's read LoadCredentials=/SetCredentials= style cred in sysusers/firstboot and when asking for passwords
Diffstat (limited to 'src')
-rw-r--r--src/ask-password/ask-password.c29
-rw-r--r--src/basic/creds-util.c54
-rw-r--r--src/basic/creds-util.h12
-rw-r--r--src/basic/meson.build2
-rw-r--r--src/basic/path-util.c6
-rw-r--r--src/basic/path-util.h2
-rw-r--r--src/core/dbus-execute.c1
-rw-r--r--src/core/execute.c18
-rw-r--r--src/core/load-fragment.c28
-rw-r--r--src/core/manager.c7
-rw-r--r--src/cryptenroll/cryptenroll-password.c4
-rw-r--r--src/cryptenroll/cryptenroll.c2
-rw-r--r--src/cryptsetup/cryptsetup-fido2.c2
-rw-r--r--src/cryptsetup/cryptsetup-pkcs11.c1
-rw-r--r--src/cryptsetup/cryptsetup.c4
-rw-r--r--src/firstboot/firstboot.c66
-rw-r--r--src/home/homectl.c8
-rw-r--r--src/nspawn/nspawn.c7
-rw-r--r--src/shared/ask-password-api.c41
-rw-r--r--src/shared/ask-password-api.h15
-rw-r--r--src/shared/dissect-image.c2
-rw-r--r--src/shared/libfido2-util.c2
-rw-r--r--src/shared/pkcs11-util.c7
-rw-r--r--src/shared/pkcs11-util.h2
-rw-r--r--src/sysusers/sysusers.c47
25 files changed, 303 insertions, 66 deletions
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index 6b89f57e1b..09bcefbe66 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -12,10 +12,12 @@
#include "main-func.h"
#include "pretty-print.h"
#include "strv.h"
+#include "terminal-util.h"
static const char *arg_icon = NULL;
-static const char *arg_id = NULL;
-static const char *arg_keyname = NULL;
+static const char *arg_id = NULL; /* identifier for 'ask-password' protocol */
+static const char *arg_key_name = NULL; /* name in kernel keyring */
+static const char *arg_credential_name = NULL; /* name in $CREDENTIALS_DIRECTORY directory */
static char *arg_message = NULL;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
static bool arg_multiple = false;
@@ -32,21 +34,26 @@ static int help(void) {
if (r < 0)
return log_oom();
- printf("%s [OPTIONS...] MESSAGE\n\n"
- "Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
+ printf("%1$s [OPTIONS...] MESSAGE\n\n"
+ "%3$sQuery the user for a system passphrase, via the TTY or an UI agent.%4$s\n\n"
" -h --help Show this help\n"
" --icon=NAME Icon name\n"
" --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
" --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
+ " --credential=NAME\n"
+ " Credential name for LoadCredential=/SetCredential=\n"
+ " credentials\n"
" --timeout=SEC Timeout in seconds\n"
" --echo Do not mask input (useful for usernames)\n"
" --no-tty Ask question via agent even on TTY\n"
" --accept-cached Accept cached passwords\n"
" --multiple List multiple passwords if available\n"
" --no-output Do not print password to standard output\n"
- "\nSee the %s for details.\n",
+ "\nSee the %2$s for details.\n",
program_invocation_short_name,
- link);
+ link,
+ ansi_highlight(),
+ ansi_normal());
return 0;
}
@@ -64,6 +71,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_KEYNAME,
ARG_NO_OUTPUT,
ARG_VERSION,
+ ARG_CREDENTIAL,
};
static const struct option options[] = {
@@ -78,6 +86,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "id", required_argument, NULL, ARG_ID },
{ "keyname", required_argument, NULL, ARG_KEYNAME },
{ "no-output", no_argument, NULL, ARG_NO_OUTPUT },
+ { "credential", required_argument, NULL, ARG_CREDENTIAL },
{}
};
@@ -128,13 +137,17 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_KEYNAME:
- arg_keyname = optarg;
+ arg_key_name = optarg;
break;
case ARG_NO_OUTPUT:
arg_no_output = true;
break;
+ case ARG_CREDENTIAL:
+ arg_credential_name = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -170,7 +183,7 @@ static int run(int argc, char *argv[]) {
else
timeout = 0;
- r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l);
+ r = ask_password_auto(arg_message, arg_icon, arg_id, arg_key_name, arg_credential_name ?: "password", timeout, arg_flags, &l);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
diff --git a/src/basic/creds-util.c b/src/basic/creds-util.c
new file mode 100644
index 0000000000..58076705e7
--- /dev/null
+++ b/src/basic/creds-util.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "creds-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
+
+bool credential_name_valid(const char *s) {
+ /* We want that credential names are both valid in filenames (since that's our primary way to pass
+ * them around) and as fdnames (which is how we might want to pass them around eventually) */
+ return filename_is_valid(s) && fdname_is_valid(s);
+}
+
+int get_credentials_dir(const char **ret) {
+ const char *e;
+
+ assert(ret);
+
+ e = secure_getenv("CREDENTIALS_DIRECTORY");
+ if (!e)
+ return -ENXIO;
+
+ if (!path_is_absolute(e) || !path_is_normalized(e))
+ return -EINVAL;
+
+ *ret = e;
+ return 0;
+}
+
+int read_credential(const char *name, void **ret, size_t *ret_size) {
+ _cleanup_free_ char *fn = NULL;
+ const char *d;
+ int r;
+
+ assert(ret);
+
+ if (!credential_name_valid(name))
+ return -EINVAL;
+
+ r = get_credentials_dir(&d);
+ if (r < 0)
+ return r;
+
+ fn = path_join(d, name);
+ if (!fn)
+ return -ENOMEM;
+
+ return read_full_file_full(
+ AT_FDCWD, fn,
+ UINT64_MAX, SIZE_MAX,
+ READ_FULL_FILE_SECURE,
+ NULL,
+ (char**) ret, ret_size);
+}
diff --git a/src/basic/creds-util.h b/src/basic/creds-util.h
new file mode 100644
index 0000000000..5e33ca3776
--- /dev/null
+++ b/src/basic/creds-util.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+bool credential_name_valid(const char *s);
+
+int get_credentials_dir(const char **ret);
+
+int read_credential(const char *name, void **ret, size_t *ret_size);
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 60ef801a25..a7b8be26ac 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -35,6 +35,8 @@ basic_sources = files('''
conf-files.h
copy.c
copy.h
+ creds-util.c
+ creds-util.h
def.h
device-nodes.c
device-nodes.h
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 50ba44492e..f40f3f27e9 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -1190,9 +1190,3 @@ bool prefixed_path_strv_contains(char **l, const char *path) {
return false;
}
-
-bool credential_name_valid(const char *s) {
- /* We want that credential names are both valid in filenames (since that's our primary way to pass
- * them around) and as fdnames (which is how we might want to pass them around eventually) */
- return filename_is_valid(s) && fdname_is_valid(s);
-}
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 74ee6362ea..c0746f68d7 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -183,5 +183,3 @@ static inline const char *empty_to_root(const char *path) {
bool path_strv_contains(char **l, const char *path);
bool prefixed_path_strv_contains(char **l, const char *path);
-
-bool credential_name_valid(const char *s);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 4a1585f663..eda21f4734 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -13,6 +13,7 @@
#include "cap-list.h"
#include "capability-util.h"
#include "cpu-set-util.h"
+#include "creds-util.h"
#include "dbus-execute.h"
#include "dbus-util.h"
#include "env-util.h"
diff --git a/src/core/execute.c b/src/core/execute.c
index b644b51b01..2152fa8500 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2564,6 +2564,7 @@ static int acquire_credentials(
ReadFullFileFlags flags = READ_FULL_FILE_SECURE;
_cleanup_(erase_and_freep) char *data = NULL;
_cleanup_free_ char *j = NULL, *bindname = NULL;
+ bool missing_ok = true;
const char *source;
size_t size, add;
@@ -2577,6 +2578,8 @@ static int acquire_credentials(
if (asprintf(&bindname, "@%" PRIx64"/unit/%s/%s", random_u64(), unit, *id) < 0)
return -ENOMEM;
+ missing_ok = false;
+
} else if (params->received_credentials) {
/* If this is a relative path, take it relative to the credentials we received
* ourselves. We don't support the AF_UNIX stuff in this mode, since we are operating
@@ -2589,16 +2592,23 @@ static int acquire_credentials(
} else
source = NULL;
-
if (source)
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
else
r = -ENOENT;
- if (r == -ENOENT &&
- faccessat(dfd, *id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) /* If the source file doesn't exist, but we already acquired the key otherwise, then don't fail */
+ if (r == -ENOENT && (missing_ok || faccessat(dfd, *id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)) {
+ /* Make a missing inherited credential non-fatal, let's just continue. After all apps
+ * will get clear errors if we don't pass such a missing credential on as they
+ * themselves will get ENOENT when trying to read them, which should not be much
+ * worse than when we handle the error here and make it fatal.
+ *
+ * Also, if the source file doesn't exist, but we already acquired the key otherwise,
+ * then don't fail either. */
+ log_debug_errno(r, "Couldn't read inherited credential '%s', skipping: %m", *fn);
continue;
+ }
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to read credential '%s': %m", *fn);
add = strlen(*id) + size;
if (add > left)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index ead7f7bf11..1a1e58976a 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -16,8 +16,8 @@
#include "sd-messages.h"
#include "af-list.h"
-#include "alloc-util.h"
#include "all-units.h"
+#include "alloc-util.h"
#include "bpf-firewall.h"
#include "bus-error.h"
#include "bus-internal.h"
@@ -28,6 +28,7 @@
#include "conf-parser.h"
#include "core-varlink.h"
#include "cpu-set-util.h"
+#include "creds-util.h"
#include "env-util.h"
#include "errno-list.h"
#include "escape.h"
@@ -4607,14 +4608,23 @@ int config_parse_load_credential(
log_syntax(unit, LOG_WARNING, filename, line, 0, "Credential name \"%s\" not valid, ignoring.", k);
return 0;
}
- r = unit_full_printf(u, p, &q);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", p);
- return 0;
- }
- if (path_is_absolute(q) ? !path_is_normalized(q) : !credential_name_valid(q)) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Credential source \"%s\" not valid, ignoring.", q);
- return 0;
+
+ if (isempty(p)) {
+ /* If only one field field is specified take it as shortcut for inheriting a credential named
+ * the same way from our parent */
+ q = strdup(k);
+ if (!q)
+ return log_oom();
+ } else {
+ r = unit_full_printf(u, p, &q);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in \"%s\", ignoring: %m", p);
+ return 0;
+ }
+ if (path_is_absolute(q) ? !path_is_normalized(q) : !credential_name_valid(q)) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Credential source \"%s\" not valid, ignoring.", q);
+ return 0;
+ }
}
r = strv_consume_pair(&context->load_credentials, TAKE_PTR(k), TAKE_PTR(q));
diff --git a/src/core/manager.c b/src/core/manager.c
index 629966ea60..57bb25ca25 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -30,6 +30,7 @@
#include "clean-ipc.h"
#include "clock-util.h"
#include "core-varlink.h"
+#include "creds-util.h"
#include "dbus-job.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
@@ -49,8 +50,8 @@
#include "install.h"
#include "io-util.h"
#include "label.h"
-#include "locale-setup.h"
#include "load-fragment.h"
+#include "locale-setup.h"
#include "log.h"
#include "macro.h"
#include "manager.h"
@@ -852,8 +853,8 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
if (r < 0)
return r;
- e = secure_getenv("CREDENTIALS_DIRECTORY");
- if (e) {
+ r = get_credentials_dir(&e);
+ if (r >= 0) {
m->received_credentials = strdup(e);
if (!m->received_credentials)
return -ENOMEM;
diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c
index e08f564d3f..0314831174 100644
--- a/src/cryptenroll/cryptenroll-password.c
+++ b/src/cryptenroll/cryptenroll-password.c
@@ -57,7 +57,7 @@ int enroll_password(
if (!question)
return log_oom();
- r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords);
+ r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
@@ -68,7 +68,7 @@ int enroll_password(
if (!question)
return log_oom();
- r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords2);
+ r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c
index a137a41c9d..7d12c427b3 100644
--- a/src/cryptenroll/cryptenroll.c
+++ b/src/cryptenroll/cryptenroll.c
@@ -417,7 +417,7 @@ static int prepare_luks(
"Too many attempts, giving up:");
r = ask_password_auto(
- question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY,
+ question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY,
ask_password_flags,
&passwords);
if (r < 0)
diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c
index dfdb964360..82b83ee477 100644
--- a/src/cryptsetup/cryptsetup-fido2.c
+++ b/src/cryptsetup/cryptsetup-fido2.c
@@ -88,7 +88,7 @@ int acquire_fido2_key(
pins = strv_free_erase(pins);
- r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", until, flags, &pins);
+ r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
if (r < 0)
return log_error_errno(r, "Failed to ask for user password: %m");
diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c
index 8d7d74fb75..6d7b01176c 100644
--- a/src/cryptsetup/cryptsetup-pkcs11.c
+++ b/src/cryptsetup/cryptsetup-pkcs11.c
@@ -70,6 +70,7 @@ static int pkcs11_callback(
data->friendly_name,
"drive-harddisk",
"pkcs11-pin",
+ "cryptsetup.pkcs11-pin",
data->until,
NULL);
if (r < 0)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index dba26a54a3..5c55dcd197 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -545,7 +545,7 @@ static int get_password(
id = strjoina("cryptsetup:", disk_path);
- r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until,
ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
&passwords);
if (r < 0)
@@ -561,7 +561,7 @@ static int get_password(
id = strjoina("cryptsetup-verification:", disk_path);
- r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", "cryptsetup.passphrase", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query verification password: %m");
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index aa7251d1ef..ba0b360cc1 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "copy.h"
+#include "creds-util.h"
#include "dissect-image.h"
#include "env-file.h"
#include "fd-util.h"
@@ -43,8 +44,8 @@
static char *arg_root = NULL;
static char *arg_image = NULL;
static char *arg_locale = NULL; /* $LANG */
-static char *arg_keymap = NULL;
static char *arg_locale_messages = NULL; /* $LC_MESSAGES */
+static char *arg_keymap = NULL;
static char *arg_timezone = NULL;
static char *arg_hostname = NULL;
static sd_id128_t arg_machine_id = {};
@@ -232,11 +233,29 @@ static bool locale_is_ok(const char *name) {
static int prompt_locale(void) {
_cleanup_strv_free_ char **locales = NULL;
+ bool acquired_from_creds = false;
int r;
if (arg_locale || arg_locale_messages)
return 0;
+ r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
+ else
+ acquired_from_creds = true;
+
+ r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.locale-message, ignoring: %m");
+ else
+ acquired_from_creds = true;
+
+ if (acquired_from_creds) {
+ log_debug("Acquired locale from credentials.");
+ return 0;
+ }
+
if (!arg_prompt_locale)
return 0;
@@ -336,6 +355,14 @@ static int prompt_keymap(void) {
if (arg_keymap)
return 0;
+ r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
+ else {
+ log_debug("Acquired keymap from credential.");
+ return 0;
+ }
+
if (!arg_prompt_keymap)
return 0;
@@ -407,6 +434,14 @@ static int prompt_timezone(void) {
if (arg_timezone)
return 0;
+ r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
+ else {
+ log_debug("Acquired timezone from credential.");
+ return 0;
+ }
+
if (!arg_prompt_timezone)
return 0;
@@ -558,6 +593,22 @@ static int prompt_root_password(void) {
if (arg_root_password)
return 0;
+ r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
+ if (r == -ENOENT) {
+ r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
+ else {
+ arg_root_password_is_hashed = false;
+ return 0;
+ }
+ } else if (r < 0)
+ log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
+ else {
+ arg_root_password_is_hashed = true;
+ return 0;
+ }
+
if (!arg_prompt_root_password)
return 0;
@@ -631,7 +682,18 @@ static int find_shell(const char *path, const char *root) {
static int prompt_root_shell(void) {
int r;
- if (arg_root_shell || !arg_prompt_root_shell)
+ if (arg_root_shell)
+ return 0;
+
+ r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
+ else {
+ log_debug("Acquired root shell from credential.");
+ return 0;
+ }
+
+ if (!arg_prompt_root_shell)
return 0;
print_welcome();
diff --git a/src/home/homectl.c b/src/home/homectl.c
index 9d12b9abae..cf1a2d9f9b 100644
--- a/src/home/homectl.c
+++ b/src/home/homectl.c
@@ -221,7 +221,7 @@ static int acquire_existing_password(const char *user_name, UserRecord *hr, bool
user_name) < 0)
return log_oom();
- r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password);
+ r = ask_password_auto(question, "user-home", NULL, "home-password", "home.password", USEC_INFINITY, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &password);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");
@@ -257,7 +257,7 @@ static int acquire_token_pin(const char *user_name, UserRecord *hr) {
return log_oom();
/* We never cache or use cached PINs, since usually there are only very few attempts allowed before the PIN is blocked */
- r = ask_password_auto(question, "user-home", NULL, "token-pin", USEC_INFINITY, 0, &pin);
+ r = ask_password_auto(question, "user-home", NULL, "token-pin", "home.token-pin", USEC_INFINITY, 0, &pin);
if (r < 0)
return log_error_errno(r, "Failed to acquire security token PIN: %m");
@@ -1010,7 +1010,7 @@ static int acquire_new_password(
if (asprintf(&question, "Please enter new password for user %s:", user_name) < 0)
return log_oom();
- r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &first);
+ r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &first);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");
@@ -1018,7 +1018,7 @@ static int acquire_new_password(
if (asprintf(&question, "Please enter new password for user %s (repeat):", user_name) < 0)
return log_oom();
- r = ask_password_auto(question, "user-home", NULL, "home-password", USEC_INFINITY, 0, &second);
+ r = ask_password_auto(question, "user-home", NULL, "home-password", "home.new-password", USEC_INFINITY, 0, &second);
if (r < 0)
return log_error_errno(r, "Failed to acquire password: %m");
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index f89fa1a573..164a330207 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -35,6 +35,7 @@
#include "cgroup-util.h"
#include "copy.h"
#include "cpu-set-util.h"
+#include "creds-util.h"
#include "dev-setup.h"
#include "discover-image.h"
#include "dissect-image.h"
@@ -1592,9 +1593,9 @@ static int parse_argv(int argc, char *argv[]) {
else {
const char *e;
- e = getenv("CREDENTIALS_DIRECTORY");
- if (!e)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential not available (no credentials passed at all): %s", word);
+ r = get_credentials_dir(&e);
+ if (r < 0)
+ return log_error_errno(r, "Credential not available (no credentials passed at all): %s", word);
j = path_join(e, p);
if (!j)
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 729aa1fb00..04c6b5287e 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -20,6 +20,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
+#include "creds-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
@@ -971,11 +972,33 @@ finish:
return r;
}
+static int ask_password_credential(const char *credential_name, AskPasswordFlags flags, char ***ret) {
+ _cleanup_(erase_and_freep) char *buffer = NULL;
+ size_t size;
+ char **l;
+ int r;
+
+ assert(credential_name);
+ assert(ret);
+
+ r = read_credential(credential_name, (void**) &buffer, &size);
+ if (IN_SET(r, -ENXIO, -ENOENT)) /* No credentials passed or this credential not defined? */
+ return -ENOKEY;
+
+ l = strv_parse_nulstr(buffer, size);
+ if (!l)
+ return -ENOMEM;
+
+ *ret = l;
+ return 0;
+}
+
int ask_password_auto(
const char *message,
const char *icon,
- const char *id,
- const char *keyname,
+ const char *id, /* id in "ask-password" protocol */
+ const char *key_name, /* name in kernel keyring */
+ const char *credential_name, /* name in $CREDENTIALS_DIRECTORY directory */
usec_t until,
AskPasswordFlags flags,
char ***ret) {
@@ -984,20 +1007,26 @@ int ask_password_auto(
assert(ret);
+ if (!(flags & ASK_PASSWORD_NO_CREDENTIAL) && credential_name) {
+ r = ask_password_credential(credential_name, flags, ret);
+ if (r != -ENOKEY)
+ return r;
+ }
+
if ((flags & ASK_PASSWORD_ACCEPT_CACHED) &&
- keyname &&
+ key_name &&
((flags & ASK_PASSWORD_NO_TTY) || !isatty(STDIN_FILENO)) &&
(flags & ASK_PASSWORD_NO_AGENT)) {
- r = ask_password_keyring(keyname, flags, ret);
+ r = ask_password_keyring(key_name, flags, ret);
if (r != -ENOKEY)
return r;
}
if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO))
- return ask_password_tty(-1, message, keyname, until, flags, NULL, ret);
+ return ask_password_tty(-1, message, key_name, until, flags, NULL, ret);
if (!(flags & ASK_PASSWORD_NO_AGENT))
- return ask_password_agent(message, icon, id, keyname, until, flags, ret);
+ return ask_password_agent(message, icon, id, key_name, until, flags, ret);
return -EUNATCH;
}
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 7aac5e5976..bb507b2e8d 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -6,16 +6,17 @@
#include "time-util.h"
typedef enum AskPasswordFlags {
- ASK_PASSWORD_ACCEPT_CACHED = 1 << 0,
- ASK_PASSWORD_PUSH_CACHE = 1 << 1,
+ ASK_PASSWORD_ACCEPT_CACHED = 1 << 0, /* read from kernel keyring */
+ ASK_PASSWORD_PUSH_CACHE = 1 << 1, /* write to kernel keyring after getting password from elsewhere */
ASK_PASSWORD_ECHO = 1 << 2, /* show the password literally while reading, instead of "*" */
ASK_PASSWORD_SILENT = 1 << 3, /* do no show any password at all while reading */
- ASK_PASSWORD_NO_TTY = 1 << 4,
- ASK_PASSWORD_NO_AGENT = 1 << 5,
+ ASK_PASSWORD_NO_TTY = 1 << 4, /* never ask for password on tty */
+ ASK_PASSWORD_NO_AGENT = 1 << 5, /* never ask for password via agent */
ASK_PASSWORD_CONSOLE_COLOR = 1 << 6, /* Use color if /dev/console points to a console that supports color */
+ ASK_PASSWORD_NO_CREDENTIAL = 1 << 7, /* never use $CREDENTIALS_DIRECTORY data */
} AskPasswordFlags;
-int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
+int ask_password_tty(int tty_fd, const char *message, const char *key_name, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
int ask_password_plymouth(const char *message, usec_t until, AskPasswordFlags flags, const char *flag_file, char ***ret);
-int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
-int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
+int ask_password_agent(const char *message, const char *icon, const char *id, const char *key_name, usec_t until, AskPasswordFlags flag, char ***ret);
+int ask_password_auto(const char *message, const char *icon, const char *id, const char *key_name, const char *credential_name, usec_t until, AskPasswordFlags flag, char ***ret);
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index c4d631c4a9..c022368dfb 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -2077,7 +2077,7 @@ int dissected_image_decrypt_interactively(
z = strv_free(z);
- r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", USEC_INFINITY, 0, &z);
+ r = ask_password_auto("Please enter image passphrase:", NULL, "dissect", "dissect", "dissect.passphrase", USEC_INFINITY, 0, &z);
if (r < 0)
return log_error_errno(r, "Failed to query for passphrase: %m");
diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c
index 22b8aba07e..951ed09899 100644
--- a/src/shared/libfido2-util.c
+++ b/src/shared/libfido2-util.c
@@ -566,7 +566,7 @@ int fido2_generate_hmac_hash(
if (!has_client_pin)
log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring.");
- r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", USEC_INFINITY, 0, &pin);
+ r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", "fido2-pin", USEC_INFINITY, 0, &pin);
if (r < 0)
return log_error_errno(r, "Failed to acquire user PIN: %m");
diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c
index 27c209cdf8..4fa1effb2d 100644
--- a/src/shared/pkcs11-util.c
+++ b/src/shared/pkcs11-util.c
@@ -181,7 +181,8 @@ int pkcs11_token_login(
const CK_TOKEN_INFO *token_info,
const char *friendly_name,
const char *icon_name,
- const char *keyname,
+ const char *key_name,
+ const char *credential_name,
usec_t until,
char **ret_used_pin) {
@@ -269,7 +270,7 @@ int pkcs11_token_login(
return log_oom();
/* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
- r = ask_password_auto(text, icon_name, id, keyname, until, 0, &passwords);
+ r = ask_password_auto(text, icon_name, id, key_name, credential_name, until, 0, &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label);
}
@@ -959,7 +960,7 @@ static int pkcs11_acquire_certificate_callback(
/* Called for every token matching our URI */
- r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", UINT64_MAX, &pin_used);
+ r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, &pin_used);
if (r < 0)
return r;
diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h
index f32ab30429..c2c852f0eb 100644
--- a/src/shared/pkcs11-util.h
+++ b/src/shared/pkcs11-util.h
@@ -30,7 +30,7 @@ char *pkcs11_token_label(const CK_TOKEN_INFO *token_info);
char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info);
char *pkcs11_token_model(const CK_TOKEN_INFO *token_info);
-int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *keyname, usec_t until, char **ret_used_pin);
+int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, char **ret_used_pin);
int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object);
#if HAVE_OPENSSL
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 27573b74e6..8d3086e209 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -6,6 +6,7 @@
#include "alloc-util.h"
#include "conf-files.h"
#include "copy.h"
+#include "creds-util.h"
#include "def.h"
#include "dissect-image.h"
#include "fd-util.h"
@@ -13,7 +14,9 @@
#include "format-util.h"
#include "fs-util.h"
#include "hashmap.h"
+#include "libcrypt-util.h"
#include "main-func.h"
+#include "memory-util.h"
#include "mount-util.h"
#include "nscd-flush.h"
#include "pager.h"
@@ -429,6 +432,8 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
}
ORDERED_HASHMAP_FOREACH(i, todo_uids) {
+ _cleanup_free_ char *creds_shell = NULL, *cn = NULL;
+
struct passwd n = {
.pw_name = i->name,
.pw_uid = i->uid,
@@ -446,6 +451,17 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
.pw_shell = i->shell ?: (char*) default_shell(i->uid),
};
+ /* Try to pick up the shell for this account via the credentials logic */
+ cn = strjoin("passwd.shell.", i->name);
+ if (!cn)
+ return -ENOMEM;
+
+ r = read_credential(cn, (void**) &creds_shell, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+ else
+ n.pw_shell = creds_shell;
+
r = putpwent_sane(&n, passwd);
if (r < 0)
return r;
@@ -530,6 +546,9 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
}
ORDERED_HASHMAP_FOREACH(i, todo_uids) {
+ _cleanup_(erase_and_freep) char *creds_password = NULL;
+ _cleanup_free_ char *cn = NULL;
+
struct spwd n = {
.sp_namp = i->name,
.sp_pwdp = (char*) "!*", /* lock this password, and make it invalid */
@@ -542,6 +561,34 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
.sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
};
+ /* Try to pick up the password for this account via the credentials logic */
+ cn = strjoin("passwd.hashed-password.", i->name);
+ if (!cn)
+ return -ENOMEM;
+
+ r = read_credential(cn, (void**) &creds_password, NULL);
+ if (r == -ENOENT) {
+ _cleanup_(erase_and_freep) char *plaintext_password = NULL;
+
+ free(cn);
+ cn = strjoin("passwd.plaintext-password.", i->name);
+ if (!cn)
+ return -ENOMEM;
+
+ r = read_credential(cn, (void**) &plaintext_password, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+ else {
+ r = hash_password(plaintext_password, &creds_password);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to hash password: %m");
+ }
+ } else if (r < 0)
+ log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
+
+ if (creds_password)
+ n.sp_pwdp = creds_password;
+
r = putspent_sane(&n, shadow);
if (r < 0)
return r;