diff options
author | Brad King <brad.king@kitware.com> | 2014-10-08 19:07:44 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2014-10-29 20:41:10 (GMT) |
commit | 9cf069f88ba43931c46b245f567b0f8371a6067c (patch) | |
tree | 7c7cb0053221fc643357404141bad628d8575548 /Utilities/cmcurl/lib/http_negotiate.c | |
parent | 15c994ebdc9674bb057567370333ee0330a60ad2 (diff) | |
download | CMake-9cf069f88ba43931c46b245f567b0f8371a6067c.zip CMake-9cf069f88ba43931c46b245f567b0f8371a6067c.tar.gz CMake-9cf069f88ba43931c46b245f567b0f8371a6067c.tar.bz2 |
curl: Move sources back into upstream layout
Update our build files as needed to compensate.
Diffstat (limited to 'Utilities/cmcurl/lib/http_negotiate.c')
-rw-r--r-- | Utilities/cmcurl/lib/http_negotiate.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c new file mode 100644 index 0000000..bdfeefa --- /dev/null +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -0,0 +1,327 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2007, 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 http://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. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +#ifdef HAVE_GSSAPI +#ifdef HAVE_GSSMIT +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif + +#ifndef CURL_DISABLE_HTTP + /* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" +#include "base64.h" +#include "http_negotiate.h" +#include "memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +static int +get_gss_name(struct connectdata *conn, gss_name_t *server) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 major_status, minor_status; + gss_buffer_desc token = GSS_C_EMPTY_BUFFER; + char name[2048]; + const char* service; + + /* GSSAPI implementation by Globus (known as GSI) requires the name to be + of form "<service>/<fqdn>" instead of <service>@<fqdn> (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 <service>@<fqdn> form but uses 'http' as the service name */ + + if (neg_ctx->gss) + service = "KHTTP"; + else + service = "HTTP"; + + token.length = strlen(service) + 1 + strlen(conn->host.name) + 1; + if (token.length + 1 > sizeof(name)) + return EMSGSIZE; + + snprintf(name, sizeof(name), "%s@%s", service, conn->host.name); + + token.value = (void *) name; + major_status = gss_import_name(&minor_status, + &token, + GSS_C_NT_HOSTBASED_SERVICE, + server); + + return GSS_ERROR(major_status) ? -1 : 0; +} + +static void +log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix) +{ + OM_uint32 maj_stat, min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + char buf[1024]; + size_t len; + + snprintf(buf, sizeof(buf), "%s", prefix); + len = strlen(buf); + do { + maj_stat = gss_display_status (&min_stat, + error_status, + GSS_C_MECH_CODE, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if (sizeof(buf) > len + status_string.length + 1) { + snprintf(buf + len, sizeof(buf) - len, + ": %s", (char*) status_string.value); + len += status_string.length; + } + gss_release_buffer(&min_stat, &status_string); + } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); + + infof(conn->data, "%s", buf); +} + +int Curl_input_negotiate(struct connectdata *conn, char *header) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 major_status, minor_status, minor_status2; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + int ret; + size_t len; + bool gss; + const char* protocol; + + while(*header && ISSPACE(*header)) + header++; + if(checkprefix("GSS-Negotiate", header)) { + protocol = "GSS-Negotiate"; + gss = TRUE; + } + else if (checkprefix("Negotiate", header)) { + protocol = "Negotiate"; + gss = FALSE; + } + else + return -1; + + if (neg_ctx->context) { + if (neg_ctx->gss != gss) { + return -1; + } + } + else { + neg_ctx->protocol = protocol; + neg_ctx->gss = gss; + } + + if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { + /* We finished succesfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_cleanup_negotiate(conn->data); + return -1; + } + + if (neg_ctx->server_name == NULL && + (ret = get_gss_name(conn, &neg_ctx->server_name))) + return ret; + + header += strlen(neg_ctx->protocol); + while(*header && ISSPACE(*header)) + header++; + + len = strlen(header); + if (len > 0) { + int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value); + if (rawlen < 0) + return -1; + input_token.length = rawlen; + +#ifdef HAVE_SPNEGO /* Handle SPNEGO */ + if (checkprefix("Negotiate", header)) { + ASN1_OBJECT * object = NULL; + int rc = 1; + unsigned char * spnegoToken = NULL; + size_t spnegoTokenLength = 0; + unsigned char * mechToken = NULL; + size_t mechTokenLength = 0; + + spnegoToken = malloc(input_token.length); + if (input_token.value == NULL) + return ENOMEM; + spnegoTokenLength = input_token.length; + + object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); + if (!parseSpnegoTargetToken(spnegoToken, + spnegoTokenLength, + NULL, + NULL, + &mechToken, + &mechTokenLength, + NULL, + NULL)) { + free(spnegoToken); + spnegoToken = NULL; + infof(conn->data, "Parse SPNEGO Target Token failed\n"); + } + else { + free(input_token.value); + input_token.value = NULL; + input_token.value = malloc(mechTokenLength); + memcpy(input_token.value, mechToken,mechTokenLength); + input_token.length = mechTokenLength; + free(mechToken); + mechToken = NULL; + infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); + } + } +#endif + } + + major_status = gss_init_sec_context(&minor_status, + GSS_C_NO_CREDENTIAL, + &neg_ctx->context, + neg_ctx->server_name, + GSS_C_NO_OID, + GSS_C_DELEG_FLAG, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + NULL, + &output_token, + NULL, + NULL); + if (input_token.length > 0) + gss_release_buffer(&minor_status2, &input_token); + neg_ctx->status = major_status; + if (GSS_ERROR(major_status)) { + /* Curl_cleanup_negotiate(conn->data) ??? */ + log_gss_error(conn, minor_status, + (char *)"gss_init_sec_context() failed: "); + return -1; + } + + if (output_token.length == 0) { + return -1; + } + + neg_ctx->output_token = output_token; + /* conn->bits.close = FALSE; */ + + return 0; +} + + +CURLcode Curl_output_negotiate(struct connectdata *conn) +{ + struct negotiatedata *neg_ctx = &conn->data->state.negotiate; + OM_uint32 minor_status; + char *encoded = NULL; + int len; + +#ifdef HAVE_SPNEGO /* Handle SPNEGO */ + if (checkprefix("Negotiate",neg_ctx->protocol)) { + ASN1_OBJECT * object = NULL; + int rc = 1; + unsigned char * spnegoToken = NULL; + size_t spnegoTokenLength = 0; + unsigned char * responseToken = NULL; + size_t responseTokenLength = 0; + + responseToken = malloc(neg_ctx->output_token.length); + if ( responseToken == NULL) + return CURLE_OUT_OF_MEMORY; + memcpy(responseToken, neg_ctx->output_token.value, + neg_ctx->output_token.length); + responseTokenLength = neg_ctx->output_token.length; + + object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1); + if (!makeSpnegoInitialToken (object, + responseToken, + responseTokenLength, + &spnegoToken, + &spnegoTokenLength)) { + free(responseToken); + responseToken = NULL; + infof(conn->data, "Make SPNEGO Initial Token failed\n"); + } + else { + free(neg_ctx->output_token.value); + responseToken = NULL; + neg_ctx->output_token.value = malloc(spnegoTokenLength); + memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength); + neg_ctx->output_token.length = spnegoTokenLength; + free(spnegoToken); + spnegoToken = NULL; + infof(conn->data, "Make SPNEGO Initial Token succeeded\n"); + } + } +#endif + len = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded); + + if (len < 0) + return CURLE_OUT_OF_MEMORY; + + conn->allocptr.userpwd = + aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded); + free(encoded); + gss_release_buffer(&minor_status, &neg_ctx->output_token); + return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; +} + +void Curl_cleanup_negotiate(struct SessionHandle *data) +{ + OM_uint32 minor_status; + struct negotiatedata *neg_ctx = &data->state.negotiate; + + if (neg_ctx->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); + + if (neg_ctx->output_token.length != 0) + gss_release_buffer(&minor_status, &neg_ctx->output_token); + + if (neg_ctx->server_name != GSS_C_NO_NAME) + gss_release_name(&minor_status, &neg_ctx->server_name); + + memset(neg_ctx, 0, sizeof(*neg_ctx)); +} + + +#endif +#endif |