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
---
 lib/url.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 5 deletions(-)

Index: curl-8.0.1/lib/url.c
===================================================================
--- curl-8.0.1.orig/lib/url.c
+++ curl-8.0.1/lib/url.c
@@ -1070,6 +1070,18 @@ ConnectionExists(struct Curl_easy *data,
 #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
+
   *force_reuse = FALSE;
   *waitpipe = FALSE;
 
@@ -1410,6 +1422,57 @@ ConnectionExists(struct Curl_easy *data,
           continue;
         }
 #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(wantNegohttp || wantProxyNegohttp) {
+          /* 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(canmultiplex) {
           /* We can multiplex if we want to. Let's continue looking for
              the optimal connection to use. */
