diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.am | 2 | ||||
| -rw-r--r-- | lib/http.c | 8 | ||||
| -rw-r--r-- | lib/http_negotiate.c | 217 | ||||
| -rw-r--r-- | lib/http_negotiate.h | 39 | ||||
| -rw-r--r-- | lib/transfer.c | 17 | ||||
| -rw-r--r-- | lib/url.c | 9 | ||||
| -rw-r--r-- | lib/urldata.h | 20 | 
7 files changed, 311 insertions, 1 deletions
| diff --git a/lib/Makefile.am b/lib/Makefile.am index b17bac198..64cfaa74f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -68,7 +68,7 @@ strequal.h easy.c security.h security.c krb4.c krb4.h memdebug.c	\  memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c strtok.h	\  connect.c connect.h llist.c llist.h hash.c hash.h multi.c		\  content_encoding.c content_encoding.h share.c share.h http_digest.c \ -md5.c md5.h http_digest.h +md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h  noinst_HEADERS = setup.h transfer.h diff --git a/lib/http.c b/lib/http.c index 16a87d937..e5d2b49d3 100644 --- a/lib/http.c +++ b/lib/http.c @@ -688,6 +688,14 @@ CURLcode Curl_http(struct connectdata *conn)      conn->allocptr.uagent=NULL;    } +#ifdef GSSAPI +  if (data->state.negotiate.context &&  +      !GSS_ERROR(data->state.negotiate.status)) { +     result = Curl_output_negotiate(conn); +     if (result) +	return result; +  } else +#endif    if(data->state.digest.nonce) {      result = Curl_output_digest(conn,                                  (unsigned char *)request, diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c new file mode 100644 index 000000000..9a2d46a1f --- /dev/null +++ b/lib/http_negotiate.c @@ -0,0 +1,217 @@ +/*************************************************************************** + *                                  _   _ ____  _      + *  Project                     ___| | | |  _ \| |     + *                             / __| | | | |_) | |     + *                            | (__| |_| |  _ <| |___  + *                             \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, 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 GSSAPI + +#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 "http_negotiate.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#ifdef MALLOCDEBUG +#include "memdebug.h" +#endif + +static int +get_gss_name(struct connectdata *conn, gss_name_t *server) +{ +  OM_uint32 major_status, minor_status; +  gss_buffer_desc token = GSS_C_EMPTY_BUFFER; +  char name[2048]; + +#ifdef KRB5 +  token.length = strlen("khttp@") + strlen(conn->hostname) + 1; +#els +  token.length = strlen("host/") + strlen(conn->hostname) + 1; +#endif +  if (token.length + 1 > sizeof(name)) +    return EMSGSIZE; +#ifdef KRB5 +  sprintf(name, "khttp@%s", conn->hostname); +#else +  sprintf(name, "host/%s", conn->hostname); +#endif +  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) { +      sprintf(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, buf); +} + +CURLcode 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; + +  while(*header && isspace((int)*header)) +    header++; +  if(!checkprefix("GSS-Negotiate", header)) +    return -1; + +  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("GSS-Negotiate"); +  while(*header && isspace((int)*header)) +    header++; + +  len = strlen(header); +  if (len > 0) { +    input_token.length = (len+3)/4 * 3; +    input_token.value = malloc(input_token.length); +    if (input_token.value == NULL) +      return ENOMEM; +    input_token.length = Curl_base64_decode(header, input_token.value); +    if (input_token.length < 0) +      return -1; +  } + +  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, "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; +  size_t len; +   +  len = Curl_base64_encode(neg_ctx->output_token.value, +                           neg_ctx->output_token.length, +                           &encoded); +  if (len < 0) +    return -1; + +  conn->allocptr.userpwd = +    aprintf("Authorization: GSS-Negotiate %s\r\n", encoded); +  free(encoded); +  gss_release_buffer(&minor_status, &neg_ctx->output_token); +  return (conn->allocptr.userpwd == NULL) ? ENOMEM : 0; +} + +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 diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h new file mode 100644 index 000000000..09141bda7 --- /dev/null +++ b/lib/http_negotiate.h @@ -0,0 +1,39 @@ +#ifndef __HTTP_NEGOTIATE_H +#define __HTTP_NEGOTIATE_H + +/*************************************************************************** + *                                  _   _ ____  _      + *  Project                     ___| | | |  _ \| |     + *                             / __| | | | |_) | |     + *                            | (__| |_| |  _ <| |___  + *                             \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, 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$ + ***************************************************************************/ + +#ifdef GSSAPI + +/* this is for Negotiate header input */ +CURLcode Curl_input_negotiate(struct connectdata *conn, char *header); + +/* this is for creating Negotiate header output */ +CURLcode Curl_output_negotiate(struct connectdata *conn); + +void Curl_cleanup_negotiate(struct SessionHandle *data); + +#endif + +#endif diff --git a/lib/transfer.c b/lib/transfer.c index 6571e1636..2eda08889 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -96,6 +96,9 @@  #include "getinfo.h"  #include "ssluse.h"  #include "http_digest.h" +#ifdef GSSAPI +#include "http_negotiate.h" +#endif  #define _MPRINTF_REPLACE /* use our functions only */  #include <curl/mprintf.h> @@ -719,6 +722,20 @@ CURLcode Curl_readwrite(struct connectdata *conn,                if(data->set.get_filetime)                  data->info.filetime = k->timeofdoc;              } +#ifdef GSSAPI +	    else if (Curl_compareheader(k->p, "WWW-Authenticate:", +                                        "GSS-Negotiate") && +		     (401 == k->httpcode) && +		     data->set.httpnegotiate) { +	      int neg; + +	      neg = Curl_input_negotiate(conn, +		    			 k->p+strlen("WWW-Authenticate:")); +	      if (neg == 0) +                /* simulate redirection to make curl send the request again */ +                conn->newurl = strdup(data->change.url); +	    } +#endif              else if(checkprefix("WWW-Authenticate:", k->p) &&                      (401 == k->httpcode) &&                      data->set.httpdigest /* Digest authentication is  @@ -108,6 +108,9 @@  #include "share.h"  #include "content_encoding.h"  #include "http_digest.h" +#ifdef GSSAPI +#include "http_negotiate.h" +#endif  /* And now for the protocols */  #include "ftp.h" @@ -847,6 +850,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)       */      data->set.httpdigest = va_arg(param, long);      break; +#ifdef GSSAPI +  case CURLOPT_HTTPNEGOTIATE: +    /* Enable HTTP Negotaiate authentication */ +    data->set.httpnegotiate = va_arg(param, long); +    break; +#endif    case CURLOPT_USERPWD:      /*       * user:password to use in the operation diff --git a/lib/urldata.h b/lib/urldata.h index 58f700677..4dbd4092a 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -86,6 +86,10 @@  #include <zlib.h> 		/* for content-encoding 08/28/02 jhrg */  #endif +#ifdef GSSAPI +#include <gssapi.h> +#endif +  /* Download buffer size, keep it fairly big for speed reasons */  #define BUFSIZE CURL_MAX_WRITE_SIZE @@ -160,6 +164,15 @@ struct digestdata {    int algo;  }; +#ifdef GSSAPI +struct negotiatedata { +  OM_uint32 status; +  gss_ctx_id_t context; +  gss_name_t server_name; +  gss_buffer_desc output_token; +}; +#endif +  /****************************************************************************   * HTTP unique setup   ***************************************************************************/ @@ -627,6 +640,10 @@ struct UrlState {                        is always set TRUE when curl_easy_perform() is called. */    struct digestdata digest; + +#ifdef GSSAPI +  struct negotiatedata negotiate; +#endif  }; @@ -672,6 +689,9 @@ struct UserDefined {    long use_port;     /* which port to use (when not using default) */    char *userpwd;     /* <user:password>, if used */    bool httpdigest;   /* if HTTP Digest is enabled */ +#ifdef GSSAPI +  bool httpnegotiate; /* if HTTP Negotiate authentication is enabled */ +#endif    char *set_range;   /* range, if used. See README for detailed specification                          on this syntax. */    long followlocation; /* as in HTTP Location: */ | 
