Fix: Complete SSH hardening recovery

This commit is contained in:
Gabriel Brown
2026-08-27 04:06:54 -04:00
parent d267da58ad
commit 51e2c8418a
2 changed files with 300 additions and 27 deletions
+45 -12
View File
@@ -84,15 +84,15 @@ restore_ssh_dropin() {
if [[ -n "${ssh_backup:-}" && -e "$ssh_backup" ]]; then
restore="$(mktemp --tmpdir="$sshd_dir" .90-panama.XXXXXX.restore)" || return 1
if ! cp -a -- "$ssh_backup" "$restore"; then
rm -f -- "$restore"
remove_ssh_artifact "$restore" || true
return 1
fi
if ! mv -f -- "$restore" "$ssh_dropin"; then
rm -f -- "$restore"
remove_ssh_artifact "$restore" || true
return 1
fi
else
rm -f -- "$ssh_dropin"
remove_ssh_artifact "$ssh_dropin"
fi
}
@@ -104,6 +104,37 @@ restore_ssh_transaction_traps() {
return 0
}
remove_ssh_artifact() {
local artifact="$1"
[[ -n "$artifact" && -e "$artifact" ]] || return 0
if rm -f -- "$artifact"; then
return 0
fi
printf 'SSH transaction cleanup failed. Retained artifact: %s\n' "$artifact" >&2
printf ' rm -f -- %q\n' "$artifact" >&2
return 1
}
handle_ssh_transaction_signal() {
local signal_status="$1"
trap - INT TERM
rollback_failed=0
restore_ssh_dropin || rollback_failed=1
sshd -t || rollback_failed=1
systemctl reload "$ssh_unit" || rollback_failed=1
ssh_transaction_active=0
restore_ssh_transaction_traps
if (( rollback_failed )); then
printf 'SSH rollback needs manual recovery. Backup: %s\n' "$ssh_backup" >&2
printf ' cp -a -- %q %q\n' "$ssh_backup" "$ssh_dropin" >&2
printf ' sshd -t\n' >&2
printf ' systemctl reload %s\n' "$ssh_unit" >&2
else
remove_ssh_artifact "$ssh_backup" || true
fi
exit "$signal_status"
}
harden_server_ssh() {
local username="$1" user_home="$2" sshd_dir ssh_dropin harden ssh_unit
local ssh_candidate="" ssh_backup="" rollback_failed=0
@@ -125,17 +156,18 @@ harden_server_ssh() {
ssh_candidate="$(umask 077; mktemp --tmpdir="$sshd_dir" .90-panama.XXXXXX.tmp)" || return 1
if ! printf 'PermitRootLogin no\nPasswordAuthentication no\n' >"$ssh_candidate"; then
rm -f -- "$ssh_candidate"
remove_ssh_artifact "$ssh_candidate" || true
return 1
fi
if [[ -e "$ssh_dropin" ]]; then
ssh_backup="$(umask 077; mktemp --tmpdir="$sshd_dir" .90-panama.XXXXXX.backup)" || {
rm -f -- "$ssh_candidate"
remove_ssh_artifact "$ssh_candidate" || true
return 1
}
if ! cat -- "$ssh_dropin" >"$ssh_backup"; then
rm -f -- "$ssh_candidate" "$ssh_backup"
remove_ssh_artifact "$ssh_candidate" || true
remove_ssh_artifact "$ssh_backup" || true
return 1
fi
fi
@@ -144,14 +176,15 @@ harden_server_ssh() {
ssh_saved_int_trap="$(trap -p INT)"
ssh_saved_term_trap="$(trap -p TERM)"
trap 'if [[ "${ssh_transaction_active:-0}" == 1 ]]; then restore_ssh_dropin || true; fi' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
trap 'handle_ssh_transaction_signal 130' INT
trap 'handle_ssh_transaction_signal 143' TERM
ssh_transaction_active=1
if ! mv -f -- "$ssh_candidate" "$ssh_dropin"; then
ssh_transaction_active=0
restore_ssh_transaction_traps
rm -f -- "$ssh_candidate" "$ssh_backup"
remove_ssh_artifact "$ssh_candidate" || true
remove_ssh_artifact "$ssh_backup" || true
return 1
fi
ssh_candidate=""
@@ -167,7 +200,7 @@ harden_server_ssh() {
printf ' sshd -t\n' >&2
printf ' systemctl reload %s\n' "$ssh_unit" >&2
else
[[ -z "$ssh_backup" ]] || rm -f -- "$ssh_backup"
remove_ssh_artifact "$ssh_backup" || true
fi
return 1
fi
@@ -184,14 +217,14 @@ harden_server_ssh() {
printf ' sshd -t\n' >&2
printf ' systemctl reload %s\n' "$ssh_unit" >&2
else
[[ -z "$ssh_backup" ]] || rm -f -- "$ssh_backup"
remove_ssh_artifact "$ssh_backup" || true
fi
return 1
fi
ssh_transaction_active=0
restore_ssh_transaction_traps
[[ -z "$ssh_backup" ]] || rm -f -- "$ssh_backup"
remove_ssh_artifact "$ssh_backup" || return 1
echo "Wrote $ssh_dropin; make sure your key works before logging out."
}