Files
ssh-jumphost/scripts/rdp_selftest.sh
2026-09-03 12:30:26 +02:00

120 lines
5.4 KiB
Bash

#!/usr/bin/env bash
#
# rdp_selftest.sh -- erhebt in EINEM Durchlauf den vollstaendigen Zustand der
# RDP-Strecke und sagt am Ende, welche Voraussetzung fehlt.
#
# Entstanden, weil die Fehlersuche am 2./3.9. zweimal im Kreis lief: es wurde
# jeweils EIN Logausschnitt betrachtet und daraus geschlossen, ohne zu pruefen,
# ob die zuvor eingebaute Massnahme im laufenden Prozess ueberhaupt angekommen
# ist. Genau das prueft dieses Skript -- nicht die Konfigurationsdateien,
# sondern den TATSAECHLICHEN Zustand des laufenden guacd (/proc/<pid>/environ
# und /proc/<pid>/maps).
#
# Als root auf dem Jumphost ausfuehren: bash scripts/rdp_selftest.sh [ZIEL-IP]
set -uo pipefail
ZIEL="${1:-}"
SHIM="/usr/local/lib/jumphost/guacd-tls-seclevel-shim.so"
FEHLER=()
titel() { printf '\n== %s ==\n' "$1"; }
ok() { printf ' [ok] %s\n' "$1"; }
warn() { printf ' [!] %s\n' "$1"; }
fehl() { printf ' [FEHL] %s\n' "$1"; FEHLER+=("$1"); }
titel "1. Dienst"
if systemctl is-active --quiet guacd; then
ok "guacd laeuft (seit $(systemctl show guacd -p ActiveEnterTimestamp --value))"
else
fehl "guacd laeuft NICHT -- 'systemctl status guacd' und 'journalctl -u guacd -n 30'"
fi
GUACD_PID="$(systemctl show guacd -p MainPID --value 2>/dev/null)"
[ "${GUACD_PID:-0}" != "0" ] || fehl "kein Haupt-Prozess ermittelbar"
titel "2. guacd.conf"
if [ -r /etc/guacamole/guacd.conf ]; then
grep -vE '^\s*(#|$)' /etc/guacamole/guacd.conf | sed 's/^/ /'
if grep -qE '^\s*log_level' /etc/guacamole/guacd.conf; then
# log_level MUSS unter [daemon] stehen; unter [server] verhindert es den Start.
abschnitt="$(awk '/^\[/{s=$0} /^[[:space:]]*log_level/{print s; exit}' /etc/guacamole/guacd.conf)"
[ "$abschnitt" = "[daemon]" ] && ok "log_level steht unter [daemon]" \
|| fehl "log_level steht unter $abschnitt statt [daemon]"
else
warn "kein log_level gesetzt (Standard info)"
fi
else
fehl "/etc/guacamole/guacd.conf nicht lesbar"
fi
titel "3. Umgebung des LAUFENDEN guacd (nicht der Unit-Datei!)"
if [ "${GUACD_PID:-0}" != "0" ] && [ -r "/proc/$GUACD_PID/environ" ]; then
UMGEBUNG="$(tr '\0' '\n' < "/proc/$GUACD_PID/environ")"
echo "$UMGEBUNG" | grep -E 'LD_PRELOAD|OPENSSL_CONF|JUMPHOST_' | sed 's/^/ /' || true
echo "$UMGEBUNG" | grep -q '^LD_PRELOAD=' \
&& ok "LD_PRELOAD ist im laufenden Prozess gesetzt" \
|| fehl "LD_PRELOAD FEHLT im laufenden Prozess -- Unit nicht neu gestartet, oder guacd_tls_seclevel ist leer"
echo "$UMGEBUNG" | grep -q '^JUMPHOST_GUACD_TLS_SECLEVEL=[0-5]' \
&& ok "JUMPHOST_GUACD_TLS_SECLEVEL ist gesetzt" \
|| fehl "JUMPHOST_GUACD_TLS_SECLEVEL fehlt oder ist leer -- die Zwischenschicht bleibt untaetig"
else
fehl "/proc/$GUACD_PID/environ nicht lesbar (als root ausfuehren)"
fi
echo " --- was die Unit-Dateien VORSEHEN (kann abweichen, wenn nicht neu gestartet) ---"
systemctl show guacd -p Environment --value | tr ' ' '\n' | sed 's/^/ /'
titel "4. Zwischenschicht"
if [ -f "$SHIM" ]; then
ok "vorhanden: $SHIM ($(stat -c %s "$SHIM") Byte, $(stat -c %y "$SHIM" | cut -d. -f1))"
else
fehl "$SHIM fehlt -- Ansible-Rolle guacd nicht gelaufen oder guacd_tls_seclevel leer"
fi
if [ "${GUACD_PID:-0}" != "0" ] && [ -r "/proc/$GUACD_PID/maps" ]; then
grep -q 'guacd-tls-seclevel-shim' "/proc/$GUACD_PID/maps" \
&& ok "Zwischenschicht ist in den laufenden guacd GELADEN" \
|| fehl "Zwischenschicht ist NICHT geladen -- sie wirkt derzeit nicht"
fi
titel "5. Ruft FreeRDP die Sicherheitsstufe ueberhaupt selbst?"
LIB="$(ldconfig -p | awk '/libfreerdp[0-9]*\.so/ {print $NF; exit}')"
if [ -n "${LIB:-}" ]; then
if grep -qa 'SSL_CTX_set_security_level' "$LIB"; then
ok "$LIB ruft SSL_CTX_set_security_level auf -- die Zwischenschicht kann greifen"
else
fehl "$LIB ruft SSL_CTX_set_security_level NICHT auf -- die Zwischenschicht ist der falsche Hebel"
fi
else
fehl "keine libfreerdp gefunden"
fi
titel "6. Was guacd zuletzt gemeldet hat"
journalctl -u guacd -n 400 --no-pager 2>/dev/null \
| grep -iE 'seclevel-shim|Certificate validation|ERRCONNECT|SSL/TLS connection failed|Security mode' \
| tail -8 | sed 's/^/ /' || echo " (nichts gefunden)"
if journalctl -u guacd -n 400 --no-pager 2>/dev/null | grep -q 'seclevel-shim'; then
ok "die Zwischenschicht hat die Stufe nachweislich geaendert"
else
warn "keine Meldung der Zwischenschicht im Journal -- sie hat noch nie eingegriffen"
fi
if journalctl -u guacd -n 400 --no-pager 2>/dev/null | grep -q 'Certificate validation'; then
ok "der Zertifikats-Rueckruf wurde erreicht -- die TLS-Schicht steht"
else
warn "keine 'Certificate validation'-Zeile -- Abbruch weiterhin VOR der Zertifikatspruefung"
fi
if [ -n "$ZIEL" ] && [ -r "$(dirname "$0")/diagnose_rdp_tls.py" ]; then
titel "7. TLS-Gegenprobe gegen $ZIEL"
python3 "$(dirname "$0")/diagnose_rdp_tls.py" "$ZIEL" 2>&1 | sed -n '/Schritt 2/,$p' | sed 's/^/ /'
fi
titel "ERGEBNIS"
if [ ${#FEHLER[@]} -eq 0 ]; then
echo " Alle Voraussetzungen erfuellt. Scheitert RDP trotzdem, liegt es nicht"
echo " mehr an der Sicherheitsstufe -- dann Abschnitt 6 und 7 auswerten."
else
echo " ${#FEHLER[@]} Voraussetzung(en) NICHT erfuellt:"
for f in "${FEHLER[@]}"; do echo " - $f"; done
echo
echo " Solange auch nur eine davon offen ist, sagt ein erneuter Verbindungs-"
echo " versuch nichts aus -- die Massnahme ist dann schlicht nicht aktiv."
fi