From 34fa034d9a390c4bd65e2d05262755ec8646ac12 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 5 Feb 2026 08:34:21 +0100
Subject: [PATCH] url: fix reuse of connections using HTTP Negotiate

Assume Negotiate means connection-based

Reported-by: Zhicheng Chen
Closes #20534

Upstream-Status: Backport [https://github.com/curl/curl/commit/34fa034d9a390c4bd6]
Backported by Ubuntu team http://archive.ubuntu.com/ubuntu/pool/main/c/curl/curl_8.5.0-2ubuntu10.8.debian.tar.xz

CVE: CVE-2026-1965
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 lib/url.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/lib/url.c b/lib/url.c
index 1439c9e..792c422 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -936,6 +936,18 @@ ConnectionExists(struct Curl_easy *data,
 #else
   bool wantProxyNTLMhttp = FALSE;
 #endif
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+  bool wantNegohttp =
+    (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#ifndef CURL_DISABLE_PROXY
+  bool wantProxyNegohttp =
+    needle->bits.proxy_user_passwd &&
+    (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#endif
 #endif
   /* plain HTTP with upgrade */
   bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
@@ -1274,6 +1286,56 @@ ConnectionExists(struct Curl_easy *data,
     }
 #endif
 
+#ifdef USE_SPNEGO
+  /* If we are looking for an HTTP+Negotiate connection, check if this is
+     already authenticating with the right credentials. If not, keep looking
+     so that we can reuse Negotiate connections if possible. */
+  if(wantNegohttp) {
+    if(Curl_timestrcmp(needle->user, check->user) ||
+       Curl_timestrcmp(needle->passwd, check->passwd))
+      continue;
+  }
+  else if(check->http_negotiate_state != GSS_AUTHNONE) {
+    /* Connection is using Negotiate auth but we do not want Negotiate */
+    continue;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  /* Same for Proxy Negotiate authentication */
+  if(wantProxyNegohttp) {
+    /* Both check->http_proxy.user and check->http_proxy.passwd can be
+     * NULL */
+    if(!check->http_proxy.user || !check->http_proxy.passwd)
+      continue;
+
+    if(Curl_timestrcmp(needle->http_proxy.user,
+		       check->http_proxy.user) ||
+       Curl_timestrcmp(needle->http_proxy.passwd,
+	               check->http_proxy.passwd))
+      continue;
+  }
+  else if(check->proxy_negotiate_state != GSS_AUTHNONE) {
+    /* Proxy connection is using Negotiate auth but we do not want Negotiate */
+    continue;
+  }
+#endif
+  if(wantNTLMhttp || wantProxyNTLMhttp) {
+    /* Credentials are already checked, we may use this connection. We MUST
+     * use a connection where it has already been fully negotiated. If it has
+     * not, we keep on looking for a better one. */
+    chosen = check;
+    if((wantNegohttp &&
+	(check->http_negotiate_state != GSS_AUTHNONE)) ||
+       (wantProxyNegohttp &&
+	(check->proxy_negotiate_state != GSS_AUTHNONE))) {
+      /* We must use this connection, no other */
+      *force_reuse = TRUE;
+      break;
+    }
+    continue; /* get another */
+  }
+#endif
+
     if(CONN_INUSE(check)) {
       DEBUGASSERT(canmultiplex);
       DEBUGASSERT(check->bits.multiplex);
-- 
2.43.0

