diff --git a/CMakeLists.txt b/CMakeLists.txt index 611388024f..159743fdd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,6 +434,8 @@ option(CURL_DISABLE_KERBEROS_AUTH "Disable Kerberos authentication" OFF) mark_as_advanced(CURL_DISABLE_KERBEROS_AUTH) option(CURL_DISABLE_NEGOTIATE_AUTH "Disable negotiate authentication" OFF) mark_as_advanced(CURL_DISABLE_NEGOTIATE_AUTH) +option(CURL_DISABLE_NEGOTIATE_NTLM "Block NTLM within SPNEGO negotiation" OFF) +mark_as_advanced(CURL_DISABLE_NEGOTIATE_NTLM) option(CURL_DISABLE_AWS "Disable aws-sigv4" OFF) mark_as_advanced(CURL_DISABLE_AWS) option(CURL_DISABLE_DICT "Disable DICT" OFF) @@ -1339,6 +1341,11 @@ if(CURL_USE_GSSAPI) elseif(GSS_VERSION) # MIT set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"") endif() + + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_LIBRARIES CURL::gss) + check_function_exists("gss_set_neg_mechs" HAVE_GSS_SET_NEG_MECHS) + cmake_pop_check_state() else() message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.") endif() diff --git a/configure.ac b/configure.ac index d06024bc10..7a014e6fba 100644 --- a/configure.ac +++ b/configure.ac @@ -2016,6 +2016,7 @@ if test "$want_gss" = "yes"; then AC_MSG_RESULT([no]) AC_MSG_ERROR([--with-gssapi was specified, but a GSS-API library was not found.]) ]) + AC_CHECK_FUNCS([gss_set_neg_mechs]) fi build_libstubgss=no @@ -4459,6 +4460,26 @@ AS_HELP_STRING([--disable-negotiate-auth],[Disable negotiate authentication]), AC_MSG_RESULT(yes) ) +dnl ************************************************************ +dnl disable NTLM within SPNEGO negotiation +dnl +AC_MSG_CHECKING([whether to allow NTLM within SPNEGO]) +AC_ARG_ENABLE(negotiate-ntlm, +AS_HELP_STRING([--enable-negotiate-ntlm],[Allow NTLM within SPNEGO (default)]) +AS_HELP_STRING([--disable-negotiate-ntlm],[Block NTLM within SPNEGO]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_NEGOTIATE_NTLM, 1, [to block NTLM within SPNEGO]) + CURL_DISABLE_NEGOTIATE_NTLM=1 + ;; + *) + AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + dnl ************************************************************ dnl disable aws dnl diff --git a/docs/CURL-DISABLE.md b/docs/CURL-DISABLE.md index a6a1ea1661..0b2596e21b 100644 --- a/docs/CURL-DISABLE.md +++ b/docs/CURL-DISABLE.md @@ -38,6 +38,10 @@ Disable support for the Kerberos authentication methods. Disable support for the negotiate authentication methods. +## `CURL_DISABLE_NEGOTIATE_NTLM` + +Block NTLM authentication within SPNEGO negotiation. + ## `CURL_DISABLE_AWS` Disable **aws-sigv4** support. diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md index fd589a834c..c6aad83135 100644 --- a/docs/libcurl/curl_version_info.md +++ b/docs/libcurl/curl_version_info.md @@ -312,6 +312,12 @@ libcurl ignore cookies with a domain that is on the list. libcurl was built with support for SPNEGO authentication (Simple and Protected GSS-API Negotiation Mechanism, defined in RFC 2478.) +## `SPNEGO-no-NTLM` + +*features* mask bit: none + +NTLM authentication is blocked within SPNEGO negotiation. + ## `SSL` *features* mask bit: CURL_VERSION_SSL diff --git a/lib/curl_config-cmake.h.in b/lib/curl_config-cmake.h.in index 41b0ddf073..36620d7e0e 100644 --- a/lib/curl_config-cmake.h.in +++ b/lib/curl_config-cmake.h.in @@ -58,6 +58,9 @@ /* disables negotiate authentication */ #cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1 +/* blocks NTLM within SPNEGO negotiation */ +#cmakedefine CURL_DISABLE_NEGOTIATE_NTLM 1 + /* disables aws-sigv4 */ #cmakedefine CURL_DISABLE_AWS 1 diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index 650d1908d0..85102ee355 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -81,7 +81,6 @@ enum min_err_code { /* libcurl is also passing this struct to these functions, which are not yet * stubbed: - * gss_inquire_context() * gss_unwrap() * gss_wrap() */ @@ -308,6 +307,48 @@ static OM_uint32 stub_gss_delete_sec_context( return GSS_S_COMPLETE; } + +/* NTLMSSP OID: 1.3.6.1.4.1.311.2.2.10 */ +static gss_OID_desc stub_ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") +}; + +static OM_uint32 +stub_gss_inquire_context(OM_uint32 *min, + struct stub_gss_ctx_id_t_desc *context, + 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) +{ + (void)src_name; + (void)targ_name; + (void)lifetime_rec; + (void)ctx_flags; + (void)locally_initiated; + (void)open_context; + + if(!min) + return GSS_S_FAILURE; + + if(!context) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + + *min = 0; + if(mech_type) { + if(context->have_ntlm && !context->have_krb5) + *mech_type = &stub_ntlmssp_oid; + else + *mech_type = (gss_OID)&Curl_krb5_mech_oid; + } + + return GSS_S_COMPLETE; +} #endif /* CURL_GSS_STUB */ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, @@ -319,7 +360,8 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, - OM_uint32 *ret_flags) + OM_uint32 *ret_flags, + gss_cred_id_t cred_handle) { OM_uint32 req_flags = GSS_C_REPLAY_FLAG; @@ -341,7 +383,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, #ifdef CURL_GSS_STUB if(getenv("CURL_STUB_GSS_CREDS")) return stub_gss_init_sec_context(minor_status, - GSS_C_NO_CREDENTIAL, /* cred_handle */ + cred_handle, (struct stub_gss_ctx_id_t_desc **)context, target_name, mech_type, @@ -356,7 +398,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, #endif /* CURL_GSS_STUB */ return gss_init_sec_context(minor_status, - GSS_C_NO_CREDENTIAL, /* cred_handle */ + cred_handle, context, target_name, mech_type, @@ -384,6 +426,23 @@ OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, return gss_delete_sec_context(min, context, output_token); } +OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context, + gss_OID *mech_type) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_inquire_context(minor_status, + (struct stub_gss_ctx_id_t_desc *)context, + NULL, NULL, NULL, mech_type, + NULL, NULL, NULL); +#endif /* CURL_GSS_STUB */ + + return gss_inquire_context(minor_status, context, + NULL, NULL, NULL, mech_type, + NULL, NULL, NULL); +} + #ifdef CURLVERBOSE #define GSS_LOG_BUFFER_LEN 1024 static size_t display_gss_error(OM_uint32 status, int type, diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h index fc3759ebcb..e7f649e114 100644 --- a/lib/curl_gssapi.h +++ b/lib/curl_gssapi.h @@ -41,12 +41,17 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, - OM_uint32 *ret_flags); + OM_uint32 *ret_flags, + gss_cred_id_t cred_handle); OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, gss_ctx_id_t *context, gss_buffer_t output_token); +OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context, + gss_OID *mech_type); + #ifdef CURLVERBOSE /* Helper to log a GSS-API error status */ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 3ea17621b1..4180643507 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -93,7 +93,7 @@ void Curl_sspi_global_cleanup(void) * Returns CURLE_OK on success. */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity) + SEC_WINNT_AUTH_IDENTITY_EX *identity) { xcharp_u useranddomain; xcharp_u user, dup_user; @@ -105,6 +105,8 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* Initialize the identity */ memset(identity, 0, sizeof(*identity)); + identity->Version = SEC_WINNT_AUTH_IDENTITY_VERSION; + identity->Length = sizeof(*identity); useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp); if(!useranddomain.tchar_ptr) @@ -195,7 +197,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, * * identity [in/out] - The identity structure. */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity) { if(identity) { curlx_safefree(identity->User); diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h index 3779d51753..ea405f53a7 100644 --- a/lib/curl_sspi.h +++ b/lib/curl_sspi.h @@ -34,14 +34,14 @@ void Curl_sspi_global_cleanup(void); /* This is used to populate the domain in an SSPI identity structure */ CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity); + SEC_WINNT_AUTH_IDENTITY_EX *identity); /* This is used to generate an SSPI identity structure */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity); + SEC_WINNT_AUTH_IDENTITY_EX *identity); /* This is used to free an SSPI identity structure */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity); /* Forward-declaration of global variables defined in curl_sspi.c */ extern PSecurityFunctionTable Curl_pSecFn; diff --git a/lib/ldap.c b/lib/ldap.c index f8e7ff6a70..ab2abc9fda 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -157,7 +157,7 @@ static ULONG ldap_win_bind_auth(LDAP *server, const char *user, const char *passwd, unsigned long authflags) { ULONG method = 0; - SEC_WINNT_AUTH_IDENTITY cred; + SEC_WINNT_AUTH_IDENTITY_EX cred; ULONG rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; memset(&cred, 0, sizeof(cred)); diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 32db07044a..f7f0cbceba 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -180,7 +180,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, gss_token, &gss_send_token, TRUE, - &gss_ret_flags); + &gss_ret_flags, + GSS_C_NO_CREDENTIAL); if(gss_token != GSS_C_NO_BUFFER) { curlx_safefree(gss_recv_token.value); diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index f0b6780fca..b7703b84fa 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -95,8 +95,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, CredHandle credentials; CtxtHandle context; PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; @@ -240,7 +240,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, * Returns CURLE_OK on success. */ CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity) + SEC_WINNT_AUTH_IDENTITY_EX *identity) { xcharp_u domain, dup_domain; @@ -466,8 +466,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->http_context) { CredHandle credentials; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; SecBuffer resp_buf; SecBufferDesc resp_desc; unsigned long attrs; diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c index 64c735be58..92c283f877 100644 --- a/lib/vauth/krb5_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -138,7 +138,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, &input_token, &output_token, mutual_auth, - NULL); + NULL, + GSS_C_NO_CREDENTIAL); if(GSS_ERROR(major_status)) { if(output_token.value) diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c index 38bb4c1422..61e293327f 100644 --- a/lib/vauth/spnego_gssapi.c +++ b/lib/vauth/spnego_gssapi.c @@ -37,6 +37,7 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif + /* * Curl_auth_is_spnego_supported() * @@ -158,6 +159,54 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, } #endif +#ifdef HAVE_GSS_SET_NEG_MECHS +#ifdef CURL_DISABLE_NEGOTIATE_NTLM + /* Acquire explicit credentials and restrict SPNEGO sub-mechanisms to + * exclude NTLM. We enumerate all available mechanisms and filter out + * the NTLMSSP OID, matching SSPI's "!ntlm". */ + if(nego->cred == GSS_C_NO_CREDENTIAL) { + /* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */ + static const gss_OID_desc ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") + }; + gss_OID_set available_mechs = GSS_C_NO_OID_SET; + gss_OID_set filtered_mechs = GSS_C_NO_OID_SET; + + /* Acquire default credentials for SPNEGO */ + major_status = gss_acquire_cred(&minor_status, GSS_C_NO_NAME, + GSS_C_INDEFINITE, GSS_C_NO_OID_SET, + GSS_C_INITIATE, &nego->cred, NULL, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_acquire_cred() failed: ", + major_status, minor_status); + Curl_safefree(input_token.value); + return CURLE_AUTH_ERROR; + } + + /* Get all available mechanisms */ + major_status = gss_indicate_mechs(&minor_status, &available_mechs); + if(!GSS_ERROR(major_status)) { + /* Build a set excluding NTLMSSP */ + major_status = gss_create_empty_oid_set(&minor_status, &filtered_mechs); + if(!GSS_ERROR(major_status)) { + size_t i; + for(i = 0; i < available_mechs->count; i++) { + gss_OID oid = &available_mechs->elements[i]; + if(oid->length != ntlmssp_oid.length || + memcmp(oid->elements, ntlmssp_oid.elements, oid->length)) { + gss_add_oid_set_member(&minor_status, oid, &filtered_mechs); + } + } + /* Restrict SPNEGO to only use non-NTLM mechanisms */ + gss_set_neg_mechs(&minor_status, nego->cred, filtered_mechs); + gss_release_oid_set(&minor_status, &filtered_mechs); + } + gss_release_oid_set(&minor_status, &available_mechs); + } + } +#endif /* CURL_DISABLE_NEGOTIATE_NTLM */ +#endif /* HAVE_GSS_SET_NEG_MECHS */ + /* Generate our challenge-response message */ major_status = Curl_gss_init_sec_context(data, &minor_status, @@ -168,7 +217,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, &input_token, &output_token, TRUE, - NULL); + NULL, + nego->cred); /* Free the decoded challenge as it is not required anymore */ curlx_safefree(input_token.value); @@ -191,6 +241,31 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, return CURLE_AUTH_ERROR; } + /* Check if NTLM was selected and is disallowed */ +#ifdef CURL_DISABLE_NEGOTIATE_NTLM + if(nego->context != GSS_C_NO_CONTEXT) { + /* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */ + static const gss_OID_desc ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") + }; + OM_uint32 inquire_major, inquire_minor; + gss_OID mech_type = GSS_C_NO_OID; + + inquire_major = Curl_gss_inquire_context(&inquire_minor, + nego->context, + &mech_type); + if(!GSS_ERROR(inquire_major) && mech_type && + mech_type->length == ntlmssp_oid.length && + !memcmp(mech_type->elements, ntlmssp_oid.elements, + ntlmssp_oid.length)) { + infof(data, "SPNEGO chose NTLM, but NTLM is not allowed"); + gss_release_buffer(&unused_status, &output_token); + Curl_auth_cleanup_spnego(nego); + return CURLE_AUTH_ERROR; + } + } +#endif /* CURL_DISABLE_NEGOTIATE_NTLM */ + /* Free previous token */ if(nego->output_token.length && nego->output_token.value) gss_release_buffer(&unused_status, &nego->output_token); @@ -280,6 +355,12 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) nego->spn = GSS_C_NO_NAME; } + /* Free our credentials */ + if(nego->cred != GSS_C_NO_CREDENTIAL) { + gss_release_cred(&minor_status, &nego->cred); + nego->cred = GSS_C_NO_CREDENTIAL; + } + /* Reset any variables */ nego->status = 0; nego->noauthpersist = FALSE; diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index 1baf59320a..ce65a93f1e 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -146,6 +146,29 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, /* Use the current Windows user */ nego->p_identity = NULL; +#ifdef CURL_DISABLE_NEGOTIATE_NTLM + /* Exclude NTLM from SPNEGO negotiation via the PackageList field */ + if(!nego->p_identity) { + memset(&nego->identity, 0, sizeof(nego->identity)); + nego->identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION; + nego->identity.Length = sizeof(nego->identity); + nego->identity.Flags = +#ifdef UNICODE + SEC_WINNT_AUTH_IDENTITY_UNICODE; +#else + SEC_WINNT_AUTH_IDENTITY_ANSI; +#endif + nego->p_identity = &nego->identity; + } + + /* Use the special name "!ntlm" to prevent NTLM from being used: + * https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-sec_winnt_auth_identity_exa + */ + nego->identity.PackageList = + (unsigned TCHAR *)CURL_UNCONST(TEXT("!ntlm")); + nego->identity.PackageListLength = 5; +#endif /* CURL_DISABLE_NEGOTIATE_NTLM */ + /* Allocate our credentials handle */ nego->credentials = curlx_calloc(1, sizeof(CredHandle)); if(!nego->credentials) diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index b5ff31414f..3d4d7511a9 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -170,8 +170,8 @@ struct ntlmdata { #endif CredHandle *credentials; CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; size_t token_max; BYTE *output_token; BYTE *input_token; @@ -241,8 +241,8 @@ struct kerberos5data { CredHandle *credentials; CtxtHandle *context; TCHAR *spn; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; size_t token_max; BYTE *output_token; #else @@ -297,6 +297,7 @@ struct negotiatedata { OM_uint32 status; gss_ctx_id_t context; gss_name_t spn; + gss_cred_id_t cred; gss_buffer_desc output_token; #ifdef GSS_C_CHANNEL_BOUND_FLAG struct dynbuf channel_binding_data; @@ -309,8 +310,8 @@ struct negotiatedata { SECURITY_STATUS status; CredHandle *credentials; CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; TCHAR *spn; size_t token_max; BYTE *output_token; diff --git a/lib/version.c b/lib/version.c index b3b0a46abb..b80da1f276 100644 --- a/lib/version.c +++ b/lib/version.c @@ -503,6 +503,9 @@ static const struct feat features_table[] = { #endif /* USE_SSL */ #ifdef USE_SPNEGO FEATURE("SPNEGO", NULL, CURL_VERSION_SPNEGO), +#ifdef CURL_DISABLE_NEGOTIATE_NTLM + FEATURE("SPNEGO-no-NTLM", NULL, 0), +#endif #endif #ifdef USE_SSL FEATURE("SSL", NULL, CURL_VERSION_SSL), diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 3003dce03b..0390ae7e9d 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -255,7 +255,7 @@ test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \ test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \ test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ -test2088 test2089 test2090 test2091 \ +test2088 test2089 test2090 test2091 test2092 test2093 \ test2100 test2101 test2102 test2103 test2104 \ \ test2200 test2201 test2202 test2203 test2204 test2205 \ diff --git a/tests/data/test2092 b/tests/data/test2092 new file mode 100644 index 0000000000..5423e15055 --- /dev/null +++ b/tests/data/test2092 @@ -0,0 +1,59 @@ + + + + +HTTP +HTTP GET +HTTP Negotiate auth (stub ntlm) +SPNEGO NTLM disallowed + + + +# Server-side + + +HTTP/1.1 200 OK swsclose +Content-Length: 23 + +This IS the real page! + + + +# Client-side + + +http + + +SPNEGO skips auth when NTLM blocked by CURL_DISABLE_NEGOTIATE_NTLM + + +GSS-API +Debug +negotiate-ntlm-disabled + + +CURL_STUB_GSS_CREDS="NTLM_Alice" + + +--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +0 + +# When NTLM is the only available mechanism and is blocked, +# negotiate auth silently fails and the request is sent without +# any Authorization header. + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + + diff --git a/tests/data/test2093 b/tests/data/test2093 new file mode 100644 index 0000000000..95f84c2656 --- /dev/null +++ b/tests/data/test2093 @@ -0,0 +1,69 @@ + + + + +HTTP +HTTP GET +HTTP Negotiate auth (stub krb5) +SPNEGO NTLM disallowed + + + +# Server-side + + +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! + + +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! + + + +# Client-side + + +http + + +SPNEGO with Kerberos still works when built with CURL_DISABLE_NEGOTIATE_NTLM + + +GSS-API +Debug +negotiate-ntlm-disabled + + +CURL_STUB_GSS_CREDS="KRB5_Alice" + + +--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +0 + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Authorization: Negotiate %b64["KRB5_Alice":HTTP@127.0.0.1:1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]b64% +User-Agent: curl/%VERSION +Accept: */* + + + + diff --git a/tests/runtests.pl b/tests/runtests.pl index e9184fd47a..ebc27c5b87 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -694,6 +694,8 @@ sub checksystemfeatures { $feature{"Kerberos"} = $feat =~ /Kerberos/i; # SPNEGO enabled $feature{"SPNEGO"} = $feat =~ /SPNEGO/i; + # SPNEGO NTLM disabled (compile-time) + $feature{"negotiate-ntlm-disabled"} = $feat =~ /SPNEGO-no-NTLM/i; # TLS-SRP enabled $feature{"TLS-SRP"} = $feat =~ /TLS-SRP/i; # PSL enabled