Commit 0f11550c for guacamole.apache.org

commit 0f11550c58d7cbdc44226ba0d5b2c1be6c8deea6
Author: Virtually Nick <vnick@apache.org>
Date:   Mon Jul 20 19:57:45 2026 -0400

    GUACAMOLE-2273: Handle FreeRDP version support for authentication reasons; support requesting gateway authentication.

diff --git a/src/protocols/rdp/argv.c b/src/protocols/rdp/argv.c
index d85bc13c..4822a5f5 100644
--- a/src/protocols/rdp/argv.c
+++ b/src/protocols/rdp/argv.c
@@ -56,6 +56,24 @@ int guac_rdp_argv_callback(guac_user* user, const char* mimetype,
         settings->domain = guac_strdup(value);
     }

+    /* Update gateway username */
+    else if (strcmp(name, GUAC_RDP_ARGV_GATEWAY_USERNAME) == 0) {
+        guac_mem_free(settings->gateway_username);
+        settings->gateway_username = guac_strdup(value);
+    }
+
+    /* Update gateway password */
+    else if (strcmp(name, GUAC_RDP_ARGV_GATEWAY_PASSWORD) == 0) {
+        guac_mem_free(settings->gateway_password);
+        settings->gateway_password = guac_strdup(value);
+    }
+
+    /* Update gateway domain */
+    else if (strcmp(name, GUAC_RDP_ARGV_GATEWAY_DOMAIN) == 0) {
+        guac_mem_free(settings->gateway_domain);
+        settings->gateway_domain = guac_strdup(value);
+    }
+
     return 0;

 }
diff --git a/src/protocols/rdp/argv.h b/src/protocols/rdp/argv.h
index c321dc6e..9d3e1a71 100644
--- a/src/protocols/rdp/argv.h
+++ b/src/protocols/rdp/argv.h
@@ -47,5 +47,23 @@ guac_argv_callback guac_rdp_argv_callback;
  */
 #define GUAC_RDP_ARGV_DOMAIN "domain"

+/**
+ * The name of the parameter that specifies/updates the gateway username that
+ * will be sent to the RDP server during authentication.
+ */
+#define GUAC_RDP_ARGV_GATEWAY_USERNAME "gateway-username"
+
+/**
+ * The name of the parameter that specifies/updates the gateway password that
+ * will be sent to the RDP server during authentication.
+ */
+#define GUAC_RDP_ARGV_GATEWAY_PASSWORD "gateway-password"
+
+/**
+ * The name of the parmaeter that specifies/updates the gateway domain that
+ * will be sent to the RDP server during authentication.
+ */
+#define GUAC_RDP_ARGV_GATEWAY_DOMAIN "gateway-domain"
+
 #endif

diff --git a/src/protocols/rdp/rdp.c b/src/protocols/rdp/rdp.c
index 1e2f954e..bc5513c5 100644
--- a/src/protocols/rdp/rdp.c
+++ b/src/protocols/rdp/rdp.c
@@ -54,15 +54,16 @@
 #include <freerdp/freerdp.h>
 #include <freerdp/gdi/gdi.h>
 #include <freerdp/graphics.h>
-#include <guacamole/proctitle.h>
 #include <freerdp/primary.h>
 #include <freerdp/settings.h>
 #include <freerdp/update.h>
+#include <freerdp/version.h>
 #include <guacamole/argv.h>
 #include <guacamole/audio.h>
 #include <guacamole/client.h>
 #include <guacamole/display.h>
 #include <guacamole/mem.h>
+#include <guacamole/proctitle.h>
 #include <guacamole/protocol.h>
 #include <guacamole/recording.h>
 #include <guacamole/socket.h>
@@ -231,6 +232,8 @@ static BOOL rdp_freerdp_pre_connect(freerdp* instance) {
     return TRUE;
 }

