File curl-CVE-2026-1965.patch of Package curl.43131

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.14.1/lib/url.c
===================================================================
--- curl-8.14.1.orig/lib/url.c
+++ curl-8.14.1/lib/url.c
@@ -817,6 +817,8 @@ struct url_conn_match {
   BIT(may_multiplex);
   BIT(want_ntlm_http);
   BIT(want_proxy_ntlm_http);
+  BIT(want_nego_http);
+  BIT(want_proxy_nego_http);
 
   BIT(wait_pipe);
   BIT(force_reuse);
@@ -1215,7 +1217,7 @@ static bool url_match_auth_ntlm(struct c
     return FALSE;
   }
 #endif
-  if(m->want_ntlm_http || m->want_proxy_ntlm_http) {
+  if(m->want_nego_http || m->want_proxy_nego_http) {
     /* Credentials are already checked, we may use this connection.
      * With NTLM being weird as it is, we MUST use a
      * connection where it has already been fully negotiated.
@@ -1239,6 +1241,63 @@ static bool url_match_auth_ntlm(struct c
 #define url_match_auth_ntlm(c,m)    ((void)c, (void)m, TRUE)
 #endif
 
+#ifdef USE_SPNEGO
+static bool url_match_auth_nego(struct connectdata *conn,
+                                struct url_conn_match *m)
+{
+  /* 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(m->want_nego_http) {
+    if(Curl_timestrcmp(m->needle->user, conn->user) ||
+       Curl_timestrcmp(m->needle->passwd, conn->passwd))
+      return FALSE;
+  }
+  else if(conn->http_negotiate_state != GSS_AUTHNONE) {
+    /* Connection is using Negotiate auth but we do not want Negotiate */
+    return FALSE;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  /* Same for Proxy Negotiate authentication */
+  if(m->want_proxy_nego_http) {
+    /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
+     * NULL */
+    if(!conn->http_proxy.user || !conn->http_proxy.passwd)
+      return FALSE;
+
+    if(Curl_timestrcmp(m->needle->http_proxy.user,
+                       conn->http_proxy.user) ||
+       Curl_timestrcmp(m->needle->http_proxy.passwd,
+                       conn->http_proxy.passwd))
+      return FALSE;
+  }
+  else if(conn->proxy_negotiate_state != GSS_AUTHNONE) {
+    /* Proxy connection is using Negotiate auth but we do not want Negotiate */
+    return FALSE;
+  }
+#endif
+  if(m->want_nego_http || m->want_proxy_nego_http) {
+    /* 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. */
+    m->found = conn;
+    if((m->want_nego_http &&
+        (conn->http_negotiate_state != GSS_AUTHNONE)) ||
+       (m->want_proxy_nego_http &&
+        (conn->proxy_negotiate_state != GSS_AUTHNONE))) {
+      /* We must use this connection, no other */
+      m->force_reuse = TRUE;
+      return TRUE;
+    }
+    return FALSE; /* get another */
+  }
+  return TRUE;
+}
+#else
+#define url_match_auth_nego(c, m) ((void)c, (void)m, TRUE)
+#endif
+
 static bool url_match_conn(struct connectdata *conn, void *userdata)
 {
   struct url_conn_match *m = userdata;
@@ -1281,6 +1340,11 @@ static bool url_match_conn(struct connec
   else if(m->force_reuse)
     return TRUE;
 
+  if(!url_match_auth_nego(conn, m))
+    return FALSE;
+  else if(m->force_reuse)
+    return TRUE;
+
   if(!url_match_multiplex_limits(conn, m))
     return FALSE;
 
@@ -1347,13 +1411,26 @@ ConnectionExists(struct Curl_easy *data,
   match.may_multiplex = xfer_may_multiplex(data, needle);
 
 #ifdef USE_NTLM
-  match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
-                          (needle->handler->protocol & PROTO_FAMILY_HTTP));
+  match.want_ntlm_http =
+    (data->state.authhost.want & CURLAUTH_NTLM) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
 #ifndef CURL_DISABLE_PROXY
   match.want_proxy_ntlm_http =
-    (needle->bits.proxy_user_passwd &&
-     (data->state.authproxy.want & CURLAUTH_NTLM) &&
-     (needle->handler->protocol & PROTO_FAMILY_HTTP));
+    needle->bits.proxy_user_passwd &&
+    (data->state.authproxy.want & CURLAUTH_NTLM) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#endif
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+  match.want_nego_http =
+    (data->state.authhost.want & CURLAUTH_NEGOTIATE) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
+#ifndef CURL_DISABLE_PROXY
+  match.want_proxy_nego_http =
+    needle->bits.proxy_user_passwd &&
+    (data->state.authproxy.want & CURLAUTH_NEGOTIATE) &&
+    (needle->handler->protocol & PROTO_FAMILY_HTTP);
 #endif
 #endif
 
openSUSE Build Service is sponsored by