From bc4b8c9717c8972acf1f8d6383b127b5c8ef3e72 Mon Sep 17 00:00:00 2001 From: toughengineer Date: Sat, 8 Jul 2017 02:10:08 +0200 Subject: ntlm_sspi: fix authentication using Credential Manager If you pass empty user/pass asking curl to use Windows Credential Storage (as stated in the docs) and it has valid credentials for the domain, e.g. curl -v -u : --ntlm example.com currently authentication fails. This change fixes it by providing proper SPN string to the SSPI API calls. Fixes https://github.com/curl/curl/issues/1622 Closes https://github.com/curl/curl/pull/1660 --- lib/curl_sasl.c | 14 ++++++++------ lib/http_ntlm.c | 14 ++++++++++++-- lib/urldata.h | 1 + lib/vauth/ntlm.c | 6 ++++++ lib/vauth/ntlm_sspi.c | 14 ++++++++++++-- lib/vauth/vauth.h | 2 ++ 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 7052bd913..e54e4875e 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -265,7 +265,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; -#if defined(USE_KERBEROS5) +#if defined(USE_KERBEROS5) || defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : sasl->params->service; @@ -333,7 +333,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, if(force_ir || data->set.sasl_ir) result = Curl_auth_create_ntlm_type1_message(data, conn->user, conn->passwd, - &conn->ntlm, &resp, &len); + service, + hostname, + &conn->ntlm, &resp, + &len); } else #endif @@ -419,13 +422,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, char *chlg = NULL; size_t chlglen = 0; #endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_NTLM) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : sasl->params->service; -#endif -#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ - defined(USE_NTLM) char *serverdata; #endif size_t len = 0; @@ -496,6 +497,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, /* Create the type-1 message */ result = Curl_auth_create_ntlm_type1_message(data, conn->user, conn->passwd, + service, hostname, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index 0f1edcf65..fd5540b5d 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -121,9 +121,11 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) server, which is for a plain host or for a HTTP proxy */ char **allocuserpwd; - /* point to the name and password for this */ + /* point to the username, password, service and host */ const char *userp; const char *passwdp; + const char *service = NULL; + const char *hostname = NULL; /* point to the correct struct with this */ struct ntlmdata *ntlm; @@ -141,6 +143,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->http_proxy.user; passwdp = conn->http_proxy.passwd; + service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ? + conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; + hostname = conn->http_proxy.host.name; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } @@ -148,6 +153,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; + service = conn->data->set.str[STRING_SERVICE_NAME] ? + conn->data->set.str[STRING_SERVICE_NAME] : "HTTP"; + hostname = conn->host.name; ntlm = &conn->ntlm; authp = &conn->data->state.authhost; } @@ -174,7 +182,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp, - ntlm, &base64, &len); + service, hostname, + ntlm, &base64, + &len); if(result) return result; diff --git a/lib/urldata.h b/lib/urldata.h index 196aa6395..d439dc3d6 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -328,6 +328,7 @@ struct ntlmdata { BYTE *output_token; BYTE *input_token; size_t input_token_len; + TCHAR *spn; #else unsigned int flags; unsigned char nonce[8]; diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index 1e0d4792e..ea5e56e37 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -355,6 +355,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. @@ -365,6 +367,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, + const char *service, + const char *hostname, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { @@ -394,6 +398,8 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, domain are empty */ (void)userp; (void)passwdp; + (void)service, + (void)hostname, /* Clean up any former leftovers and initialise to defaults */ Curl_auth_ntlm_cleanup(ntlm); diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 921524618..089c1a6d4 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -70,6 +70,8 @@ bool Curl_auth_is_ntlm_supported(void) * data [in] - The session handle. * userp [in] - The user name in the format User or Domain\User. * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. * ntlm [in/out] - The NTLM data struct being used and modified. * outptr [in/out] - The address where a pointer to newly allocated memory * holding the result will be stored upon completion. @@ -80,6 +82,8 @@ bool Curl_auth_is_ntlm_supported(void) CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, + const char *service, + const char *host, struct ntlmdata *ntlm, char **outptr, size_t *outlen) { @@ -143,6 +147,10 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, if(!ntlm->context) return CURLE_OUT_OF_MEMORY; + ntlm->spn = Curl_auth_build_spn(service, host, NULL); + if(!ntlm->spn) + return CURLE_OUT_OF_MEMORY; + /* Setup the type-1 "output" security buffer */ type_1_desc.ulVersion = SECBUFFER_VERSION; type_1_desc.cBuffers = 1; @@ -153,7 +161,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, /* Generate our type-1 message */ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - (TCHAR *) TEXT(""), + ntlm->spn, 0, 0, SECURITY_NETWORK_DREP, NULL, 0, ntlm->context, &type_1_desc, @@ -271,7 +279,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* Generate our type-3 message */ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, ntlm->context, - (TCHAR *) TEXT(""), + ntlm->spn, 0, 0, SECURITY_NETWORK_DREP, &type_2_desc, 0, ntlm->context, @@ -329,6 +337,8 @@ void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) /* Reset any variables */ ntlm->token_max = 0; + + Curl_safefree(ntlm->spn); } #endif /* USE_WINDOWS_SSPI && USE_NTLM */ diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index dfaf985c6..f43064211 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -122,6 +122,8 @@ bool Curl_auth_is_ntlm_supported(void); CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, const char *passwdp, + const char *service, + const char *host, struct ntlmdata *ntlm, char **outptr, size_t *outlen); -- cgit v1.2.1