]> granicus.if.org Git - curl/commitdiff
tests: add initial gssapi test using stub implementation
authorIsaac Boukris <iboukris@gmail.com>
Tue, 18 Jul 2017 18:46:21 +0000 (21:46 +0300)
committerMarcel Raad <Marcel.Raad@teamviewer.com>
Fri, 15 Sep 2017 12:09:08 +0000 (14:09 +0200)
The stub implementation is pre-loaded using LD_PRELOAD
and emulates common gssapi uses (only builds if curl is
initially built with gssapi support).

The initial tests are currently disabled for debug builds
as LD_PRELOAD is not used then.

Ref: https://github.com/curl/curl/pull/1687

configure.ac
tests/FILEFORMAT
tests/data/Makefile.inc
tests/data/test2056 [new file with mode: 0644]
tests/data/test2057 [new file with mode: 0644]
tests/libtest/Makefile.am
tests/libtest/stub_gssapi.c [new file with mode: 0644]
tests/libtest/stub_gssapi.h [new file with mode: 0644]
tests/runtests.pl
tests/server/sws.c

index 234da10525d437c2b183ebd6570aaa6646288943..4d5018d91bcd1aa2e9b0444cfc35a65199cf3f6b 100755 (executable)
@@ -1335,6 +1335,13 @@ else
   CPPFLAGS="$save_CPPFLAGS"
 fi
 
+build_libstubgss=no
+if test x"$want_gss" = "xyes"; then
+  build_libstubgss=yes
+fi
+
+AM_CONDITIONAL(BUILD_STUB_GSS, test "x$build_libstubgss" = "xyes")
+
 dnl -------------------------------------------------------------
 dnl parse --with-default-ssl-backend so it can be validated below
 dnl -------------------------------------------------------------
index 75e561ae8a0a5b86d98730660d892b0cb34dd55b..fbeee2a7e6be55314ce3e9b4bc3937996c26b48c 100644 (file)
@@ -74,6 +74,8 @@ B) The request was HTTP and included digest details, which adds 1000 to NUM
 C) If a HTTP request is NTLM type-1, it adds 1001 to num
 D) If a HTTP request is NTLM type-3, it adds 1002 to num
 E) If a HTTP request is Basic and num is already >=1000, it adds 1 to num
+F) If a HTTP request is Negotiate, num gets incremented by one for each
+request with Negotiate authorization header on the same test case.
 
 Dynamically changing num in this way allows the test harness to be used to
 test authentication negotiation where several different requests must be sent
@@ -243,6 +245,7 @@ threaded-resolver
 unittest
 unix-sockets
 WinSSL