+#if defined(HAVE_FREERDP_AUTHENTICATE) || defined(HAVE_FREERDP_AUTHENTICATEEX)
+
 /**
  * Provided a guac_client, a NULL-terminated list of parameters, and the
  * pointers to the various authentication-related parameters, send the
@@ -271,20 +274,42 @@ static void guac_rdp_send_auth_params(guac_client* client, const char** params,
     /* Free old values and get new values from settings. */
     for (int i = 0; params[i] != NULL; i++) {

-        if (!strcmp(params[i], GUAC_RDP_ARGV_USERNAME)) {
+        if (strcmp(params[i], GUAC_RDP_ARGV_USERNAME) == 0) {
             guac_mem_free(*username);
             *username = guac_strdup(settings->username);
         }

-        if (!strcmp(params[i], GUAC_RDP_ARGV_DOMAIN)) {
+        else if (strcmp(params[i], GUAC_RDP_ARGV_GATEWAY_USERNAME) == 0) {
+            guac_mem_free(*username);
+            *username = guac_strdup(settings->gateway_username);
+        }
+
+        else if (strcmp(params[i], GUAC_RDP_ARGV_DOMAIN) == 0) {
             guac_mem_free(*domain);
             *domain = guac_strdup(settings->domain);
         }

-        if (!strcmp(params[i], GUAC_RDP_ARGV_PASSWORD)) {
+        else if (strcmp(params[i], GUAC_RDP_ARGV_GATEWAY_DOMAIN) == 0) {
+            guac_mem_free(*domain);
+            *domain = guac_strdup(settings->gateway_domain);
+        }
+
+        else if (strcmp(params[i], GUAC_RDP_ARGV_PASSWORD) == 0) {
             guac_mem_free(*password);
             *password = guac_strdup(settings->password);
         }
+
+        else if (strcmp(params[i], GUAC_RDP_ARGV_GATEWAY_PASSWORD) == 0) {
+            guac_mem_free(*password);
+            *password = guac_strdup(settings->gateway_password);
+        }
+
+        /* This should never happen, but we'll log it just in case. */
+        else {
+            guac_client_log(client, GUAC_LOG_WARNING,
+                    "Unknown authentication parameter requested.");
+        }
+
     }

 }
@@ -338,6 +363,54 @@ static int guac_rdp_register_required_auth(guac_rdp_settings* settings, char** p

 }

+#ifdef HAVE_FREERDP_AUTHENTICATEEX
+/**
+ * A function called when FreeRDP receives a request for gateway-related
+ * authentication settings, returning the number of settings that will be
+ * requested from the client.
+ *
+ * @param settings
+ *     The settings member from the RDP client.
+ *
+ * @param params
+ *     The structure used to store the parameters.
+ *
+ * @return
+ *     The number of settings that will be requested from the client.
+ */
+static int guac_rdp_register_required_gateway_auth(guac_rdp_settings* settings, char** params) {
+
+    int i = 0;
+
+    /* If the gateway username is null, we'll request that. */
+    if (settings->gateway_username == NULL) {
+        guac_argv_register(GUAC_RDP_ARGV_GATEWAY_USERNAME, guac_rdp_argv_callback, NULL, 0);
+        params[i] = GUAC_RDP_ARGV_GATEWAY_USERNAME;
+        i++;
+
+        /* If the gateway domain is null, we'll also request that. */
+        if (settings->gateway_domain == NULL) {
+            guac_argv_register(GUAC_RDP_ARGV_GATEWAY_DOMAIN, guac_rdp_argv_callback, NULL, 0);
+            params[i] = GUAC_RDP_ARGV_GATEWAY_DOMAIN;
+            i++;
+        }
+    }
+
+    /* If the gateway password is null, request that. */
+    if (settings->gateway_password == NULL) {
+        guac_argv_register(GUAC_RDP_ARGV_GATEWAY_PASSWORD, guac_rdp_argv_callback, NULL, 0);
+        params[i] = GUAC_RDP_ARGV_GATEWAY_PASSWORD;
+        i++;
+    }
+
+    /* NULL-terminate the array and return the number of items. */
+    params[i] = NULL;
+
+    return i;
+
+}
+#endif // HAVE_FREERDP_AUTHENTICATEEX
+
 #ifdef HAVE_FREERDP_AUTHENTICATE
 /**
  * Callback invoked by FreeRDP when authentication is required but the required
@@ -457,8 +530,12 @@ static BOOL rdp_freerdp_authenticate_ex(freerdp* instance, char** username,
     switch (reason) {

         /* In the case that we just need a PIN, request only the PIN/password. */
-        case AUTH_SMARTCARD_PIN:
+#if (FREERDP_VERSION_MAJOR >= 4) || \
+    (FREERDP_VERSION_MAJOR == 3 && FREERDP_VERSION_MINOR >= 25)
+        /* FIDO PIN support was added in 3.25.0 */
         case AUTH_FIDO_PIN:
+#endif
+        case AUTH_SMARTCARD_PIN:

             /* If the password/PIN is undefined, add it to the requested parameters. */
             if (settings->password == NULL) {
@@ -473,15 +550,23 @@ static BOOL rdp_freerdp_authenticate_ex(freerdp* instance, char** username,
             break;

         /* For all other cases, request anything that isn't configured. */
+#if (FREERDP_VERSION_MAJOR >= 4) || \
+    (FREERDP_VERSION_MAJOR == 3 && FREERDP_VERSION_MINOR >= 18)
+        /* RDSTLS support was added in 3.18.0 */
         case AUTH_RDSTLS:
+#endif
         case AUTH_TLS:
         case AUTH_RDP:
         case AUTH_NLA:
+            i = guac_rdp_register_required_auth(settings, params);
+            break;
+
         case GW_AUTH_HTTP:
         case GW_AUTH_RDG:
         case GW_AUTH_RPC:
-            i = guac_rdp_register_required_auth(settings, params);
+            i = guac_rdp_register_required_gateway_auth(settings, params);
             break;
+
     }

     /* If one or more params have been required, send them. */
@@ -493,6 +578,7 @@ static BOOL rdp_freerdp_authenticate_ex(freerdp* instance, char** username,

 }
 #endif // HAVE_FREERDP_AUTHENTICATEEX
+#endif // HAVE_FREERDP_AUTHENTICATE OR HAVE_FREERDP_AUTHENTICATEEX

 #ifdef HAVE_FREERDP_VERIFYCERTIFICATEEX
 /**
diff --git a/src/protocols/rdp/settings.c b/src/protocols/rdp/settings.c
index 451a056b..09566492 100644
--- a/src/protocols/rdp/settings.c
+++ b/src/protocols/rdp/settings.c
@@ -133,9 +133,9 @@ const char* GUAC_RDP_CLIENT_ARGS[] = {

     "gateway-hostname",
     "gateway-port",
-    "gateway-domain",
-    "gateway-username",
-    "gateway-password",
+    GUAC_RDP_ARGV_GATEWAY_DOMAIN,
+    GUAC_RDP_ARGV_GATEWAY_USERNAME,
+    GUAC_RDP_ARGV_GATEWAY_PASSWORD,

     "load-balance-info",