sysusers: validate shell credentials
Validate passwd.shell.<user> 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: 99e9f896fb
This commit is contained in:
+39
-9
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user