#!/bin/bash # ============================================================================= # passwordless-sudo.sh — toggle temporary NOPASSWD sudo for the current user # ============================================================================= # Some workflows (unattended VM builds, agent-driven scripting sessions) need # to run a string of `sudo` commands with nothing around to answer a password # prompt. This drops a single sudoers.d file granting the invoking user full # NOPASSWD sudo, and removes it again just as easily. # # This is a deliberate, temporary reduction in local security — anything # running as your user can become root without a password while it's active. # Turn it off (`disable`) as soon as whatever needed it is done. It does NOT # persist across the dotfiles install/update flow — it's a manual toggle you # reach for and put back, not a permanent config. # # Usage: # passwordless-sudo.sh enable [--yes] Grant NOPASSWD sudo to $USER # passwordless-sudo.sh disable Revoke it # passwordless-sudo.sh status Report whether it's currently active # # The drop-in is validated with `visudo -c` before being installed, so a typo # here can't corrupt sudo for the whole system. # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # lib/logging.sh lives at setup/modules/lib/, two levels up from setup/tools/. source "$SCRIPT_DIR/../modules/lib/logging.sh" TARGET_USER="$(id -un)" SUDOERS_FILE="/etc/sudoers.d/90-${TARGET_USER}-temp-nopasswd" usage() { printf 'Usage: %s {enable|disable|status} [--yes]\n' "$(basename "$0")" >&2 exit 1 } [[ $# -ge 1 ]] || usage ACTION="$1"; shift || true ASSUME_YES=0 for arg in "$@"; do case "$arg" in -y|--yes) ASSUME_YES=1 ;; *) usage ;; esac done is_enabled() { [[ -f "$SUDOERS_FILE" ]]; } cmd_status() { if is_enabled; then log "Passwordless sudo is ENABLED for $TARGET_USER ($SUDOERS_FILE)" else skip "Passwordless sudo is disabled for $TARGET_USER" fi } cmd_enable() { if is_enabled; then skip "Already enabled — nothing to do." return 0 fi warn "This grants $TARGET_USER full root access with NO password prompt," warn "system-wide, until you run: $(basename "$0") disable" if [[ $ASSUME_YES -ne 1 ]]; then read -rp "Proceed? [y/N] " _ans [[ "${_ans,,}" == "y" ]] || { skip "Aborted."; exit 0; } fi local tmp tmp="$(mktemp)" printf '%s ALL=(ALL) NOPASSWD: ALL\n' "$TARGET_USER" > "$tmp" # Validate the drop-in in isolation before it ever touches /etc/sudoers.d — # visudo -c checks syntax without requiring the file to be in place first. if ! sudo visudo -c -f "$tmp" >/dev/null; then err "Generated sudoers snippet failed validation — not installing it." rm -f "$tmp" exit 1 fi sudo install -m 0440 -o root -g root "$tmp" "$SUDOERS_FILE" rm -f "$tmp" log "Passwordless sudo enabled for $TARGET_USER." warn "Remember to run: $(basename "$0") disable" } cmd_disable() { if ! is_enabled; then skip "Already disabled — nothing to do." return 0 fi sudo rm -f "$SUDOERS_FILE" log "Passwordless sudo disabled for $TARGET_USER." } case "$ACTION" in enable) cmd_enable ;; disable) cmd_disable ;; status) cmd_status ;; *) usage ;; esac