umbau 1.3.12
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Stellt genau den TLS-Verbindungsaufbau nach, an dem guacd/FreeRDP scheitert.
|
||||
"""Stellt genau den TLS-Verbindungsaufbau nach, an dem guacd/FreeRDP scheitert,
|
||||
und ermittelt die MILDESTE Lockerung, die ihn gelingen laesst.
|
||||
|
||||
Hintergrund (Live-Test 3.9.):
|
||||
|
||||
@ -14,27 +15,28 @@ Dass es NICHT am Zertifikat liegt, zeigt das guacd-Journal selbst: guacd
|
||||
protokolliert beim Pruefen eines Zertifikats immer eine der beiden Zeilen
|
||||
"Certificate validation bypassed" (ignore-cert greift) oder "Certificate
|
||||
validation failed". Steht KEINE von beiden im Journal, wurde der
|
||||
Zertifikats-Rueckruf nie erreicht -- der Handshake ist also schon vorher
|
||||
gescheitert, bei der Aushandlung von Protokollversion und Cipher. Die
|
||||
Hosteinstellung "Zertifikat ignorieren" kann daran nichts aendern.
|
||||
Zertifikats-Rueckruf nie erreicht -- der Handshake ist schon vorher
|
||||
gescheitert, bei der Aushandlung von Protokollversion, Cipher-Suite und
|
||||
Signaturverfahren. Die Hosteinstellung "Zertifikat ignorieren" kann daran
|
||||
nichts aendern.
|
||||
|
||||
Genau das prueft dieses Skript. Es macht, was FreeRDP macht:
|
||||
Was dieses Skript macht -- dasselbe wie FreeRDP:
|
||||
|
||||
1. TCP zu <ziel>:3389
|
||||
2. X.224-Verbindungsanfrage mit RDP_NEG_REQ (MS-RDPBCGR 2.2.1.1) --
|
||||
das ist die RDP-eigene Vorstufe, ohne die kein RDP-Server TLS spricht.
|
||||
Deshalb funktioniert "openssl s_client -connect ziel:3389" hier auch
|
||||
nicht: es faengt sofort mit ClientHello an und laeuft ins Leere.
|
||||
3. Auswerten, welche Sicherheitsstufe der Server auswaehlt
|
||||
4. TLS-Handshake auf derselben Verbindung -- und zwar MEHRFACH, mit
|
||||
verschiedenen OpenSSL-Vorgaben:
|
||||
a) System-Standard: exakt das, was guacd/FreeRDP auf diesem Host
|
||||
bekommen. Debian 12 setzt in /etc/ssl/openssl.cnf
|
||||
MinProtocol = TLSv1.2 und CipherString = DEFAULT@SECLEVEL=2.
|
||||
b) Alles erlaubt (SECLEVEL=0, ab TLS 1.0)
|
||||
c/d) TLS 1.0 bzw. TLS 1.2 einzeln erzwungen
|
||||
Der Vergleich sagt, ob die OpenSSL-Vorgaben des JUMPHOSTS die Ursache
|
||||
sind (a scheitert, b klappt) oder das Ziel selbst (alles scheitert).
|
||||
2. X.224-Verbindungsanfrage mit RDP_NEG_REQ (MS-RDPBCGR 2.2.1.1). Das ist
|
||||
die RDP-eigene Vorstufe, ohne die kein RDP-Server TLS spricht -- deshalb
|
||||
taugt "openssl s_client -connect ziel:3389" hier NICHT als Gegentest:
|
||||
es faengt sofort mit dem ClientHello an und laeuft ins Leere.
|
||||
3. Auswerten, welche Sicherheitsstufe der Server waehlt.
|
||||
4. TLS-Handshake auf derselben Verbindung, mehrfach, mit aufsteigend
|
||||
staerkerer Lockerung der OpenSSL-Vorgaben -- von "unveraendert" bis
|
||||
"alles erlaubt". Die Zertifikatspruefung ist ueberall AUS (wie
|
||||
ignore-cert), damit kein Ergebnis daran haengen kann.
|
||||
|
||||
Die Reihenfolge ist Absicht: gemeldet wird die ERSTE (= mildeste) Variante,
|
||||
die funktioniert, zusammen mit den passenden Ansible-Variablen. Auf einem
|
||||
Jumphost pauschal auf SECLEVEL=0 zu gehen, wenn SECLEVEL=1 genuegt, waere
|
||||
unnoetig.
|
||||
|
||||
Braucht nichts ausser Python 3 -- kein X11, kein xfreerdp, kein nmap.
|
||||
Aufruf: python3 scripts/diagnose_rdp_tls.py 10.0.0.12
|
||||
@ -46,6 +48,12 @@ import socket
|
||||
import ssl
|
||||
import struct
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
# ssl.TLSVersion.TLSv1/TLSv1_1 sind in neueren Python-Fassungen als veraltet
|
||||
# markiert. Hier werden sie absichtlich benutzt -- um festzustellen, OB das
|
||||
# Ziel sie noch spricht. Die Warnungen wuerden die Ausgabe nur zumuellen.
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning, module=__name__)
|
||||
|
||||
# MS-RDPBCGR 2.2.1.1.1 -- requestedProtocols
|
||||
PROTOCOL_RDP = 0x00000000 # "Native RDP", ohne TLS
|
||||
@ -72,6 +80,85 @@ _FAILURE_CODES = {
|
||||
0x06: "SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER",
|
||||
}
|
||||
|
||||
_VERSIONS = {
|
||||
"TLSv1": ssl.TLSVersion.TLSv1,
|
||||
"TLSv1.1": ssl.TLSVersion.TLSv1_1,
|
||||
"TLSv1.2": ssl.TLSVersion.TLSv1_2,
|
||||
"TLSv1.3": ssl.TLSVersion.TLSv1_3,
|
||||
}
|
||||
|
||||
|
||||
class Variante:
|
||||
"""Eine zu testende OpenSSL-Einstellung.
|
||||
|
||||
`ansible` ist None, wenn die Variante keine Empfehlung darstellt
|
||||
(System-Standard, oder reine Versionstests zur Information).
|
||||
"""
|
||||
|
||||
def __init__(self, key, label, *, ciphers=None, min_version=None,
|
||||
max_version=None, ansible=None, kandidat=False):
|
||||
self.key = key
|
||||
self.label = label
|
||||
self.ciphers = ciphers
|
||||
self.min_version = min_version
|
||||
self.max_version = max_version
|
||||
self.ansible = ansible
|
||||
self.kandidat = kandidat # kommt als Empfehlung in Frage?
|
||||
|
||||
def context(self) -> ssl.SSLContext:
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
# Wie guacd mit ignore-cert: keinerlei Pruefung. Damit ist
|
||||
# ausgeschlossen, dass ein Ergebnis an der Zertifikatspruefung haengt.
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
if self.ciphers:
|
||||
ctx.set_ciphers(self.ciphers)
|
||||
if self.min_version:
|
||||
ctx.minimum_version = _VERSIONS[self.min_version]
|
||||
if self.max_version:
|
||||
ctx.maximum_version = _VERSIONS[self.max_version]
|
||||
return ctx
|
||||
|
||||
|
||||
# Reihenfolge = aufsteigende Staerke der Lockerung. Die erste funktionierende
|
||||
# Variante mit kandidat=True ist die Empfehlung.
|
||||
VARIANTEN = [
|
||||
Variante("system", "System-Standard (genau das, was guacd/FreeRDP heute bekommt)"),
|
||||
|
||||
Variante("max12", "unveraendert streng, aber hoechstens TLS 1.2",
|
||||
max_version="TLSv1.2", kandidat=True,
|
||||
ansible={"guacd_tls_security_level": 2, "guacd_tls_min_protocol": "TLSv1.2",
|
||||
"guacd_tls_max_protocol": "TLSv1.2"}),
|
||||
|
||||
Variante("sec1", "SECLEVEL=1 (SHA-1-Signaturen wieder erlaubt), bis TLS 1.3",
|
||||
ciphers="DEFAULT@SECLEVEL=1", kandidat=True,
|
||||
ansible={"guacd_tls_security_level": 1, "guacd_tls_min_protocol": "TLSv1.2",
|
||||
"guacd_tls_max_protocol": ""}),
|
||||
|
||||
Variante("sec1_max12", "SECLEVEL=1 und hoechstens TLS 1.2",
|
||||
ciphers="DEFAULT@SECLEVEL=1", max_version="TLSv1.2", kandidat=True,
|
||||
ansible={"guacd_tls_security_level": 1, "guacd_tls_min_protocol": "TLSv1.2",
|
||||
"guacd_tls_max_protocol": "TLSv1.2"}),
|
||||
|
||||
Variante("sec0_max12", "SECLEVEL=0, ab TLS 1.2, hoechstens TLS 1.2",
|
||||
ciphers="DEFAULT@SECLEVEL=0", min_version="TLSv1.2", max_version="TLSv1.2",
|
||||
kandidat=True,
|
||||
ansible={"guacd_tls_security_level": 0, "guacd_tls_min_protocol": "TLSv1.2",
|
||||
"guacd_tls_max_protocol": "TLSv1.2"}),
|
||||
|
||||
Variante("relaxed", "alles erlaubt: ALL@SECLEVEL=0, ab TLS 1.0",
|
||||
ciphers="ALL@SECLEVEL=0", min_version="TLSv1", kandidat=True,
|
||||
ansible={"guacd_tls_security_level": 0, "guacd_tls_min_protocol": "TLSv1",
|
||||
"guacd_tls_max_protocol": ""}),
|
||||
]
|
||||
|
||||
# Nur zur Information: welche Versionen spricht das Ziel ueberhaupt?
|
||||
VERSIONSTESTS = [
|
||||
Variante(f"nur {name}", f"nur {name}", ciphers="ALL@SECLEVEL=0",
|
||||
min_version=name, max_version=name)
|
||||
for name in ("TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3")
|
||||
]
|
||||
|
||||
|
||||
def _x224_connection_request(requested: int) -> bytes:
|
||||
"""TPKT + X.224 Connection Request mit angehaengtem RDP_NEG_REQ."""
|
||||
@ -81,14 +168,6 @@ def _x224_connection_request(requested: int) -> bytes:
|
||||
return struct.pack(">BBH", 0x03, 0x00, 4 + len(x224)) + x224
|
||||
|
||||
|
||||
def _read_tpkt(sock: socket.socket) -> bytes:
|
||||
header = _recv_exact(sock, 4)
|
||||
if header[0] != 0x03:
|
||||
raise ValueError(f"Keine TPKT-Antwort (erstes Byte 0x{header[0]:02x}) -- spricht dort wirklich RDP?")
|
||||
(length,) = struct.unpack(">H", header[2:4])
|
||||
return header + _recv_exact(sock, length - 4)
|
||||
|
||||
|
||||
def _recv_exact(sock: socket.socket, count: int) -> bytes:
|
||||
buf = b""
|
||||
while len(buf) < count:
|
||||
@ -99,11 +178,18 @@ def _recv_exact(sock: socket.socket, count: int) -> bytes:
|
||||
return buf
|
||||
|
||||
|
||||
def _read_tpkt(sock: socket.socket) -> bytes:
|
||||
header = _recv_exact(sock, 4)
|
||||
if header[0] != 0x03:
|
||||
raise ValueError(f"Keine TPKT-Antwort (erstes Byte 0x{header[0]:02x}) -- spricht dort wirklich RDP?")
|
||||
(length,) = struct.unpack(">H", header[2:4])
|
||||
return header + _recv_exact(sock, length - 4)
|
||||
|
||||
|
||||
def negotiate(sock: socket.socket, requested: int) -> int:
|
||||
"""Fuehrt die X.224-Aushandlung durch, gibt das gewaehlte Protokoll zurueck."""
|
||||
"""X.224-Aushandlung; gibt das vom Server gewaehlte Protokoll zurueck."""
|
||||
sock.sendall(_x224_connection_request(requested))
|
||||
response = _read_tpkt(sock)
|
||||
body = response[4:]
|
||||
body = _read_tpkt(sock)[4:]
|
||||
if len(body) < 7:
|
||||
raise ValueError("X.224-Antwort zu kurz")
|
||||
payload = body[7:]
|
||||
@ -113,56 +199,33 @@ def negotiate(sock: socket.socket, requested: int) -> int:
|
||||
kind = payload[0]
|
||||
if kind == 0x03:
|
||||
(code,) = struct.unpack("<I", payload[4:8])
|
||||
raise ValueError(
|
||||
"Der Server LEHNT die gewuenschte Sicherheitsstufe ab: "
|
||||
+ _FAILURE_CODES.get(code, f"unbekannter failureCode 0x{code:02x}")
|
||||
)
|
||||
raise ValueError("Der Server LEHNT die gewuenschte Sicherheitsstufe ab: "
|
||||
+ _FAILURE_CODES.get(code, f"unbekannter failureCode 0x{code:02x}"))
|
||||
if kind != 0x02:
|
||||
raise ValueError(f"Unerwartete Antwortart 0x{kind:02x} in der X.224-Antwort")
|
||||
(selected,) = struct.unpack("<I", payload[4:8])
|
||||
return selected
|
||||
|
||||
|
||||
def _context(variant: str) -> ssl.SSLContext:
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
# Wie guacd mit ignore-cert: keinerlei Pruefung. Damit ist ausgeschlossen,
|
||||
# dass ein Ergebnis hier an der Zertifikatspruefung haengt.
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
if variant == "system":
|
||||
return ctx # erbt /etc/ssl/openssl.cnf -- genau wie guacd
|
||||
if variant == "relaxed":
|
||||
ctx.minimum_version = ssl.TLSVersion.TLSv1
|
||||
ctx.set_ciphers("ALL:@SECLEVEL=0")
|
||||
return ctx
|
||||
if variant in ("tls1.0", "tls1.1", "tls1.2", "tls1.3"):
|
||||
version = {
|
||||
"tls1.0": ssl.TLSVersion.TLSv1,
|
||||
"tls1.1": ssl.TLSVersion.TLSv1_1,
|
||||
"tls1.2": ssl.TLSVersion.TLSv1_2,
|
||||
"tls1.3": ssl.TLSVersion.TLSv1_3,
|
||||
}[variant]
|
||||
ctx.set_ciphers("ALL:@SECLEVEL=0")
|
||||
ctx.minimum_version = version
|
||||
ctx.maximum_version = version
|
||||
return ctx
|
||||
raise ValueError(variant)
|
||||
|
||||
|
||||
def try_handshake(host: str, port: int, requested: int, variant: str, timeout: float):
|
||||
"""Gibt (erfolg, text) zurueck."""
|
||||
def try_handshake(host, port, requested, variante: Variante, timeout):
|
||||
try:
|
||||
with socket.create_connection((host, port), timeout=timeout) as sock:
|
||||
selected = negotiate(sock, requested)
|
||||
if selected == PROTOCOL_RDP and requested != PROTOCOL_RDP:
|
||||
return (False, "Server waehlt 'Native RDP' -- er bietet auf dieser Stufe gar kein TLS an")
|
||||
ctx = _context(variant)
|
||||
with ctx.wrap_socket(sock, server_hostname=host) as tls:
|
||||
return (False, "Server waehlt 'Native RDP' -- kein TLS auf dieser Stufe")
|
||||
with variante.context().wrap_socket(sock, server_hostname=host) as tls:
|
||||
cert = tls.getpeercert(binary_form=True)
|
||||
info = f"{tls.version()}, {tls.cipher()[0]}, Zertifikat {len(cert)} Byte"
|
||||
return (True, info)
|
||||
return (True, f"{tls.version()}, {tls.cipher()[0]}, Zertifikat {len(cert)} Byte")
|
||||
except ssl.SSLError as exc:
|
||||
return (False, f"{type(exc).__name__}: {exc.reason if getattr(exc, 'reason', None) else exc}")
|
||||
grund = getattr(exc, "reason", None) or exc
|
||||
return (False, f"{type(exc).__name__}: {grund}")
|
||||
except ConnectionResetError:
|
||||
# Wichtig zu unterscheiden: KEIN lokaler OpenSSL-Abbruch, sondern die
|
||||
# Gegenstelle legt auf. SCHANNEL (Windows) schickt ein TCP-RST statt
|
||||
# einer sauberen handshake_failure-Warnung, wenn im ClientHello nichts
|
||||
# Verwendbares steht -- also ein Aushandlungsproblem, kein Netzfehler.
|
||||
return (False, "Connection reset by peer -- das Ziel hat aufgelegt "
|
||||
"(nichts Passendes im ClientHello gefunden)")
|
||||
except (OSError, ValueError) as exc:
|
||||
return (False, f"{type(exc).__name__}: {exc}")
|
||||
|
||||
@ -174,20 +237,16 @@ def main() -> int:
|
||||
parser.add_argument("--timeout", type=float, default=10.0)
|
||||
args = parser.parse_args()
|
||||
|
||||
import ssl as _ssl
|
||||
print(f"Jumphost: {_ssl.OPENSSL_VERSION}")
|
||||
print(f"Jumphost: {ssl.OPENSSL_VERSION}")
|
||||
try:
|
||||
with open("/etc/ssl/openssl.cnf", encoding="utf-8") as fh:
|
||||
relevant = [
|
||||
line.strip() for line in fh
|
||||
if line.strip().startswith(("MinProtocol", "CipherString", "MaxProtocol", "Options"))
|
||||
]
|
||||
relevant = [line.strip() for line in fh
|
||||
if line.strip().startswith(("MinProtocol", "MaxProtocol", "CipherString", "Options"))]
|
||||
print(" /etc/ssl/openssl.cnf: " + ("; ".join(relevant) if relevant else "keine Protokoll-/Cipher-Vorgaben"))
|
||||
except OSError:
|
||||
print(" /etc/ssl/openssl.cnf nicht lesbar")
|
||||
print(f"Ziel: {args.host}:{args.port}\n")
|
||||
|
||||
# 1) Welche Sicherheitsstufe waehlt der Server, wenn man ihm alles anbietet?
|
||||
print("== Schritt 1: X.224-Aushandlung ==")
|
||||
requested = PROTOCOL_SSL | PROTOCOL_HYBRID
|
||||
try:
|
||||
@ -196,8 +255,8 @@ def main() -> int:
|
||||
print(f" Angeboten: TLS + CredSSP/NLA -> Server waehlt: "
|
||||
f"{_PROTOCOL_NAMES.get(selected, hex(selected))}")
|
||||
except Exception as exc:
|
||||
print(f" FEHLGESCHLAGEN: {exc}")
|
||||
print("\n Damit erübrigt sich der TLS-Test -- die RDP-Vorstufe scheitert bereits.")
|
||||
print(f" FEHLGESCHLAGEN: {exc}\n")
|
||||
print(" Damit eruebrigt sich der TLS-Test -- die RDP-Vorstufe scheitert bereits.")
|
||||
return 1
|
||||
|
||||
if selected == PROTOCOL_RDP:
|
||||
@ -206,43 +265,52 @@ def main() -> int:
|
||||
print(" (GPO: 'Bestimmte Sicherheitsebene fuer RDP-Verbindungen anfordern').")
|
||||
return 1
|
||||
|
||||
# 2) TLS-Handshake unter verschiedenen OpenSSL-Vorgaben
|
||||
print("\n== Schritt 2: TLS-Handshake (Zertifikatspruefung ueberall AUS, wie ignore-cert) ==")
|
||||
varianten = [
|
||||
("system", "System-Standard (das, was guacd/FreeRDP bekommt)"),
|
||||
("relaxed", "Alles erlaubt (SECLEVEL=0, ab TLS 1.0)"),
|
||||
("tls1.0", "nur TLS 1.0"),
|
||||
("tls1.1", "nur TLS 1.1"),
|
||||
("tls1.2", "nur TLS 1.2"),
|
||||
("tls1.3", "nur TLS 1.3"),
|
||||
]
|
||||
print("\n== Schritt 2: TLS-Handshake, aufsteigend gelockert ==")
|
||||
print(" (Zertifikatspruefung ueberall AUS -- wie bei ignore-cert)\n")
|
||||
ergebnisse = {}
|
||||
for variant, label in varianten:
|
||||
ok, text = try_handshake(args.host, args.port, requested, variant, args.timeout)
|
||||
ergebnisse[variant] = ok
|
||||
print(f" [{'OK ' if ok else 'FEHL'}] {label}\n {text}")
|
||||
for v in VARIANTEN:
|
||||
ok, text = try_handshake(args.host, args.port, requested, v, args.timeout)
|
||||
ergebnisse[v.key] = ok
|
||||
print(f" [{'OK ' if ok else 'FEHL'}] {v.label}\n {text}")
|
||||
|
||||
print("\n== Schritt 3: welche TLS-Versionen spricht das Ziel? ==")
|
||||
gesprochen = []
|
||||
for v in VERSIONSTESTS:
|
||||
ok, text = try_handshake(args.host, args.port, requested, v, args.timeout)
|
||||
if ok:
|
||||
gesprochen.append(v.label.replace("nur ", ""))
|
||||
print(f" [{'OK ' if ok else 'FEHL'}] {v.label}: {text}")
|
||||
|
||||
# 3) Auswertung
|
||||
print("\n== Befund ==")
|
||||
if ergebnisse["system"]:
|
||||
print(" Der TLS-Handshake gelingt mit den System-Vorgaben. Die Ursache liegt")
|
||||
print(" dann NICHT in der TLS-Schicht, sondern eine Stufe weiter (CredSSP/NLA,")
|
||||
print(" Anmeldedaten) oder in guacd/FreeRDP selbst.")
|
||||
print(" Naechster Schritt: guacd_log_level auf 'debug' und erneut verbinden.")
|
||||
print(" Der TLS-Handshake gelingt bereits mit den System-Vorgaben.")
|
||||
print(" Die Ursache liegt dann NICHT in der TLS-Schicht, sondern eine Stufe")
|
||||
print(" weiter (CredSSP/NLA, Anmeldedaten) oder in guacd/FreeRDP selbst.")
|
||||
print(" Naechster Schritt: guacd_log_level auf 'debug', erneut verbinden,")
|
||||
print(" 'journalctl -u guacd -n 200' auswerten.")
|
||||
return 0
|
||||
if ergebnisse["relaxed"]:
|
||||
moeglich = [v for v in ("tls1.0", "tls1.1", "tls1.2", "tls1.3") if ergebnisse[v]]
|
||||
print(" EINDEUTIG: Der Handshake scheitert NUR an den OpenSSL-Vorgaben DIESES")
|
||||
print(" Jumphosts, nicht am Ziel und nicht am Zertifikat.")
|
||||
print(f" Das Ziel spricht: {', '.join(moeglich) if moeglich else '(nur mit SECLEVEL=0)'}")
|
||||
print(" Debian 12 setzt systemweit MinProtocol=TLSv1.2 und DEFAULT@SECLEVEL=2;")
|
||||
print(" guacd erbt das. Abhilfe: eine eigene OPENSSL_CONF NUR fuer die")
|
||||
print(" guacd-Unit (nicht systemweit lockern).")
|
||||
|
||||
empfehlung = next((v for v in VARIANTEN if v.kandidat and ergebnisse.get(v.key)), None)
|
||||
if empfehlung is None:
|
||||
print(" Der Handshake scheitert in JEDER Variante -- die Ursache liegt am Ziel")
|
||||
print(f" ({args.host}) oder dazwischen, nicht an den OpenSSL-Vorgaben des Jumphosts.")
|
||||
print(" Am Windows-Ziel pruefen: SCHANNEL-Registry (aktivierte TLS-Versionen und")
|
||||
print(" Cipher-Suites), Gruppenrichtlinie 'SSL-Verschluesselungsverfahren', und ob")
|
||||
print(" ueberhaupt ein RDP-Zertifikat hinterlegt ist.")
|
||||
return 1
|
||||
print(" Der Handshake scheitert in JEDER Variante -- die Ursache liegt am Ziel")
|
||||
print(" (10.0.0.12) oder dazwischen, nicht an den OpenSSL-Vorgaben des Jumphosts.")
|
||||
print(" Am Windows-Ziel pruefen: SCHANNEL-Registry (aktivierte TLS-Versionen),")
|
||||
print(" Cipher-Suite-Richtlinie, und ob ein RDP-Zertifikat hinterlegt ist.")
|
||||
|
||||
print(" Der Handshake scheitert an den OpenSSL-Vorgaben DIESES Jumphosts,")
|
||||
print(" nicht am Ziel und nicht am Zertifikat.")
|
||||
print(f" Das Ziel spricht: {', '.join(gesprochen) if gesprochen else '(unklar)'}")
|
||||
print(f"\n MILDESTE ausreichende Lockerung: {empfehlung.label}")
|
||||
print("\n In ansible/inventory/group_vars eintragen:")
|
||||
print(" guacd_tls_legacy_compat: true")
|
||||
for key, value in empfehlung.ansible.items():
|
||||
gezeigt = '""' if value == "" else (f'"{value}"' if isinstance(value, str) else value)
|
||||
print(f" {key}: {gezeigt}")
|
||||
print("\n Das wirkt NUR auf den guacd-Prozess (Environment=OPENSSL_CONF in dessen")
|
||||
print(" Unit), nicht systemweit. Die saubere Loesung bleibt, das Windows-Ziel")
|
||||
print(" passend zu konfigurieren -- dies ist die Ueberbrueckung bis dahin.")
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user