+ld_preload
 
 as well as each protocol that curl supports.  A protocol only needs to be
 specified if it is different from the server (useful when the server
index 942d2fe7c478e730081f71e7630c26c30bee9172..c26699ab01bbabb3fa42d9a8a59ba7afb61b10c2 100644 (file)
@@ -182,4 +182,5 @@ test2016 test2017 test2018 test2019 test2020 test2021 test2022 test2023 \
 test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
 test2032 test2033 test2034 test2035 test2036 test2037 test2038 test2039 \
 test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 \
-test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055
+test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055 \
+test2056 test2057
diff --git a/tests/data/test2056 b/tests/data/test2056
new file mode 100644 (file)
index 0000000..f00e212
--- /dev/null
@@ -0,0 +1,87 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Negotiate auth (stub krb5)
+</keywords>
+</info>
+# Server-side
+<reply>
+<!-- First request, expect 401 Negotiate -->
+<data>
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate
+Content-Length: 13
+
+Not yet sir!
+</data>
+<!-- Second request, expect success in one shot -->
+<data1>
+HTTP/1.1 200 Things are fine in server land
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate RA==
+Content-Length: 15
+
+Nice auth sir!
+</data1>
+<datacheck>
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate
+Content-Length: 13
+
+HTTP/1.1 200 Things are fine in server land
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate RA==
+Content-Length: 15
+
+Nice auth sir!
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+HTTP Negotiate authentication (stub krb5)
+</name>
+<features>
+GSS-API
+ld_preload
+!debug
+</features>
+<setenv>
+LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
+CURL_STUB_GSS_CREDS="KRB5_Alice"
+</setenv>
+<command>
+-u: --negotiate http://%HOSTIP:%HTTPPORT/2056
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /2056 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+GET /2056 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Authorization: Negotiate IktSQjVfQWxpY2UiOkhUVFBAMTI3LjAuMC4xOjE6QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test2057 b/tests/data/test2057
new file mode 100644 (file)
index 0000000..5625051
--- /dev/null
@@ -0,0 +1,108 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Negotiate auth (stub ntlm)
+</keywords>
+</info>
+# Server-side
+<reply>
+<!-- First request, expect 401 Negotiate -->
+<data>
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate
+Content-Length: 13
+
+Not yet sir!
+</data>
+<!-- Second request, expect 401 (ntlm challenge) -->
+<data1>
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate Qw==
+Content-Length: 19
+
+Still not yet sir!
+</data1>
+<!-- Third request, expect success  -->
+<data2>
+HTTP/1.1 200 Things are fine in server land
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate RA==
+Content-Length: 15
+
+Nice auth sir!
+</data2>
+<datacheck>
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate
+Content-Length: 13
+
+HTTP/1.1 401 Authorization Required
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate Qw==
+Content-Length: 19
+
+HTTP/1.1 200 Things are fine in server land
+Server: Microsoft-IIS/7.0
+Content-Type: text/html; charset=iso-8859-1
+WWW-Authenticate: Negotiate RA==
+Content-Length: 15
+
+Nice auth sir!
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+HTTP Negotiate authentication (stub ntlm)
+</name>
+<features>
+GSS-API
+ld_preload
+!debug
+</features>
+<setenv>
+LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
+CURL_STUB_GSS_CREDS="NTLM_Alice"
+</setenv>
+<command>
+-u: --negotiate http://%HOSTIP:%HTTPPORT/2057
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /2057 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+GET /2057 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Authorization: Negotiate Ik5UTE1fQWxpY2UiOkhUVFBAMTI3LjAuMC4xOjI6QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==\r
+Accept: */*\r
+\r
+GET /2057 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Authorization: Negotiate Ik5UTE1fQWxpY2UiOkhUVFBAMTI3LjAuMC4xOjM6QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>
index 9128a453db3d2f26c1e04871d780a24930638ce3..a4e85ef0c241cc6bea0bdfc5da3e6d0b370b562f 100644 (file)
@@ -109,6 +109,21 @@ libhostname_la_SOURCES = sethostname.c sethostname.h
 libhostname_la_LIBADD =
 libhostname_la_DEPENDENCIES =
 
+# Build a stub gssapi implementation for testing
+if BUILD_STUB_GSS
+noinst_LTLIBRARIES += libstubgss.la
+
+libstubgss_la_CPPFLAGS = $(AM_CPPFLAGS)
+libstubgss_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version -rpath /nowhere
+libstubgss_la_CFLAGS = $(AM_CFLAGS) -g -Wno-unused-parameter
+
+libstubgss_la_SOURCES = stub_gssapi.c stub_gssapi.h
+
+libstubgss_la_LIBADD =
+libstubgss_la_DEPENDENCIES =
+endif
+
+
 lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/curl.h
        @PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h > lib1521.c
 
diff --git a/tests/libtest/stub_gssapi.c b/tests/libtest/stub_gssapi.c
new file mode 100644 (file)
index 0000000..168becf
--- /dev/null
@@ -0,0 +1,397 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017, 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.haxx.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.
+ *
+ ***************************************************************************/
+
+/* Only provides the bare minimum to link with libcurl */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stub_gssapi.h"
+
+#define MAX_CREDS_LENGTH 250
+#define APPROX_TOKEN_LEN 250
+
+enum min_err_code {
+    GSS_OK = 0,
+    GSS_NO_MEMORY,
+    GSS_INVALID_ARGS,
+    GSS_INVALID_CREDS,
+    GSS_INVALID_CTX,
+    GSS_SERVER_ERR,
+    GSS_NO_MECH,
+    GSS_LAST
+};
+
+const char *min_err_table[] = {
+    "stub-gss: no error",
+    "stub-gss: no memory",
+    "stub-gss: invalid arguments",
+    "stub-gss: invalid credentials",
+    "stub-gss: invalid context",
+    "stub-gss: server returned error",
+    "stub-gss: cannot find a mechanism",
+    NULL
+};
+
+struct gss_ctx_id_t_desc_struct {
+  enum { NONE, KRB5, NTLM1, NTLM3 } sent;
+  int have_krb5;
+  int have_ntlm;
+  OM_uint32 flags;
+  char creds[MAX_CREDS_LENGTH];
+};
+
+OM_uint32 gss_init_sec_context(OM_uint32 *min,
+            gss_const_cred_id_t initiator_cred_handle,
+            gss_ctx_id_t *context_handle,
+            gss_const_name_t target_name,
+            const gss_OID mech_type,
+            OM_uint32 req_flags,
+            OM_uint32 time_req,
+            const gss_channel_bindings_t input_chan_bindings,
+            const gss_buffer_t input_token,
+            gss_OID *actual_mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 *ret_flags,
+            OM_uint32 *time_rec)
+{
+  /* The token will be encoded in base64 */
+  int length = APPROX_TOKEN_LEN * 3 / 4;
+  int used = 0;
+  char *token = NULL;
+  const char *creds = NULL;
+  gss_ctx_id_t ctx = NULL;
+
+  if(!min)
+    return GSS_S_FAILURE;
+
+  *min = 0;
+
+  if(!context_handle || !target_name || !output_token) {
+    *min = GSS_INVALID_ARGS;
+    return GSS_S_FAILURE;
+  }
+
+  creds = getenv("CURL_STUB_GSS_CREDS");
+  if(!creds || strlen(creds) >= MAX_CREDS_LENGTH) {
+    *min = GSS_INVALID_CREDS;
+    return GSS_S_FAILURE;
+  }
+
+  ctx = *context_handle;
+  if(ctx && strcmp(ctx->creds, creds)) {
+    *min = GSS_INVALID_CREDS;
+    return GSS_S_FAILURE;
+  }
+
+  output_token->length = 0;
+  output_token->value = NULL;
+
+  if(input_token && input_token->length) {
+    if(!ctx) {
+      *min = GSS_INVALID_CTX;
+      return GSS_S_FAILURE;
+    }
+
+    /* Server response, either D (RA==) or C (Qw==) */
+    if(((char *) input_token->value)[0] == 'D') {
+      /* Done */
+      switch(ctx->sent) {
+      case KRB5:
+      case NTLM3:
+        if(ret_flags)
+          *ret_flags = ctx->flags;
+        if(time_rec)
+          *time_rec = GSS_C_INDEFINITE;
+        return GSS_S_COMPLETE;
+      default:
+        *min = GSS_SERVER_ERR;
+        return GSS_S_FAILURE;
+      }
+    }
+
+    if(((char *) input_token->value)[0] != 'C') {
+      /* We only support Done or Continue */
+      *min = GSS_SERVER_ERR;
+      return GSS_S_FAILURE;
+    }
+
+    /* Continue */
+    switch(ctx->sent) {
+    case KRB5:
+      /* We sent KRB5 and it failed, let's try NTLM */
+      if(ctx->have_ntlm) {
+        ctx->sent = NTLM1;
+        break;
+      }
+      else {
+        *min = GSS_SERVER_ERR;
+        return GSS_S_FAILURE;
+      }
+    case NTLM1:
+      ctx->sent = NTLM3;
+      break;
+    default:
+      *min = GSS_SERVER_ERR;
+      return GSS_S_FAILURE;
+    }
+  }
+  else {
+    if(ctx) {
+      *min = GSS_INVALID_CTX;
+      return GSS_S_FAILURE;
+    }
+
+    ctx = (gss_ctx_id_t) calloc(sizeof(*ctx), 1);
+    if(!ctx) {
+      *min = GSS_NO_MEMORY;
+      return GSS_S_FAILURE;
+    }
+
+    if(strstr(creds, "KRB5"))
+      ctx->have_krb5 = 1;
+
+    if(strstr(creds, "NTLM"))
+      ctx->have_ntlm = 1;
+
+    if(ctx->have_krb5)
+      ctx->sent = KRB5;
+    else if(ctx->have_ntlm)
+      ctx->sent = NTLM1;
+    else {
+      free(ctx);
+      *min = GSS_NO_MECH;
+      return GSS_S_FAILURE;
+    }
+
+    strcpy(ctx->creds, creds);
+    ctx->flags = req_flags;
+  }
+
+  token = malloc(length);
+  if(!token) {
+    free(ctx);
+    *min = GSS_NO_MEMORY;
+    return GSS_S_FAILURE;
+  }
+
+  /* Token format: creds:target:type:padding */
+  used = snprintf(token, length, "%s:%s:%d:", creds,
+                  (char *) target_name, ctx->sent);
+
+  if(used >= length) {
+    free(token);
+    free(ctx);
+    *min = GSS_NO_MEMORY;
+    return GSS_S_FAILURE;
+  }
+
+  /* Overwrite null terminator */
+  memset(token + used, 'A', length - used);
+
+  *context_handle = ctx;
+
+  output_token->value = token;
+  output_token->length = length;
+
+  return GSS_S_CONTINUE_NEEDED;
+}
+
+OM_uint32 gss_delete_sec_context(OM_uint32 *min,
+                                 gss_ctx_id_t *context_handle,
+                                 gss_buffer_t output_token)
+{
+  if(!min)
+    return GSS_S_FAILURE;
+
+  if(!context_handle) {
+    *min = GSS_INVALID_CTX;
+    return GSS_S_FAILURE;
+  }
+
+  free(*context_handle);
+  *context_handle = NULL;
+  *min = 0;
+
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_release_buffer(OM_uint32 *min,
+                             gss_buffer_t buffer)
+{
+  if(min)
+    *min = 0;
+
+  if(buffer && buffer->length) {
+    free(buffer->value);
+    buffer->length = 0;
+  }
+
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_import_name(OM_uint32 *min,
+                          const gss_buffer_t input_name_buffer,
+                          const gss_OID input_name_type,
+                          gss_name_t *output_name)
+{
+  char *name = NULL;
+
+  if(!min)
+    return GSS_S_FAILURE;
+
+  if(!input_name_buffer || !output_name) {
+    *min = GSS_INVALID_ARGS;
+    return GSS_S_FAILURE;
+  }
+
+  name = strndup(input_name_buffer->value, input_name_buffer->length);
+  if(!name) {
+    *min = GSS_NO_MEMORY;
+    return GSS_S_FAILURE;
+  }
+
+  *output_name = (gss_name_t) name;
+  *min = 0;
+
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_release_name(OM_uint32 *min,
+                           gss_name_t *input_name)
+{
+  if(min)
+    *min = 0;
+
+  if(input_name)
+    free(*input_name);
+
+  return GSS_S_COMPLETE;
+}
+
+OM_uint32 gss_display_status(OM_uint32 *min,
+                             OM_uint32 status_value,
+                             int status_type,
+                             const gss_OID mech_type,
+                             OM_uint32 *message_context,
+                             gss_buffer_t status_string)
+{
+  const char maj_str[] = "Stub GSS error";
+  if(min)
+    *min = 0;
+
+  if(message_context)
+    *message_context = 0;
+
+  if(status_string) {
+    status_string->value = NULL;
+    status_string->length = 0;
+
+    if(status_value >= GSS_LAST)
+      return GSS_S_FAILURE;
+
+    switch(status_type) {
+      case GSS_C_GSS_CODE:
+        status_string->value = strdup(maj_str);
+        break;
+      case GSS_C_MECH_CODE:
+        status_string->value = strdup(min_err_table[status_value]);
+        break;
+      default:
+        return GSS_S_FAILURE;
+    }
+
+    if(status_string->value)
+      status_string->length = strlen(status_string->value);
+    else
+       return GSS_S_FAILURE;
+  }
+
+  return GSS_S_COMPLETE;
+}
+
+/* Stubs returning error */
+
+OM_uint32 gss_display_name(OM_uint32 *min,
+                           gss_const_name_t input_name,
+                           gss_buffer_t output_name_buffer,
+                           gss_OID *output_name_type)
+{
+  return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_inquire_context(OM_uint32 *min,
+                              gss_const_ctx_id_t context_handle,
+                              gss_name_t *src_name,
+                              gss_name_t *targ_name,
+                              OM_uint32 *lifetime_rec,
+                              gss_OID *mech_type,
+                              OM_uint32 *ctx_flags,
+                              int *locally_initiated,
+                              int *open_context)
+{
+  return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_wrap(OM_uint32 *min,
+                   gss_const_ctx_id_t context_handle,
+                   int conf_req_flag,
+                   gss_qop_t qop_req,
+                   const gss_buffer_t input_message_buffer,
+                   int *conf_state,
+                   gss_buffer_t output_message_buffer)
+{
+  return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_unwrap(OM_uint32 *min,
+                     gss_const_ctx_id_t context_handle,
+                     const gss_buffer_t input_message_buffer,
+                     gss_buffer_t output_message_buffer,
+                     int *conf_state,
+                     gss_qop_t *qop_state)
+{
+  return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_seal(OM_uint32 *min,
+                   gss_ctx_id_t context_handle,
+                   int conf_req_flag,
+                   int qop_req,
+                   gss_buffer_t input_message_buffer,
+                   int *conf_state,
+                   gss_buffer_t output_message_buffer)
+{
+  return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_unseal(OM_uint32 *min,
+                     gss_ctx_id_t context_handle,
+                     gss_buffer_t input_message_buffer,
+                     gss_buffer_t output_message_buffer,
+                     int *conf_state,
+                     int *qop_state)
+{
+  return GSS_S_FAILURE;
+}
+
diff --git a/tests/libtest/stub_gssapi.h b/tests/libtest/stub_gssapi.h
new file mode 100644 (file)
index 0000000..9a302f0
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef HEADER_CURL_GSSAPI_STUBS_H
+#define HEADER_CURL_GSSAPI_STUBS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017, 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.haxx.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.
+ *
+ ***************************************************************************/
+
+/* Roughly based on Heimdal's gssapi.h */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define GSS_ERROR(status) (status & 0x80000000)
+
+#define GSS_S_COMPLETE 0
+#define GSS_S_FAILURE (0x80000000)
+#define GSS_S_CONTINUE_NEEDED (1ul)
+
+#define GSS_C_QOP_DEFAULT 0
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+
+#define GSS_C_NULL_OID GSS_C_NO_OID
+
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+#define GSS_C_AF_INET 2
+
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE 0xfffffffful
+
+#define GSS_C_NT_HOSTBASED_SERVICE NULL
+
+typedef uint32_t OM_uint32;
+
+typedef OM_uint32 gss_qop_t;
+
+typedef struct gss_buffer_desc_struct {
+  size_t length;
+  void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+struct gss_cred_id_t_desc_struct;
+typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t;
+typedef const struct gss_cred_id_t_desc_struct *gss_const_cred_id_t;
+
+struct gss_ctx_id_t_desc_struct;
+typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t;
+typedef const struct gss_ctx_id_t_desc_struct *gss_const_ctx_id_t;
+
+struct gss_name_t_desc_struct;
+typedef struct gss_name_t_desc_struct *gss_name_t;
+typedef const struct gss_name_t_desc_struct *gss_const_name_t;
+
+typedef struct gss_OID_desc_struct {
+  OM_uint32 length;
+  void      *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_channel_bindings_struct {
+  OM_uint32 initiator_addrtype;
+  gss_buffer_desc initiator_address;
+  OM_uint32 acceptor_addrtype;
+  gss_buffer_desc acceptor_address;
+  gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+OM_uint32 gss_release_buffer(OM_uint32 * /*minor_status*/,
+                             gss_buffer_t /*buffer*/);
+
+OM_uint32 gss_init_sec_context(OM_uint32 * /*minor_status*/,
+            gss_const_cred_id_t /*initiator_cred_handle*/,
+            gss_ctx_id_t * /*context_handle*/,
+            gss_const_name_t /*target_name*/,
+            const gss_OID /*mech_type*/,
+            OM_uint32 /*req_flags*/,
+            OM_uint32 /*time_req*/,
+            const gss_channel_bindings_t /*input_chan_bindings*/,
+            const gss_buffer_t /*input_token*/,
+            gss_OID * /*actual_mech_type*/,
+            gss_buffer_t /*output_token*/,
+            OM_uint32 * /*ret_flags*/,
+            OM_uint32 * /*time_rec*/);
+
+OM_uint32 gss_delete_sec_context(OM_uint32 * /*minor_status*/,
+                                 gss_ctx_id_t * /*context_handle*/,
+                                 gss_buffer_t /*output_token*/);
+
+OM_uint32 gss_inquire_context(OM_uint32 * /*minor_status*/,
+                              gss_const_ctx_id_t /*context_handle*/,
+                              gss_name_t * /*src_name*/,
+                              gss_name_t * /*targ_name*/,
+                              OM_uint32 * /*lifetime_rec*/,
+                              gss_OID * /*mech_type*/,
+                              OM_uint32 * /*ctx_flags*/,
+                              int * /*locally_initiated*/,
+                              int * /*open_context*/);
+
+OM_uint32 gss_wrap(OM_uint32 * /*minor_status*/,
+                   gss_const_ctx_id_t /*context_handle*/,
+                   int /*conf_req_flag*/,
+                   gss_qop_t /*qop_req*/,
+                   const gss_buffer_t /*input_message_buffer*/,
+                   int * /*conf_state*/,
+                   gss_buffer_t /*output_message_buffer*/);
+
+OM_uint32 gss_unwrap(OM_uint32 * /*minor_status*/,
+                     gss_const_ctx_id_t /*context_handle*/,
+                     const gss_buffer_t /*input_message_buffer*/,
+                     gss_buffer_t /*output_message_buffer*/,
+                     int * /*conf_state*/,
+                     gss_qop_t * /*qop_state*/);
+
+OM_uint32 gss_seal(OM_uint32 * /*minor_status*/,
+                   gss_ctx_id_t /*context_handle*/,
+                   int /*conf_req_flag*/,
+                   int /*qop_req*/,
+                   gss_buffer_t /*input_message_buffer*/,
+                   int * /*conf_state*/,
+                   gss_buffer_t /*output_message_buffer*/);
+
+OM_uint32 gss_unseal(OM_uint32 * /*minor_status*/,
+                     gss_ctx_id_t /*context_handle*/,
+                     gss_buffer_t /*input_message_buffer*/,
+                     gss_buffer_t /*output_message_buffer*/,
+                     int * /*conf_state*/,
+                     int * /*qop_state*/);
+
+OM_uint32 gss_import_name(OM_uint32 * /*minor_status*/,
+                          const gss_buffer_t /*input_name_buffer*/,
+                          const gss_OID /*input_name_type*/,
+                          gss_name_t * /*output_name*/);
+
+OM_uint32 gss_release_name(OM_uint32 * /*minor_status*/,
+                           gss_name_t * /*input_name*/);
+
+OM_uint32 gss_display_name(OM_uint32 * /*minor_status*/,
+                           gss_const_name_t /*input_name*/,
+                           gss_buffer_t /*output_name_buffer*/,
+                           gss_OID * /*output_name_type*/);
+
+OM_uint32 gss_display_status(OM_uint32 * /*minor_status*/,
+                             OM_uint32 /*status_value*/,
+                             int /*status_type*/,
+                             const gss_OID /*mech_type*/,
+                             OM_uint32 * /*message_context*/,
+                             gss_buffer_t /*status_string*/);
+
+#endif /* HEADER_CURL_GSSAPI_STUBS_H */
+
index e3cf2bff8f19265d612040c5f38476816bc1b0ad..44fd0ae93038d4d66babde189165d231b44d646c 100755 (executable)
@@ -232,6 +232,7 @@ my $has_crypto;     # set if libcurl is built with cryptographic support
 my $has_cares;      # set if built with c-ares
 my $has_threadedres;# set if built with threaded resolver
 my $has_psl;        # set if libcurl is built with PSL support
+my $has_ldpreload;  # set if curl is built for systems supporting LD_PRELOAD
 
 # this version is decided by the particular nghttp2 library that is being used
 my $h2cver = "h2c";
@@ -2731,6 +2732,9 @@ sub checksystem {
             $curl =~ s/^(.*)(libcurl.*)/$1/g;
 
             $libcurl = $2;
+            if($curl =~ /linux|bsd|solaris|darwin/) {
+                $has_ldpreload = 1;
+            }
             if($curl =~ /win32|mingw(32|64)/) {
                 # This is a Windows MinGW build or native build, we need to use
                 # Win32-style path.
@@ -3315,6 +3319,11 @@ sub singletest {
                     next;
                 }
             }
+            elsif($1 eq "ld_preload") {
+                if($has_ldpreload && !$debug_build) {
+                    next;
+                }
+            }
             elsif($1 eq "unittest") {
                 if($debug_build) {
                     next;
index 993fefcf72678963da0ada5022222f360ed6bb82..821497068352c7bee7654b8f101ead72a0d3ef75 100644 (file)
@@ -763,7 +763,20 @@ static int ProcessRequest(struct httprequest *req)
       logmsg("Authorization header found, as required");
   }
 
-  if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
+  if(strstr(req->reqbuf, "Authorization: Negotiate")) {
+    /* Negotiate iterations */
+    static long prev_testno = -1;
+    static long prev_partno = -1;
+    logmsg("Negotiate: prev_testno: %d, prev_partno: %d",
+            prev_testno, prev_partno);
+    if(req->testno != prev_testno) {
+      prev_testno = req->testno;
+      prev_partno = req->partno;
+    }
+    prev_partno += 1;
+    req->partno = prev_partno;
+  }
+  else if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {
     /* If the client is passing this Digest-header, we set the part number
        to 1000. Not only to spice up the complexity of this, but to make
        Digest stuff to work in the test suite. */