From 283a81e1bb56c0326bb690dfe664061c445f8fd7 Mon Sep 17 00:00:00 2001 From: Preston Hunt Date: Fri, 28 Aug 2026 12:23:44 -0700 Subject: [PATCH] sudo: install validated drop-ins instead of editing /etc/sudoers Two functions edited /etc/sudoers in place with no validation: enable_sudo_without_password ran 'sed -i.bak' against the %sudo line, and pass_http_thru_sudo appended an env_keep Defaults line via 'sudo tee -a'. A syntax error introduced by either -- a sed pattern that matches unexpectedly on a future Ubuntu, a partially written append -- makes sudo refuse to run at all, and the .bak is then only recoverable from a root shell or recovery boot. Write both rules to /etc/sudoers.d/ instead, via a helper that: - confirms /etc/sudoers actually has an includedir directive - runs 'visudo -cf' on the candidate file and aborts if it fails - installs with 'install -m 0440 -o root -g root', which is atomic This is also idempotent by construction, replacing the grep-based guards. Verified both generated snippets parse with visudo -cf. Machines provisioned by an earlier version keep the inline edits in /etc/sudoers; the drop-ins are equivalent, so those lines can be removed by hand with visudo. Co-Authored-By: Claude Opus 5 (1M context) --- setup | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/setup b/setup index df939ed..bc2ba7f 100755 --- a/setup +++ b/setup @@ -177,11 +177,35 @@ install_pscripts() { done } -enable_sudo_without_password() { - if ! sudo grep -q NOPASSWD /etc/sudoers; then - : Allow sudo without password - sudo sed -E -i.bak 's|^(%sudo.+ALL:ALL\)) (ALL)|\1 NOPASSWD:SETENV: \2|' /etc/sudoers +_install_sudoers_snippet() { + : "_install_sudoers_snippet ... -- validates before installing" + local name=$1 tmp + shift + + if ! sudo grep -qE '^[@#]includedir[[:space:]]+/etc/sudoers.d' /etc/sudoers; then + die "/etc/sudoers does not include /etc/sudoers.d; refusing to edit sudoers" + fi + + tmp=$(mktemp) + printf '%s\n' "$@" >"$tmp" + + # Never install a sudoers file we have not parsed: a syntax error in + # /etc/sudoers.d locks the machine out of sudo entirely. + if ! sudo visudo -cf "$tmp" >/dev/null; then + rm -f "$tmp" + die "generated sudoers snippet '$name' is invalid; not installing" fi + + sudo install -o root -g root -m 0440 "$tmp" "/etc/sudoers.d/$name" + rm -f "$tmp" +} + +enable_sudo_without_password() { + : Allow sudo without password + # SETENV is required for the "sudo -E" calls elsewhere in this script + _install_sudoers_snippet prestobuntu-nopasswd \ + '# Managed by prestobuntu' \ + '%sudo ALL=(ALL:ALL) NOPASSWD:SETENV: ALL' } remove_sudo_warning() { @@ -189,7 +213,9 @@ remove_sudo_warning() { } pass_http_thru_sudo() { - _require_line 'Defaults:%sudo env_keep += "http_proxy https_proxy"' /etc/sudoers + _install_sudoers_snippet prestobuntu-proxy \ + '# Managed by prestobuntu' \ + 'Defaults:%sudo env_keep += "http_proxy https_proxy"' } setup_ssh() {