]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homectl: also import signing keys at firstboot time
authorLennart Poettering <lennart@poettering.net>
Wed, 19 Feb 2025 21:53:21 +0000 (22:53 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 Mar 2025 17:14:09 +0000 (18:14 +0100)
man/systemd.system-credentials.xml
src/home/homectl.c

index aa974837cded4b54872823ff7b5c2d286c017137..1dd7f8aee68821db36bfa24a9987b2dcb9fb4592 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>home.add-signing-key.*</varname></term>
+        <listitem>
+          <para>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 <command>homectl get-signing-key</command>. 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 <filename>.public</filename> suffix). For details see
+          <citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>home.create.*</varname></term>
         <listitem>
index 6857acbcc676c54118c054cd2ab7a08a2dadff2a..66f3f773f6460cea6b24a434a8b114bbb7108488 100644 (file)
@@ -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;