]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
spnego_sspi: honor CURLOPT_GSSAPI_DELEGATION for Windows SSPI
authorSong X. Gao <39278329+xsgao-github@users.noreply.github.com>
Mon, 11 May 2026 16:45:15 +0000 (12:45 -0400)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 12 May 2026 08:27:29 +0000 (10:27 +0200)
Make CURLOPT_GSSAPI_DELEGATION effective on Windows builds that use SSPI
(instead of a native GSS-API implementation), so Kerberos delegation can
be requested during SPNEGO/Negotiate authentication.

Closes #21528

lib/setopt.c
lib/urldata.h
lib/vauth/spnego_sspi.c
tests/data/Makefile.am
tests/data/test3302 [new file with mode: 0644]
tests/unit/Makefile.inc
tests/unit/unit3302.c [new file with mode: 0644]

index 24d0c42bcf5d993151e6097aa4017f27a643713e..61d87be06fcfc83b866e3968caa36d744cd3f594 100644 (file)
@@ -1288,7 +1288,7 @@ static CURLcode setopt_long_misc(struct Curl_easy *data, CURLoption option,
   case CURLOPT_ALTSVC_CTRL:
     return Curl_altsvc_ctrl(data, arg);
 #endif
-#ifdef HAVE_GSSAPI
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   case CURLOPT_GSSAPI_DELEGATION:
     s->gssapi_delegation = (unsigned char)arg &
       (CURLGSSAPI_DELEGATION_POLICY_FLAG | CURLGSSAPI_DELEGATION_FLAG);
index 335e61c4a39d3d748106e8171d439ea8bdcca1e2..2889e936a4ae7fd7591bbdbc3ca7918043576cd5 100644 (file)
@@ -1191,9 +1191,8 @@ struct UserDefined {
   uint8_t ipver; /* the CURL_IPRESOLVE_* defines in the public header
                           file 0 - whatever, 1 - v2, 2 - v6 */
   uint8_t upload_flags; /* flags set by CURLOPT_UPLOAD_FLAGS */
-#ifdef HAVE_GSSAPI
-  /* GSS-API credential delegation, see the documentation of
-     CURLOPT_GSSAPI_DELEGATION */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  /* GSS-API/SSPI credential delegation, see CURLOPT_GSSAPI_DELEGATION */
   uint8_t gssapi_delegation;
 #endif
   uint8_t http_follow_mode; /* follow HTTP redirects */
index 1baf59320a37709ef0ad2c74b6c449d89fae075d..eeae0214841676c37e04c7afd4852f702f03f92a 100644 (file)
@@ -223,15 +223,21 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
   resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);
 
   /* Generate our challenge-response message */
-  nego->status =
-    Curl_pSecFn->InitializeSecurityContext(nego->credentials,
-                                           chlg ? nego->context : NULL,
-                                           nego->spn,
-                                           ISC_REQ_CONFIDENTIALITY,
-                                           0, SECURITY_NATIVE_DREP,
-                                           chlg ? &chlg_desc : NULL,
-                                           0, nego->context,
-                                           &resp_desc, &attrs, NULL);
+  {
+    DWORD sspi_flags = ISC_REQ_CONFIDENTIALITY;
+    if(data->set.gssapi_delegation & (CURLGSSAPI_DELEGATION_FLAG |
+                                      CURLGSSAPI_DELEGATION_POLICY_FLAG))
+      sspi_flags |= ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH;
+    nego->status =
+      Curl_pSecFn->InitializeSecurityContext(nego->credentials,
+                                             chlg ? nego->context : NULL,
+                                             nego->spn,
+                                             sspi_flags,
+                                             0, SECURITY_NATIVE_DREP,
+                                             chlg ? &chlg_desc : NULL,
+                                             0, nego->context,
+                                             &resp_desc, &attrs, NULL);
+  }
 
   /* Free the decoded challenge as it is not required anymore */
   curlx_free(chlg);
index 12f6bfbc0cc754fdac04ce4d9a9afe16b1901da4..8dcf2d360c94ce416cb80a54b1b45b00ff9d3d23 100644 (file)
@@ -287,7 +287,7 @@ test3200 test3201 test3202 test3203 test3204 test3205 test3206 test3207 \
 test3208 test3209 test3210 test3211 test3212 test3213 test3214 test3215 \
 test3216 test3217 test3218 test3219 test3220 \
 \
-test3300 test3301 \
+test3300 test3301 test3302 \
 \
 test4000 test4001
 
diff --git a/tests/data/test3302 b/tests/data/test3302
new file mode 100644 (file)
index 0000000..35ccfc7
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+unittest
+CURLOPT_GSSAPI_DELEGATION
+</keywords>
+</info>
+
+# Client-side
+<client>
+<features>
+unittest
+</features>
+<name>
+CURLOPT_GSSAPI_DELEGATION stores flags in data->set on GSS-API and SSPI builds
+</name>
+</client>
+</testcase>
index 102c15f3b288b0345417c42f02c60c6e04118eac..f0ce3d4eefaa85bcc079f9b948ddbd97aaaed40c 100644 (file)
@@ -47,4 +47,4 @@ TESTS_C = \
   unit2600.c unit2601.c unit2602.c unit2603.c unit2604.c unit2605.c \
   unit3200.c                                             unit3205.c \
   unit3211.c unit3212.c unit3213.c unit3214.c            unit3216.c unit3219.c \
-  unit3300.c unit3301.c
+  unit3300.c unit3301.c unit3302.c
diff --git a/tests/unit/unit3302.c b/tests/unit/unit3302.c
new file mode 100644 (file)
index 0000000..6c0abed
--- /dev/null
@@ -0,0 +1,89 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "unitcheck.h"
+#include "urldata.h"
+
+static CURLcode test_unit3302(const char *arg)
+{
+  UNITTEST_BEGIN_SIMPLE
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  struct Curl_easy *easy;
+  CURLcode result;
+
+  curl_global_init(CURL_GLOBAL_ALL);
+  easy = curl_easy_init();
+  if(!easy) {
+    curl_global_cleanup();
+    goto unit_test_abort; /* OOM during setup, not a test failure */
+  }
+
+  /* CURLGSSAPI_DELEGATION_FLAG must be stored */
+  result = curl_easy_setopt(easy, CURLOPT_GSSAPI_DELEGATION,
+                            CURLGSSAPI_DELEGATION_FLAG);
+  fail_unless(result == CURLE_OK,
+              "setopt DELEGATION_FLAG returned error");
+  fail_unless(easy->set.gssapi_delegation == CURLGSSAPI_DELEGATION_FLAG,
+              "DELEGATION_FLAG not stored in data->set");
+
+  /* CURLGSSAPI_DELEGATION_POLICY_FLAG must be stored */
+  result = curl_easy_setopt(easy, CURLOPT_GSSAPI_DELEGATION,
+                            CURLGSSAPI_DELEGATION_POLICY_FLAG);
+  fail_unless(result == CURLE_OK,
+              "setopt DELEGATION_POLICY_FLAG returned error");
+  fail_unless(easy->set.gssapi_delegation == CURLGSSAPI_DELEGATION_POLICY_FLAG,
+              "DELEGATION_POLICY_FLAG not stored in data->set");
+
+  /* both flags together */
+  result = curl_easy_setopt(easy, CURLOPT_GSSAPI_DELEGATION,
+                            CURLGSSAPI_DELEGATION_FLAG |
+                            CURLGSSAPI_DELEGATION_POLICY_FLAG);
+  fail_unless(result == CURLE_OK,
+              "setopt both flags returned error");
+  fail_unless(easy->set.gssapi_delegation ==
+              (CURLGSSAPI_DELEGATION_FLAG | CURLGSSAPI_DELEGATION_POLICY_FLAG),
+              "both delegation flags not stored in data->set");
+
+  /* CURLGSSAPI_DELEGATION_NONE must clear the field */
+  result = curl_easy_setopt(easy, CURLOPT_GSSAPI_DELEGATION,
+                            CURLGSSAPI_DELEGATION_NONE);
+  fail_unless(result == CURLE_OK,
+              "setopt DELEGATION_NONE returned error");
+  fail_unless(easy->set.gssapi_delegation == 0,
+              "gssapi_delegation not cleared by DELEGATION_NONE");
+
+  /* unknown bits must be masked off */
+  result = curl_easy_setopt(easy, CURLOPT_GSSAPI_DELEGATION, 0xFFL);
+  fail_unless(result == CURLE_OK,
+              "setopt 0xFF returned error");
+  fail_unless(easy->set.gssapi_delegation ==
+              (CURLGSSAPI_DELEGATION_FLAG | CURLGSSAPI_DELEGATION_POLICY_FLAG),
+              "unknown bits not masked off");
+
+  curl_easy_cleanup(easy);
+  curl_global_cleanup();
+#endif /* HAVE_GSSAPI || USE_WINDOWS_SSPI */
+
+  UNITTEST_END_SIMPLE
+}