1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-11 05:17:44 +03:00

sysusers: allow defining additional sysusers lines via credentials

This commit is contained in:
Lennart Poettering 2022-07-13 11:06:04 +02:00 committed by Yu Watanabe
parent 69a7d10832
commit 3acb6edef3
6 changed files with 61 additions and 24 deletions

View File

@ -86,10 +86,10 @@
<term><literal>sysctl.extra</literal></term> <term><literal>sysctl.extra</literal></term>
<listitem><para>The contents of this credential may contain additional lines to operate on. The <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> credential contents should follow the same format as any other <filename>sysctl.d/</filename> drop-in
drop-in. If this credential is passed it is processed after all of the drop-in files read from the configuration file. If this credential is passed it is processed after all of the drop-in files read
file system. The settings configured in the credential hence take precedence over those in the file from the file system. The settings configured in the credential hence take precedence over those in
system.</para></listitem> the file system.</para></listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -169,18 +169,27 @@
<listitem><para>Specifies the shell binary to use for the specified account when creating it.</para></listitem> <listitem><para>Specifies the shell binary to use for the specified account when creating it.</para></listitem>
</varlistentry> </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> </variablelist>
<para>Note that by default the <filename>systemd-sysusers.service</filename> unit file is set up to <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>, inherit the <literal>passwd.hashed-password.root</literal>,
<literal>passwd.plaintext-password.root</literal> and <literal>passwd.shell.root</literal> credentials <literal>passwd.plaintext-password.root</literal>, <literal>passwd.shell.root</literal> and
from the service manager. Thus, when invoking a container with an unpopulated <filename>/etc/</filename> <literal>sysusers.extra</literal> credentials from the service manager. Thus, when invoking a container
for the first time it is possible to configure the root user's password to be <literal>systemd</literal> with an unpopulated <filename>/etc/</filename> for the first time it is possible to configure the root
like this:</para> 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><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 for the first time, it may not be used for changing the password or shell of an account that already
exists.</para> exists.</para>

View File

@ -1981,7 +1981,7 @@ static int parse_arguments(char **args) {
/* Use (argument):n, where n==1 for the first positional arg */ /* Use (argument):n, where n==1 for the first positional arg */
r = parse_line("(argument)", pos, *arg); r = parse_line("(argument)", pos, *arg);
else else
r = read_config_file(*arg, false); r = read_config_file(*arg, /* ignore_enoent= */ false);
if (r < 0) if (r < 0)
return r; 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)); log_debug("Reading config file \"%s\"%s", *f, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
/* Just warn, ignore result otherwise */ /* Just warn, ignore result otherwise */
(void) read_config_file(*f, true); (void) read_config_file(*f, /* ignore_enoent= */ true);
} }
return 0; 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[]) { static int run(int argc, char *argv[]) {
#ifndef STANDALONE #ifndef STANDALONE
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL; _cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
@ -2068,12 +2087,10 @@ static int run(int argc, char *argv[]) {
assert(!arg_image); assert(!arg_image);
#endif #endif
/* If command line arguments are specified along with --replace, read all /* If command line arguments are specified along with --replace, read all configuration files and
* configuration files and insert the positional arguments at the specified * insert the positional arguments at the specified place. Otherwise, if command line arguments are
* place. Otherwise, if command line arguments are specified, execute just * specified, execute just them, and finally, without --replace= or any positional arguments, just
* them, and finally, without --replace= or any positional arguments, just * read configuration and execute it. */
* read configuration and execute it.
*/
if (arg_replace || optind >= argc) if (arg_replace || optind >= argc)
r = read_config_files(argv + optind); r = read_config_files(argv + optind);
else else
@ -2081,11 +2098,15 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
return r; return r;
/* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection r = read_credential_lines();
* whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though if (r < 0)
* nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the return r;
* synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated
* /etc. */ /* 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) if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0)
return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m"); return log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m");

View File

@ -4,7 +4,7 @@ set -e
TEST_DESCRIPTION="test credentials" TEST_DESCRIPTION="test credentials"
NSPAWN_ARGUMENTS="${NSPAWN_ARGUMENTS:-} --set-credential=mynspawncredential:strangevalue" 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" 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 # shellcheck source=test/test-functions

View File

@ -40,6 +40,9 @@ elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then
# Verify that writing a sysctl via the kernel cmdline worked # Verify that writing a sysctl via the kernel cmdline worked
[ "$(cat /proc/sys/kernel/domainname)" = "sysctltest" ] [ "$(cat /proc/sys/kernel/domainname)" = "sysctltest" ]
# Verify that creating a user via sysusers via the kernel cmdline worked
grep -q ^credtestuser: /etc/passwd
else else
echo "qemu_fw_cfg support missing in kernel. Sniff!" echo "qemu_fw_cfg support missing in kernel. Sniff!"
expected_credential="" expected_credential=""

View File

@ -14,7 +14,8 @@ DefaultDependencies=no
Conflicts=shutdown.target Conflicts=shutdown.target
After=systemd-remount-fs.service After=systemd-remount-fs.service
Before=sysinit.target shutdown.target systemd-update-done.service Before=sysinit.target shutdown.target systemd-update-done.service
ConditionNeedsUpdate=/etc ConditionNeedsUpdate=|/etc
ConditionCredential=|sysusers.extra
[Service] [Service]
Type=oneshot Type=oneshot
@ -28,3 +29,6 @@ TimeoutSec=90s
LoadCredential=passwd.hashed-password.root LoadCredential=passwd.hashed-password.root
LoadCredential=passwd.plaintext-password.root LoadCredential=passwd.plaintext-password.root
LoadCredential=passwd.shell.root LoadCredential=passwd.shell.root
# Also, allow configuring extra sysusers lines via a credential
LoadCredential=sysusers.extra