create the user account first, and fix the sudoers filename bug that found
The user account section is now the first thing that acts, ahead of disk space.
The reason is a real defect, not tidiness. If the account does not exist yet,
USER_HOME is a path that is not there — and the ballast offers to put its file in
it, where ballast_create's `mkdir -p` runs as root and creates /home/<name> owned
by root:root. adduser afterwards finds the directory already present and does not
populate or chown it, so the account ends up with a home it cannot write to.
Making the account before any step can write into its home removes the ordering
entirely.
USER_HOME is re-read from getent after adduser runs. Until that point it is the
/home/<name> guess, because there is nothing to look up; adduser is free to have
used something else and every later step writes there.
Found while testing that, and worse than the thing it was testing:
local user="$1" dest="/etc/sudoers.d/99-${user}-nopasswd"
bash expands ${user} before the assignment to user has happened, so dest came out
as /etc/sudoers.d/99--nopasswd with the name missing. The rule inside was correct,
which is what made it invisible — visudo passes, sudo works, and the account
really does get passwordless sudo. What breaks is everything around it: every
account granted this way writes to that same file, so a second grant silently
overwrites the first and revokes it; and has_passwordless_sudo looks for
99-<user>-nopasswd, never finds it, and re-grants on every run forever.
Split into separate declarations, with the reason recorded where it happened, and
an empty username is now refused outright. Scanned the other lib files for the
same shape — the remaining multi-assignment locals only read positional
parameters, which is safe.
The stray /etc/sudoers.d/99--nopasswd this created on the dev box during testing
has been removed and visudo -c re-verified.
Verified with a real throwaway account: correctly reports not-granted before,
writes 99-msdemo-nopasswd as root:root 0440 with the right rule, reports granted
after, and leaves sudoers valid.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -285,9 +285,18 @@ as_user() {
|
||||
# places it with its mode in a single install(1) — so what lands in /etc is
|
||||
# already known good and already 0440.
|
||||
grant_passwordless_sudo() {
|
||||
local user="$1" dest="/etc/sudoers.d/99-${user}-nopasswd" tmp
|
||||
# Declared separately, deliberately. In `local a="$1" b="${a}"` bash expands
|
||||
# $a before it has been assigned, so b comes out with the name missing — which
|
||||
# here meant every account's rule landing in the same /etc/sudoers.d/99--nopasswd,
|
||||
# each one silently overwriting the last, and has_passwordless_sudo never
|
||||
# finding the file it was looking for.
|
||||
local user="$1"
|
||||
local dest="/etc/sudoers.d/99-${user}-nopasswd"
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
|
||||
[[ -n "$user" ]] || fail "grant_passwordless_sudo needs a username"
|
||||
|
||||
echo "${user} ALL=(ALL) NOPASSWD: ALL" >"$tmp"
|
||||
|
||||
if ! visudo -c -f "$tmp" >/dev/null 2>&1; then
|
||||
|
||||
Reference in New Issue
Block a user