From: dongshengyuan <545258830@qq.com> Date: Thu, 16 Jul 2026 06:21:02 +0000 (+0800) Subject: sysusers: validate shell credentials X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=05b49871a28cd86bef636d6189ec8befb400026d;p=thirdparty%2Fsystemd.git sysusers: validate shell credentials Validate passwd.shell. credentials with the same login-shell rules used for sysusers.d shell fields before writing passwd entries. Reproducer: CREDENTIALS_DIRECTORY=... systemd-sysusers --root=... with --inline 'u creduser 999 "Cred User" / -' Before: relative-shell was written as the login shell and the command exited successfully. Follow-up: 99e9f896fb491d13c6d02f6f5bbfceabae833f05 --- diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 0970b76de23..8eb1ae13c59 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -468,6 +468,35 @@ static const char* pick_shell(const Item *i) { return NOLOGIN; } +static int read_shell_credential(const Item *i, char **ret) { + _cleanup_free_ char *cn = NULL, *shell = NULL; + int r; + + assert(i); + + cn = strjoin("passwd.shell.", i->name); + if (!cn) + return -ENOMEM; + + r = read_credential(cn, (void**) &shell, /* ret_size= */ NULL); + if (r < 0) { + log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn); + if (ret) + *ret = NULL; + return 0; + } + + path_simplify(shell); + if (!valid_shell(shell)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Shell credential '%s' specifies invalid login shell '%s'.", + cn, shell); + + if (ret) + *ret = TAKE_PTR(shell); + return 0; +} + static int write_temporary_passwd( Context *c, const char *passwd_path, @@ -488,6 +517,12 @@ static int write_temporary_passwd( goto done; if (arg_dry_run) { + ORDERED_HASHMAP_FOREACH(i, c->todo_uids) { + r = read_shell_credential(i, /* ret= */ NULL); + if (r < 0) + return r; + } + log_info("Would write /etc/passwd%s", glyph(GLYPH_ELLIPSIS)); goto done; } @@ -540,7 +575,7 @@ static int write_temporary_passwd( } ORDERED_HASHMAP_FOREACH(i, c->todo_uids) { - _cleanup_free_ char *creds_shell = NULL, *cn = NULL; + _cleanup_free_ char *creds_shell = NULL; struct passwd n = { .pw_name = i->name, @@ -559,15 +594,10 @@ static int write_temporary_passwd( .pw_shell = (char*) pick_shell(i), }; - /* 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); + r = read_shell_credential(i, &creds_shell); if (r < 0) - log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn); - else + return r; + if (creds_shell) n.pw_shell = creds_shell; r = putpwent_sane(&n, passwd); diff --git a/test/units/TEST-74-AUX-UTILS.sysusers.sh b/test/units/TEST-74-AUX-UTILS.sysusers.sh index 6e3fcac8c56..3322d337d8f 100755 --- a/test/units/TEST-74-AUX-UTILS.sysusers.sh +++ b/test/units/TEST-74-AUX-UTILS.sysusers.sh @@ -30,6 +30,15 @@ at_exit() { trap at_exit EXIT +root="$(mktemp -d)" +cred="$(mktemp -d)" +mkdir -p "$root/etc" +printf 'relative-shell' >"$cred/passwd.shell.creduser" +(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --dry-run --root="$root" --inline 'u creduser 999 "Cred User" / -') +(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --root="$root" --inline 'u creduser 999 "Cred User" / -') +(! grep -F creduser "$root/etc/passwd" >/dev/null 2>&1) +rm -rf "$root" "$cred" + # Ensure that a non-responsive NSS socket doesn't make sysusers fail mount -t tmpfs tmpfs /run/systemd/userdb/ touch /run/systemd/userdb/io.systemd.DynamicUser