]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sysusers: allow defining additional sysusers lines via credentials
authorLennart Poettering <lennart@poettering.net>
Wed, 13 Jul 2022 09:06:04 +0000 (11:06 +0200)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 15 Jul 2022 15:47:22 +0000 (00:47 +0900)
man/systemd-sysctl.service.xml
man/systemd-sysusers.xml
src/sysusers/sysusers.c
test/TEST-54-CREDS/test.sh
test/units/testsuite-54.sh
units/systemd-sysusers.service

index 2313d4c44d09348d66961dc8388071accddf9bfd..312bc3ba43f43f7e24146aa5b79c4a708e05b702 100644 (file)
         <term><literal>sysctl.extra</literal></term>
 
         <listitem><para>The contents of this credential may contain additional lines to operate on. The
-        credential contents should follow the same format as any other <filename>sysctl.d/</filename>
-        drop-in. If this credential is passed it is processed after all of the drop-in files read from the
-        file system. The settings configured in the credential hence take precedence over those in the file
-        system.</para></listitem>
+        credential contents should follow the same format as any other <filename>sysctl.d/</filename> drop-in
+        configuration file. If this credential is passed it is processed after all of the drop-in files read
+        from the file system. The settings configured in the credential hence take precedence over those in
+        the file system.</para></listitem>
       </varlistentry>
     </variablelist>
 
index 7da7b18dcf95fac696693036c8c36cf24528f0e0..9011cdb7552f1bc3e78b74b78031d5c6c8112965 100644 (file)
 
         <listitem><para>Specifies the shell binary to use for the specified account when creating it.</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><literal>sysusers.extra</literal></term>
+
+        <listitem><para>The contents of this credential may contain additional lines to operate on. The
+        credential contents should follow the same format as any other <filename>sysusers.d/</filename>
+        drop-in. If this credential is passed it is processed after all of the drop-in files read from the
+        file system.</para></listitem>
+      </varlistentry>
     </variablelist>
 
     <para>Note that by default the <filename>systemd-sysusers.service</filename> unit file is set up to
     inherit the <literal>passwd.hashed-password.root</literal>,
-    <literal>passwd.plaintext-password.root</literal> and <literal>passwd.shell.root</literal> credentials
-    from the service manager. Thus, when invoking a container with an unpopulated <filename>/etc/</filename>
-    for the first time it is possible to configure the root user's password to be <literal>systemd</literal>
-    like this:</para>
+    <literal>passwd.plaintext-password.root</literal>, <literal>passwd.shell.root</literal> and
+    <literal>sysusers.extra</literal> credentials from the service manager. Thus, when invoking a container
+    with an unpopulated <filename>/etc/</filename> for the first time it is possible to configure the root
+    user's password to be <literal>systemd</literal> like this:</para>
 
     <para><programlisting># systemd-nspawn --image=… --set-credential=passwd.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' …</programlisting></para>
 
-    <para>Note again that the data specified in these credentials is consulted only when creating an account
+    <para>Note again that the data specified in this credential is consulted only when creating an account
     for the first time, it may not be used for changing the password or shell of an account that already
     exists.</para>
 
