diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml
index aa974837cd..1dd7f8aee6 100644
--- a/man/systemd.system-credentials.xml
+++ b/man/systemd.system-credentials.xml
@@ -378,6 +378,19 @@
+
+ home.add-signing-key.*
+
+ Adds a new signing key for user records to the system. The credential contents should contain
+ a user signing key, for example as reported by homectl get-signing-key. Multiple
+ keys may be specified, and they will be put in place under the name of the credential name suffix
+ (which must itself carry the .public suffix). For details see
+ homectl1.
+
+
+
+
+
home.create.*
diff --git a/src/home/homectl.c b/src/home/homectl.c
index 6857acbcc6..66f3f773f6 100644
--- a/src/home/homectl.c
+++ b/src/home/homectl.c
@@ -2702,6 +2702,8 @@ static int create_interactively(void) {
return create_home_common(/* input= */ NULL, /* show_enforce_password_policy_hint= */ false);
}
+static int add_signing_keys_from_credentials(void);
+
static int verb_firstboot(int argc, char *argv[], void *userdata) {
int r;
@@ -2717,11 +2719,13 @@ static int verb_firstboot(int argc, char *argv[], void *userdata) {
arg_prompt_new_user = false;
}
+ int ret = 0;
+
+ RET_GATHER(ret, add_signing_keys_from_credentials());
+
r = create_from_credentials();
- if (r < 0)
- return r;
- if (r > 0) /* Already created users from credentials */
- return 0;
+ RET_GATHER(ret, r);
+ bool existing_users = r > 0;
r = getenv_bool("SYSTEMD_HOME_FIRSTBOOT_OVERRIDE");
if (r == 0)
@@ -2730,16 +2734,21 @@ static int verb_firstboot(int argc, char *argv[], void *userdata) {
if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_HOME_FIRSTBOOT_OVERRIDE, ignoring: %m");
- r = has_regular_user();
- if (r < 0)
- return r;
- if (r > 0) {
- log_info("Regular user already present in user database, skipping user creation.");
+ if (!existing_users) {
+ r = has_regular_user();
+ if (r < 0)
+ return r;
+
+ existing_users = r > 0;
+ }
+ if (existing_users) {
+ log_info("Regular user already present in user database, skipping interactive user creation.");
return 0;
}
}
- return create_interactively();
+ RET_GATHER(ret, create_interactively());
+ return ret;
}
static int drop_from_identity(const char *field) {
@@ -5130,6 +5139,53 @@ static int verb_add_signing_key(int argc, char *argv[], void *userdata) {
return ret;
}
+static int add_signing_keys_from_credentials(void) {
+ int r;
+
+ _cleanup_close_ int fd = open_credentials_dir();
+ if (IN_SET(fd, -ENXIO, -ENOENT)) /* Credential env var not set, or dir doesn't exist. */
+ return 0;
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to open credentials directory: %m");
+
+ _cleanup_free_ DirectoryEntries *des = NULL;
+ r = readdir_all(fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate credentials: %m");
+
+ int ret = 0;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ FOREACH_ARRAY(i, des->entries, des->n_entries) {
+ struct dirent *de = *i;
+ if (de->d_type != DT_REG)
+ continue;
+
+ const char *e = startswith(de->d_name, "home.add-signing-key.");
+ if (!e)
+ continue;
+
+ if (!filename_is_valid(e))
+ continue;
+
+ if (!bus) {
+ r = acquire_bus(&bus);
+ if (r < 0)
+ return r;
+ }
+
+ _cleanup_fclose_ FILE *f = NULL;
+ r = xfopenat(fd, de->d_name, "re", O_NOFOLLOW, &f);
+ if (r < 0) {
+ RET_GATHER(ret, log_error_errno(r, "Failed to open credential '%s': %m", de->d_name));
+ continue;
+ }
+
+ RET_GATHER(ret, add_signing_key_one(bus, e, f));
+ }
+
+ return ret;
+}
+
static int remove_signing_key_one(sd_bus *bus, const char *fn) {
int r;