|
|
|
@@ -188,6 +188,77 @@ sshd_disable_keygen() {
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
# Alpine keeps PAM support in a SEPARATE binary.
|
|
|
|
|
#
|
|
|
|
|
# openssh-server -> /usr/sbin/sshd (built WITHOUT PAM)
|
|
|
|
|
# openssh-server-pam -> /usr/sbin/sshd.pam (built WITH PAM)
|
|
|
|
|
#
|
|
|
|
|
# The OpenRC init picks between them in start_pre (checkconfig -> update_command:
|
|
|
|
|
# "sshd.pam if it is executable and the config says UsePAM yes"), and its
|
|
|
|
|
# reload/stop match the running process with `start-stop-daemon --exec "$command"`.
|
|
|
|
|
# So a host that is ALREADY running /usr/sbin/sshd never swaps over on its own:
|
|
|
|
|
# reload signals a process that doesn't match (nothing happens), stop matches
|
|
|
|
|
# nothing, and a follow-up start hits "address already in use". The daemon keeps
|
|
|
|
|
# serving without PAM -- which means /etc/pam.d/sshd, and therefore the pam_exec
|
|
|
|
|
# login notifier, is silently never consulted. Every other distro builds PAM into
|
|
|
|
|
# the one sshd binary, so this is Alpine-only.
|
|
|
|
|
# ----------------------------------------------------------------------------
|
|
|
|
|
sshd_wanted_binary() { # echo the sshd binary this host's config should be running
|
|
|
|
|
_require_detected
|
|
|
|
|
if [[ "$OS_FAMILY" == alpine ]] && [[ -x /usr/sbin/sshd.pam ]] && grep -qiE '^[[:space:]]*UsePAM[[:space:]]+yes' /etc/ssh/sshd_config 2>/dev/null; then
|
|
|
|
|
echo /usr/sbin/sshd.pam
|
|
|
|
|
else
|
|
|
|
|
echo /usr/sbin/sshd
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sshd_running_binary() { # echo the executable behind the running sshd master ('' if unknown)
|
|
|
|
|
local pid="" p
|
|
|
|
|
if [[ -r /run/sshd.pid ]]; then pid="$(cat /run/sshd.pid 2>/dev/null || true)"; fi
|
|
|
|
|
if [[ -z "$pid" ]]; then
|
|
|
|
|
for p in sshd.pam sshd; do
|
|
|
|
|
pid="$(pgrep -x "$p" 2>/dev/null | head -n1 || true)"
|
|
|
|
|
[[ -n "$pid" ]] && break
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
[[ -n "$pid" ]] || return 0
|
|
|
|
|
readlink -f "/proc/$pid/exe" 2>/dev/null || true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Apply a freshly written sshd_config. Normally a reload (keeps connections).
|
|
|
|
|
# On Alpine, when the running binary is not the one the config calls for, the
|
|
|
|
|
# service is stopped by pidfile and started again so the PAM build takes over --
|
|
|
|
|
# established sessions are separate processes and survive; only the listener
|
|
|
|
|
# blinks.
|
|
|
|
|
sshd_apply_config() {
|
|
|
|
|
_require_detected
|
|
|
|
|
local svc; svc="$(sshd_service)"
|
|
|
|
|
if [[ "$OS_FAMILY" == alpine ]]; then
|
|
|
|
|
local want run pid i
|
|
|
|
|
want="$(sshd_wanted_binary)"
|
|
|
|
|
run="$(sshd_running_binary)"
|
|
|
|
|
if [[ -n "$run" && "$run" != "$want" ]]; then
|
|
|
|
|
_warn "sshd is running $run, but this config needs $want -- restarting to swap it in."
|
|
|
|
|
_warn "(Existing SSH sessions survive; the listener is down for about a second.)"
|
|
|
|
|
pid=""
|
|
|
|
|
if [[ -r /run/sshd.pid ]]; then pid="$(cat /run/sshd.pid 2>/dev/null || true)"; fi
|
|
|
|
|
rc-service "$svc" stop >/dev/null 2>&1 || true
|
|
|
|
|
if [[ -n "$pid" ]]; then
|
|
|
|
|
kill "$pid" 2>/dev/null || true
|
|
|
|
|
i=0
|
|
|
|
|
while kill -0 "$pid" 2>/dev/null && [[ "$i" -lt 10 ]]; do sleep 1; i=$((i + 1)); done
|
|
|
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
|
|
|
fi
|
|
|
|
|
rm -f /run/sshd.pid
|
|
|
|
|
svc_start "$svc" || _die "sshd failed to start as $want. Check: rc-service $svc start"
|
|
|
|
|
_log "sshd restarted as $(sshd_running_binary)."
|
|
|
|
|
return 0
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
svc_reload "$svc"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
|
|
|
|
# Users & groups (busybox adduser/addgroup vs shadow useradd/groupadd)
|
|
|
|
|
# ============================================================================
|
|
|
|
@@ -286,6 +357,7 @@ install_boot_hook() { # install_boot_hook <name> <path-to-script>
|
|
|
|
|
rc-update add local default >/dev/null 2>&1 || true
|
|
|
|
|
"/etc/local.d/${name}.start" || true ;;
|
|
|
|
|
systemd)
|
|
|
|
|
install -d -m 0755 /usr/local/sbin
|
|
|
|
|
install -m 0755 "$src" "/usr/local/sbin/${name}"
|
|
|
|
|
cat > "/etc/systemd/system/${name}.service" <<UNIT
|
|
|
|
|
[Unit]
|
|
|
|
@@ -316,6 +388,8 @@ install_daily_job() { # install_daily_job <name> <script-src> [run-args...]
|
|
|
|
|
local args="$*"
|
|
|
|
|
# The job scripts use bash; ensure it's present (Alpine images often lack it).
|
|
|
|
|
command -v bash >/dev/null 2>&1 || pkg_install bash || true
|
|
|
|
|
# Alpine's baselayout ships /usr/local/{bin,lib,share} but NOT sbin.
|
|
|
|
|
install -d -m 0755 /usr/local/sbin
|
|
|
|
|
install -m 0755 "$src" "/usr/local/sbin/$name"
|
|
|
|
|
# Co-install oslib.sh so a script that sources it still works standalone.
|
|
|
|
|
local srcdir; srcdir="$(dirname "$src")"
|
|
|
|
@@ -587,6 +661,17 @@ CONF
|
|
|
|
|
# Verify the hook actually landed and report loudly. A notifier that fails to
|
|
|
|
|
# install silently is worse than none -- you'd believe logins are watched
|
|
|
|
|
# when they aren't (exactly the trap that hid this on the first Alma run).
|
|
|
|
|
# "Wired into /etc/pam.d/sshd" is not the same as "will fire": on Alpine the
|
|
|
|
|
# PAM stack is only read when sshd IS the PAM build (see sshd_wanted_binary).
|
|
|
|
|
# Check that too, or we'd report ACTIVE for a hook that can never run.
|
|
|
|
|
if [[ "${OS_FAMILY:-}" == alpine ]]; then
|
|
|
|
|
if [[ ! -x /usr/sbin/sshd.pam ]]; then
|
|
|
|
|
_warn "Alpine: /usr/sbin/sshd.pam is missing, so /etc/pam.d/sshd is never read and this notifier cannot fire."
|
|
|
|
|
_warn " Fix: apk add openssh-server-pam && rc-service $(sshd_service) restart"
|
|
|
|
|
elif ! grep -qiE '^[[:space:]]*UsePAM[[:space:]]+yes' /etc/ssh/sshd_config 2>/dev/null; then
|
|
|
|
|
_warn "Alpine: sshd_config lacks 'UsePAM yes', so the PAM build is never selected and this notifier cannot fire."
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
if [[ -x /opt/scripts/ntfy-ssh-login.sh ]] \
|
|
|
|
|
&& grep -qF '/opt/scripts/ntfy-ssh-login.sh' "$pam" 2>/dev/null; then
|
|
|
|
|
_log "Login notifier ACTIVE -> ${NTFY_URL:-<NTFY_URL unset!>}"
|
|
|
|
|