index c60dee812f0d0f7b3d23ca577b16e18f17154498..aba08a7563b5823b6883c1380d200bbc669933bc 100644 (file)
@@ -1981,7 +1981,7 @@ static int parse_arguments(char **args) {
                         /* Use (argument):n, where n==1 for the first positional arg */
                         r = parse_line("(argument)", pos, *arg);
                 else
-                        r = read_config_file(*arg, false);
+                        r = read_config_file(*arg, /* ignore_enoent= */ false);
                 if (r < 0)
                         return r;
 
@@ -2011,12 +2011,31 @@ static int read_config_files(char **args) {
                         log_debug("Reading config file \"%s\"%s", *f, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
 
                         /* Just warn, ignore result otherwise */
-                        (void) read_config_file(*f, true);
+                        (void) read_config_file(*f, /* ignore_enoent= */ true);
                 }
 
         return 0;
 }
 
+static int read_credential_lines(void) {
+        _cleanup_free_ char *j = NULL;
+        const char *d;
+        int r;
+
+        r = get_credentials_dir(&d);
+        if (r == -ENXIO)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to get credentials directory: %m");
+
+        j = path_join(d, "sysusers.extra");
+        if (!j)
+                return log_oom();
+
+        (void) read_config_file(j, /* ignore_enoent= */ true);
+        return 0;
+}
+
 static int run(int argc, char *argv[]) {
 #ifndef STANDALONE
         _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
@@ -2068,12 +2087,10 @@ static int run(int argc, char *argv[]) {
         assert(!arg_image);
 #endif
 
-        /* If command line arguments are specified along with --replace, read all
-         * configuration files and insert the positional arguments at the specified
-         * place. Otherwise, if command line arguments are specified, execute just
-         * them, and finally, without --replace= or any positional arguments, just
-         * read configuration and execute it.
-         */
+        /* If command line arguments are specified along with --replace, read all configuration files and
+         * insert the positional arguments at the specified place. Otherwise, if command line arguments are
+         * specified, execute just them, and finally, without --replace= or any positional arguments, just
+         * read configuration and execute it. */
         if (arg_replace || optind >= argc)
                 r = read_config_files(argv + optind);
         else
@@ -2081,11 +2098,15 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
-        /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection
-         * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though
-         * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the
-         * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated
-         * /etc. */
+        r = read_credential_lines();
+        if (r < 0)
+                return r;
+
+        /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our
+         * detection whether the names or UID/GID area already used otherwise doesn't get confused. After
+         * all, even though nss-systemd synthesizes these users/groups, they should still appear in
+         * /etc/passwd and /etc/group, as the synthesizing logic is merely supposed to be fallback for cases
+         * where we run with a completely unpopulated /etc. */
         if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0)
                 return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m");
 
index 7bbc94ebc02f1c4b32278b21ea4c29f85414519d..8f66f1c7b841ec3549c05dd9dbd56d263006df2d 100755 (executable)
@@ -4,7 +4,7 @@ set -e
 
 TEST_DESCRIPTION="test credentials"
 NSPAWN_ARGUMENTS="${NSPAWN_ARGUMENTS:-} --set-credential=mynspawncredential:strangevalue"
-QEMU_OPTIONS="${QEMU_OPTIONS:-} -fw_cfg name=opt/io.systemd.credentials/myqemucredential,string=othervalue -smbios type=11,value=io.systemd.credential:smbioscredential=magicdata -smbios type=11,value=io.systemd.credential.binary:binarysmbioscredential=bWFnaWNiaW5hcnlkYXRh"
+QEMU_OPTIONS="${QEMU_OPTIONS:-} -fw_cfg name=opt/io.systemd.credentials/myqemucredential,string=othervalue -smbios type=11,value=io.systemd.credential:smbioscredential=magicdata -smbios type=11,value=io.systemd.credential.binary:binarysmbioscredential=bWFnaWNiaW5hcnlkYXRh -smbios type=11,value=io.systemd.credential.binary:sysusers.extra=dSBjcmVkdGVzdHVzZXIK"
 KERNEL_APPEND="${KERNEL_APPEND:-} systemd.set_credential=kernelcmdlinecred:uff systemd.set_credential=sysctl.extra:kernel.domainname=sysctltest rd.systemd.import_credentials=no"
 
 # shellcheck source=test/test-functions
index 771b041bf1de400bdc2a5e90c25df2c8278d1d0d..a7ccdca032f50e075c6ce9c444627468e613c56a 100755 (executable)
@@ -40,6 +40,9 @@ elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then
 
     # Verify that writing a sysctl via the kernel cmdline worked
     [ "$(cat /proc/sys/kernel/domainname)" = "sysctltest" ]
+
+    # Verify that creating a user via sysusers via the kernel cmdline worked
+    grep -q ^credtestuser: /etc/passwd
 else
     echo "qemu_fw_cfg support missing in kernel. Sniff!"
     expected_credential=""
index 47373307b32a527bf9cb0caf9232afe11c3a4938..91132dafa98d8d24f64f55f7215dbc086027fe85 100644 (file)
@@ -14,7 +14,8 @@ DefaultDependencies=no
 Conflicts=shutdown.target
 After=systemd-remount-fs.service
 Before=sysinit.target shutdown.target systemd-update-done.service
-ConditionNeedsUpdate=/etc
+ConditionNeedsUpdate=|/etc
+ConditionCredential=|sysusers.extra
 
 [Service]
 Type=oneshot
@@ -28,3 +29,6 @@ TimeoutSec=90s
 LoadCredential=passwd.hashed-password.root
 LoadCredential=passwd.plaintext-password.root
 LoadCredential=passwd.shell.root
+
+# Also, allow configuring extra sysusers lines via a credential
+LoadCredential=sysusers.extra