umbau 1.3.2
This commit is contained in:
126
ansible/roles/guacd/files/guacd_tls_seclevel_shim.c
Normal file
126
ansible/roles/guacd/files/guacd_tls_seclevel_shim.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* guacd-tls-seclevel-shim -- setzt die OpenSSL-Sicherheitsstufe, die FreeRDP
|
||||
* fuer seine RDP-Verbindungen verwendet.
|
||||
*
|
||||
* WOZU (Live-Test 3.9.2026, jumphost-97 -> 10.0.0.12)
|
||||
* ---------------------------------------------------
|
||||
* RDP-Verbindungen scheiterten mit
|
||||
* ERRCONNECT_TLS_CONNECT_FAILED [0x00020008]
|
||||
* und guacds daraus abgeleiteter Meldung
|
||||
* "SSL/TLS connection failed (untrusted/self-signed certificate?)".
|
||||
* Der Klammerzusatz ist irrefuehrend -- guacd setzt diesen festen Text fuer
|
||||
* genau diesen FreeRDP-Fehlercode. Am Zertifikat lag es nicht: im Journal
|
||||
* fehlte jede "Certificate validation ..."-Zeile, der Zertifikats-Rueckruf
|
||||
* wurde also nie erreicht.
|
||||
*
|
||||
* Gemessen mit scripts/diagnose_rdp_tls.py:
|
||||
* OpenSSL-Sicherheitsstufe 2 -> Verbindung vom Ziel zurueckgesetzt (TCP-RST)
|
||||
* OpenSSL-Sicherheitsstufe 1 -> IDENTISCH zurueckgesetzt
|
||||
* OpenSSL-Sicherheitsstufe 0 -> erfolgreich, TLS 1.2, ECDHE-RSA-AES256-SHA384
|
||||
*
|
||||
* Die Cipher-Listen sind auf allen drei Stufen identisch (gegengeprueft mit
|
||||
* `openssl ciphers -s 'DEFAULT@SECLEVEL=0|1|2'` -- jeweils dieselben 30). Der
|
||||
* Unterschied liegt also in der signature_algorithms-Erweiterung: OpenSSL 3.0
|
||||
* bietet SHA-1 ab Stufe 1 nicht mehr als Signaturverfahren an. Das Windows-Ziel
|
||||
* kann den ServerKeyExchange offenbar nicht anders signieren, findet nichts
|
||||
* Verwendbares und legt auf -- SCHANNEL schickt dabei ein TCP-RST statt einer
|
||||
* sauberen handshake_failure-Warnung.
|
||||
*
|
||||
* WARUM NICHT EINFACH OPENSSL_CONF
|
||||
* --------------------------------
|
||||
* Wurde versucht und reicht nicht. FreeRDP 2 setzt die Sicherheitsstufe SELBST
|
||||
* (Kommandozeilenoption /tls-seclevel, Vorgabe 1) und ruft dafuer nach dem
|
||||
* Anlegen des SSL_CTX SSL_CTX_set_security_level() auf. Das ueberschreibt jede
|
||||
* Vorgabe aus /etc/ssl/openssl.cnf bzw. aus einer eigenen OPENSSL_CONF.
|
||||
* guacamole-server 1.5.5 reicht diese FreeRDP-Option nicht als RDP-Parameter
|
||||
* durch -- es gibt also keinen Konfigurationsweg dorthin.
|
||||
*
|
||||
* WARUM DIESER WEG UND NICHT EIN QUELLCODE-PATCH
|
||||
* ----------------------------------------------
|
||||
* Ein Patch an guacamole-server muesste das Argument-Array GUAC_RDP_CLIENT_ARGS
|
||||
* und das dazu positionsgleiche IDX-Enum in src/protocols/rdp/settings.c
|
||||
* gemeinsam erweitern. Das ist bei jedem Versionswechsel neu anzupassen und
|
||||
* bricht den Build, sobald sich dort etwas verschiebt -- auf einem Host, der
|
||||
* guacd bei jedem Ansible-Lauf aus dem Quellcode baut, ein schlechtes Geschaeft.
|
||||
* Diese Zwischenschicht ist dagegen versionsunabhaengig, kann den Build nicht
|
||||
* beschaedigen und laesst sich durch Entfernen einer Environment-Zeile in der
|
||||
* guacd-Unit vollstaendig zuruecknehmen.
|
||||
*
|
||||
* VERHALTEN
|
||||
* ---------
|
||||
* Ohne die Umgebungsvariable JUMPHOST_GUACD_TLS_SECLEVEL tut diese Bibliothek
|
||||
* NICHTS: sie reicht jeden Aufruf unveraendert weiter. Erst ein gesetzter,
|
||||
* nicht-negativer Wert erzwingt diese Stufe. Die erste tatsaechliche Aenderung
|
||||
* wird nach syslog gemeldet, damit im Journal nachvollziehbar steht, dass hier
|
||||
* etwas eingreift.
|
||||
*
|
||||
* REICHWEITE
|
||||
* ----------
|
||||
* Wird ausschliesslich ueber Environment=LD_PRELOAD= in der guacd-Unit geladen
|
||||
* und wirkt damit nur im guacd-Prozess. Da guacd auf diesem Jumphost nur RDP
|
||||
* spricht und selbst kein TLS anbietet (bind_host=127.0.0.1, kein [ssl]-
|
||||
* Abschnitt in guacd.conf), betrifft die Absenkung genau die Strecke
|
||||
* guacd -> Windows-Ziel. Browser -> Jumphost, nginx, die Anwendung, SSH und
|
||||
* apt bleiben unberuehrt.
|
||||
*
|
||||
* EINSCHRAENKUNG
|
||||
* --------------
|
||||
* Die Stufe gilt fuer ALLE RDP-Ziele dieses Jumphosts, nicht je Host. Eine
|
||||
* Einstellung je Host waere nur ueber den oben verworfenen Quellcode-Patch zu
|
||||
* haben.
|
||||
*
|
||||
* Bewusst ohne <openssl/ssl.h>: der SSL_CTX-Zeiger wird nur durchgereicht, nie
|
||||
* dereferenziert. Damit braucht das Uebersetzen nur gcc, kein libssl-dev.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
typedef struct ssl_ctx_st SSL_CTX;
|
||||
|
||||
static int gewuenschte_stufe = -1; /* -1 = nicht eingreifen */
|
||||
static int stufe_gelesen = 0;
|
||||
static int bereits_gemeldet = 0;
|
||||
|
||||
static void stufe_lesen(void) {
|
||||
const char* wert = getenv("JUMPHOST_GUACD_TLS_SECLEVEL");
|
||||
if (wert != NULL && *wert != '\0') {
|
||||
char* ende = NULL;
|
||||
long gelesen = strtol(wert, &ende, 10);
|
||||
/* Nur vollstaendig geparste Werte im gueltigen OpenSSL-Bereich 0..5
|
||||
* uebernehmen. Bei Unsinn in der Variablen lieber nicht eingreifen,
|
||||
* als eine unbeabsichtigte Stufe zu erzwingen. */
|
||||
if (ende != NULL && *ende == '\0' && gelesen >= 0 && gelesen <= 5)
|
||||
gewuenschte_stufe = (int) gelesen;
|
||||
else
|
||||
syslog(LOG_WARNING, "guacd-tls-seclevel-shim: unbrauchbarer Wert "
|
||||
"JUMPHOST_GUACD_TLS_SECLEVEL=\"%s\", bleibe untaetig", wert);
|
||||
}
|
||||
stufe_gelesen = 1;
|
||||
}
|
||||
|
||||
void SSL_CTX_set_security_level(SSL_CTX* ctx, int stufe) {
|
||||
static void (*original)(SSL_CTX*, int) = NULL;
|
||||
|
||||
if (original == NULL)
|
||||
original = (void (*)(SSL_CTX*, int)) dlsym(RTLD_NEXT, "SSL_CTX_set_security_level");
|
||||
|
||||
if (!stufe_gelesen)
|
||||
stufe_lesen();
|
||||
|
||||
if (gewuenschte_stufe >= 0 && stufe != gewuenschte_stufe) {
|
||||
if (!bereits_gemeldet) {
|
||||
syslog(LOG_INFO, "guacd-tls-seclevel-shim: OpenSSL-Sicherheitsstufe %d -> %d "
|
||||
"(siehe ansible/roles/guacd, guacd_tls_seclevel)",
|
||||
stufe, gewuenschte_stufe);
|
||||
bereits_gemeldet = 1;
|
||||
}
|
||||
stufe = gewuenschte_stufe;
|
||||
}
|
||||
|
||||
/* Fehlt das Original wider Erwarten, ist Nichtstun richtig: OpenSSL bleibt
|
||||
* dann bei seiner Vorgabe, statt dass der Aufruf ins Leere laeuft. */
|
||||
if (original != NULL)
|
||||
original(ctx, stufe);
|
||||
}
|
||||
Reference in New Issue
Block a user