X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fhttp_negotiate_sspi.c;h=8396a6197829798923a38399a0bce9ec0853050d;hb=867eb33477c07331e7b58302119308d02a02ee01;hp=d651ac9c8bc5245b977fac0eb5de1d1fb43fa9d0;hpb=32de14ae0782822e9c54c3fbb28cdefc1f4de969;p=platform%2Fupstream%2Fcurl.git diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c index d651ac9..8396a61 100644 --- a/lib/http_negotiate_sspi.c +++ b/lib/http_negotiate_sspi.c @@ -24,14 +24,13 @@ #ifdef USE_WINDOWS_SSPI -#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP_NEGOTIATE) #include "urldata.h" #include "sendf.h" #include "rawstr.h" #include "warnless.h" #include "curl_base64.h" -#include "curl_sasl.h" #include "http_negotiate.h" #include "curl_memory.h" #include "curl_multibyte.h" @@ -42,47 +41,84 @@ /* The last #include file should be: */ #include "memdebug.h" +static int +get_gss_name(struct connectdata *conn, bool proxy, + struct negotiatedata *neg_ctx) +{ + const char* service; + size_t length; + + if(proxy && !conn->proxy.name) + /* proxy auth requested but no given proxy name, error out! */ + return -1; + + /* GSSAPI implementation by Globus (known as GSI) requires the name to be + of form "/" instead of @ (ie. slash instead + of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. + Change following lines if you want to use GSI */ + + /* IIS uses the @ form but uses 'http' as the service name, + and SSPI then generates an NTLM token. When using / a + Kerberos token is generated. */ + + if(neg_ctx->gss) + service = "KHTTP"; + else + service = "HTTP"; + + length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name : + conn->host.name) + 1; + if(length + 1 > sizeof(neg_ctx->server_name)) + return EMSGSIZE; + + snprintf(neg_ctx->server_name, sizeof(neg_ctx->server_name), "%s/%s", + service, proxy ? conn->proxy.name : conn->host.name); + + return 0; +} + /* returning zero (0) means success, everything else is treated as "failure" with no care exactly what the failure was */ int Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { - BYTE *input_token = NULL; + struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: + &conn->data->state.negotiate; + BYTE *input_token = 0; SecBufferDesc out_buff_desc; SecBuffer out_sec_buff; SecBufferDesc in_buff_desc; SecBuffer in_sec_buff; unsigned long context_attributes; - TimeStamp expiry; + TimeStamp lifetime; + TCHAR *sname; int ret; size_t len = 0, input_token_len = 0; + bool gss = FALSE; + const char* protocol; CURLcode error; - /* Point to the username and password */ - const char *userp; - const char *passwdp; - - /* Point to the correct struct with this */ - struct negotiatedata *neg_ctx; + if(checkprefix("GSS-Negotiate", header)) { + protocol = "GSS-Negotiate"; + gss = TRUE; + } + else if(checkprefix("Negotiate", header)) { + protocol = "Negotiate"; + gss = FALSE; + } + else + return -1; - if(proxy) { - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - neg_ctx = &conn->data->state.proxyneg; + if(neg_ctx->context) { + if(neg_ctx->gss != gss) { + return -1; + } } else { - userp = conn->user; - passwdp = conn->passwd; - neg_ctx = &conn->data->state.negotiate; + neg_ctx->protocol = protocol; + neg_ctx->gss = gss; } - /* Not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - if(neg_ctx->context && neg_ctx->status == SEC_E_OK) { /* We finished successfully our part of authentication, but server * rejected it (since we're again here). Exit with an error since we @@ -91,119 +127,102 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, return -1; } - if(!neg_ctx->server_name) { - /* Check proxy auth requested but no given proxy name */ - if(proxy && !conn->proxy.name) - return -1; - - /* Generate our SPN */ - neg_ctx->server_name = Curl_sasl_build_spn("HTTP", - proxy ? conn->proxy.name : - conn->host.name); - if(!neg_ctx->server_name) - return -1; + if(0 == strlen(neg_ctx->server_name)) { + ret = get_gss_name(conn, proxy, neg_ctx); + if(ret) + return ret; } if(!neg_ctx->output_token) { PSecPkgInfo SecurityPackage; - ret = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NEGOTIATE), + ret = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("Negotiate"), &SecurityPackage); if(ret != SEC_E_OK) return -1; /* Allocate input and output buffers according to the max token size as indicated by the security package */ - neg_ctx->token_max = SecurityPackage->cbMaxToken; - neg_ctx->output_token = malloc(neg_ctx->token_max); + neg_ctx->max_token_length = SecurityPackage->cbMaxToken; + neg_ctx->output_token = malloc(neg_ctx->max_token_length); s_pSecFn->FreeContextBuffer(SecurityPackage); } /* Obtain the input token, if any */ - header += strlen("Negotiate"); + header += strlen(neg_ctx->protocol); while(*header && ISSPACE(*header)) header++; len = strlen(header); if(!len) { - /* Is this the first call in a new negotiation? */ - if(neg_ctx->context) { - /* The server rejected our authentication and hasn't suppled any more - negotiation mechanisms */ - return -1; - } + /* first call in a new negotation, we have to acquire credentials, + and allocate memory for the context */ - /* We have to acquire credentials and allocate memory for the context */ neg_ctx->credentials = malloc(sizeof(CredHandle)); neg_ctx->context = malloc(sizeof(CtxtHandle)); if(!neg_ctx->credentials || !neg_ctx->context) return -1; - if(userp && *userp) { - /* Populate our identity structure */ - error = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); - if(error) - return -1; - - /* Allow proper cleanup of the identity structure */ - neg_ctx->p_identity = &neg_ctx->identity; - } - else - /* Use the current Windows user */ - neg_ctx->p_identity = NULL; - - /* Acquire our credientials handle */ neg_ctx->status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NEGOTIATE), - SECPKG_CRED_OUTBOUND, NULL, - neg_ctx->p_identity, NULL, NULL, - neg_ctx->credentials, &expiry); + (TCHAR *) TEXT("Negotiate"), + SECPKG_CRED_OUTBOUND, NULL, NULL, + NULL, NULL, neg_ctx->credentials, + &lifetime); if(neg_ctx->status != SEC_E_OK) return -1; } else { + input_token = malloc(neg_ctx->max_token_length); + if(!input_token) + return -1; + error = Curl_base64_decode(header, (unsigned char **)&input_token, &input_token_len); - if(error || !input_token_len) + if(error || input_token_len == 0) return -1; } - /* Setup the "output" security buffer */ - out_buff_desc.ulVersion = SECBUFFER_VERSION; + /* prepare the output buffers, and input buffers if present */ + out_buff_desc.ulVersion = 0; out_buff_desc.cBuffers = 1; out_buff_desc.pBuffers = &out_sec_buff; + + out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->max_token_length); out_sec_buff.BufferType = SECBUFFER_TOKEN; out_sec_buff.pvBuffer = neg_ctx->output_token; - out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max); - /* Setup the "input" security buffer if present */ + if(input_token) { - in_buff_desc.ulVersion = SECBUFFER_VERSION; + in_buff_desc.ulVersion = 0; in_buff_desc.cBuffers = 1; in_buff_desc.pBuffers = &in_sec_buff; + + in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); in_sec_buff.BufferType = SECBUFFER_TOKEN; in_sec_buff.pvBuffer = input_token; - in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); } - /* Generate our message */ + sname = Curl_convert_UTF8_to_tchar(neg_ctx->server_name); + if(!sname) + return CURLE_OUT_OF_MEMORY; + neg_ctx->status = s_pSecFn->InitializeSecurityContext( neg_ctx->credentials, - input_token ? neg_ctx->context : NULL, - neg_ctx->server_name, + input_token ? neg_ctx->context : 0, + sname, ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, - input_token ? &in_buff_desc : NULL, + input_token ? &in_buff_desc : 0, 0, neg_ctx->context, &out_buff_desc, &context_attributes, - &expiry); + &lifetime); - Curl_safefree(input_token); + Curl_unicodefree(sname); if(GSS_ERROR(neg_ctx->status)) return -1; @@ -238,50 +257,41 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) if(error) return error; - if(!len) + if(len == 0) return CURLE_REMOTE_ACCESS_DENIED; - userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - encoded); + userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", + neg_ctx->protocol, encoded); - if(proxy) { - Curl_safefree(conn->allocptr.proxyuserpwd); + if(proxy) conn->allocptr.proxyuserpwd = userp; - } - else { - Curl_safefree(conn->allocptr.userpwd); + else conn->allocptr.userpwd = userp; - } free(encoded); + Curl_cleanup_negotiate (conn->data); return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } static void cleanup(struct negotiatedata *neg_ctx) { - /* Free our security context */ if(neg_ctx->context) { s_pSecFn->DeleteSecurityContext(neg_ctx->context); free(neg_ctx->context); - neg_ctx->context = NULL; + neg_ctx->context = 0; } - /* Free our credentials handle */ if(neg_ctx->credentials) { s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials); free(neg_ctx->credentials); - neg_ctx->credentials = NULL; + neg_ctx->credentials = 0; } - /* Free our identity */ - Curl_sspi_free_identity(neg_ctx->p_identity); - neg_ctx->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(neg_ctx->server_name); - Curl_safefree(neg_ctx->output_token); + if(neg_ctx->output_token) { + free(neg_ctx->output_token); + neg_ctx->output_token = 0; + } - /* Reset any variables */ - neg_ctx->token_max = 0; + neg_ctx->max_token_length = 0; } void Curl_cleanup_negotiate(struct SessionHandle *data) @@ -290,6 +300,6 @@ void Curl_cleanup_negotiate(struct SessionHandle *data) cleanup(&data->state.proxyneg); } -#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ +#endif /* !CURL_DISABLE_HTTP && USE_HTTP_NEGOTIATE */ #endif /* USE_WINDOWS_SSPI */