예제 #1
0
파일: getpart.c 프로젝트: 1498636925/curl
static int appenddata(char  **dst_buf,   /* dest buffer */
                      size_t *dst_len,   /* dest buffer data length */
                      size_t *dst_alloc, /* dest buffer allocated size */
                      char   *src_buf,   /* source buffer */
                      int     src_b64)   /* != 0 if source is base64 encoded */
{
  size_t need_alloc, src_len;
  union {
    unsigned char *as_uchar;
             char *as_char;
  } buf64;

  src_len = strlen(src_buf);
  if(!src_len)
    return GPE_OK;

  buf64.as_char = NULL;

  if(src_b64) {
    /* base64 decode the given buffer */
    src_len = Curl_base64_decode(src_buf, &buf64.as_uchar);
    src_buf = buf64.as_char;
    if(!src_len || !src_buf) {
      /*
      ** currently there is no way to tell apart an OOM condition in
      ** Curl_base64_decode() from zero length decoded data. For now,
      ** let's just assume it is an OOM condition, currently we have
      ** no input for this function that decodes to zero length data.
      */
      if(buf64.as_char)
        free(buf64.as_char);
      return GPE_OUT_OF_MEMORY;
    }
  }

  need_alloc = src_len + *dst_len + 1;

  /* enlarge destination buffer if required */
  if(need_alloc > *dst_alloc) {
    size_t newsize = need_alloc * 2;
    char *newptr = realloc(*dst_buf, newsize);
    if(!newptr) {
      if(buf64.as_char)
        free(buf64.as_char);
      return GPE_OUT_OF_MEMORY;
    }
    *dst_alloc = newsize;
    *dst_buf = newptr;
  }

  /* memcpy to support binary blobs */
  memcpy(*dst_buf + *dst_len, src_buf, src_len);
  *dst_len += src_len;
  *(*dst_buf + *dst_len) = '\0';

  if(buf64.as_char)
    free(buf64.as_char);

  return GPE_OK;
}
예제 #2
0
/*
* Curl_sasl_decode_ntlm_type2_message()
*
* This is used to decode an already encoded NTLM type-2 message.
*
* Parameters:
*
* data     [in]     - The session handle.
* type2msg [in]     - The base64 encoded type-2 message.
* ntlm     [in/out] - The ntlm data struct being used and modified.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
                                             const char *type2msg,
                                             struct ntlmdata *ntlm)
{
  CURLcode result = CURLE_OK;
  unsigned char *type2 = NULL;
  size_t type2_len = 0;

#if defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) data;
#endif

  /* Decode the base-64 encoded type-2 message */
  if(strlen(type2msg) && *type2msg != '=') {
    result = Curl_base64_decode(type2msg, &type2, &type2_len);
    if(result)
      return result;
  }

  /* Ensure we have a valid type-2 message */
  if(!type2) {
    infof(data, "NTLM handshake failure (empty type-2 message)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Simply store the challenge for use later */
  ntlm->input_token = type2;
  ntlm->input_token_len = type2_len;

  return result;
}
예제 #3
0
int
Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
{
  int len;
  unsigned char *buf;
  int code;

  len = Curl_base64_decode(s + 4, &buf); /* XXX */
  if(len > 0)
    len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
  else
    return -1;

  if(len < 0) {
    free(buf);
    return -1;
  }

  buf[len] = '\0';

  if(buf[3] == '-')
    code = 0;
  else
    sscanf((char *)buf, "%d", &code);
  if(buf[len-1] == '\n')
    buf[len-1] = '\0';
  strcpy(s, (char *)buf);
  free(buf);
  return code;
}
예제 #4
0
int
Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
{
    int len;
    char *buf;
    int code;
    
    buf = malloc(strlen(s));
    len = Curl_base64_decode(s + 4, buf); /* XXX */
    
    len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
    if(len < 0)
	return -1;
    
    buf[len] = '\0';

    if(buf[3] == '-')
	code = 0;
    else
	sscanf(buf, "%d", &code);
    if(buf[len-1] == '\n')
	buf[len-1] = '\0';
    strcpy(s, buf);
    free(buf);
    return code;
}
예제 #5
0
int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
                      enum protection_level level)
{
  /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
     int */
  int decoded_len;
  char *buf;
  int ret_code = 0;
  size_t decoded_sz = 0;
  CURLcode error;

  if(!conn->mech)
    /* not inititalized, return error */
    return -1;

  DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);

  error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
  if(error || decoded_sz == 0)
    return -1;

  if(decoded_sz > (size_t)INT_MAX) {
    free(buf);
    return -1;
  }
  decoded_len = curlx_uztosi(decoded_sz);

  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
                                   level, conn);
  if(decoded_len <= 0) {
    free(buf);
    return -1;
  }

  if(conn->data->set.verbose) {
    buf[decoded_len] = '\n';
    Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1, conn);
  }

  buf[decoded_len] = '\0';
  if(decoded_len <= 3)
    /* suspiciously short */
    return 0;

  if(buf[3] != '-')
    /* safe to ignore return code */
    (void)sscanf(buf, "%d", &ret_code);

  if(buf[decoded_len - 1] == '\n')
    buf[decoded_len - 1] = '\0';
  /* FIXME: Is |buffer| length always greater than |decoded_len|? */
  strcpy(buffer, buf);
  free(buf);
  return ret_code;
}
예제 #6
0
파일: vtls.c 프로젝트: Necktrox/mtasa-blue
static CURLcode pubkey_pem_to_der(const char *pem,
                                  unsigned char **der, size_t *der_len)
{
  char *stripped_pem, *begin_pos, *end_pos;
  size_t pem_count, stripped_pem_count = 0, pem_len;
  CURLcode result;

  /* if no pem, exit. */
  if(!pem)
    return CURLE_BAD_CONTENT_ENCODING;

  begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
  if(!begin_pos)
    return CURLE_BAD_CONTENT_ENCODING;

  pem_count = begin_pos - pem;
  /* Invalid if not at beginning AND not directly following \n */
  if(0 != pem_count && '\n' != pem[pem_count - 1])
    return CURLE_BAD_CONTENT_ENCODING;

  /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
  pem_count += 26;

  /* Invalid if not directly following \n */
  end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
  if(!end_pos)
    return CURLE_BAD_CONTENT_ENCODING;

  pem_len = end_pos - pem;

  stripped_pem = malloc(pem_len - pem_count + 1);
  if(!stripped_pem)
    return CURLE_OUT_OF_MEMORY;

  /*
   * Here we loop through the pem array one character at a time between the
   * correct indices, and place each character that is not '\n' or '\r'
   * into the stripped_pem array, which should represent the raw base64 string
   */
  while(pem_count < pem_len) {
    if('\n' != pem[pem_count] && '\r' != pem[pem_count])
      stripped_pem[stripped_pem_count++] = pem[pem_count];
    ++pem_count;
  }
  /* Place the null terminator in the correct place */
  stripped_pem[stripped_pem_count] = '\0';

  result = Curl_base64_decode(stripped_pem, der, der_len);

  Curl_safefree(stripped_pem);

  return result;
}
예제 #7
0
파일: digest.c 프로젝트: 2px/curl
/*
 * auth_decode_digest_md5_message()
 *
 * This is used internally to decode an already encoded DIGEST-MD5 challenge
 * message into the seperate attributes.
 *
 * Parameters:
 *
 * chlg64  [in]     - The base64 encoded challenge message.
 * nonce   [in/out] - The buffer where the nonce will be stored.
 * nlen    [in]     - The length of the nonce buffer.
 * realm   [in/out] - The buffer where the realm will be stored.
 * rlen    [in]     - The length of the realm buffer.
 * alg     [in/out] - The buffer where the algorithm will be stored.
 * alen    [in]     - The length of the algorithm buffer.
 * qop     [in/out] - The buffer where the qop-options will be stored.
 * qlen    [in]     - The length of the qop buffer.
 *
 * Returns CURLE_OK on success.
 */
static CURLcode auth_decode_digest_md5_message(const char *chlg64,
                                               char *nonce, size_t nlen,
                                               char *realm, size_t rlen,
                                               char *alg, size_t alen,
                                               char *qop, size_t qlen)
{
  CURLcode result = CURLE_OK;
  unsigned char *chlg = NULL;
  size_t chlglen = 0;
  size_t chlg64len = strlen(chlg64);

  /* Decode the base-64 encoded challenge message */
  if(chlg64len && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!chlg)
    return CURLE_BAD_CONTENT_ENCODING;

  /* Retrieve nonce string from the challenge */
  if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen,
                                '\"')) {
    free(chlg);
    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Retrieve realm string from the challenge */
  if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen,
                                '\"')) {
    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
    strcpy(realm, "");
  }

  /* Retrieve algorithm string from the challenge */
  if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) {
    free(chlg);
    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Retrieve qop-options string from the challenge */
  if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) {
    free(chlg);
    return CURLE_BAD_CONTENT_ENCODING;
  }

  free(chlg);

  return CURLE_OK;
}
예제 #8
0
/*
 * Curl_sasl_create_cram_md5_message()
 *
 * This is used to generate an already encoded CRAM-MD5 response message ready
 * for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - Pointer to the base64 encoded challenge buffer.
 * userp   [in]     - The user name.
 * passdwp [in]     - The user's password.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
                                           const char* chlg64,
                                           const char* userp,
                                           const char* passwdp,
                                           char **outptr, size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlg64len = strlen(chlg64);
  unsigned char *chlg = (unsigned char *) NULL;
  size_t chlglen = 0;
  HMAC_context *ctxt;
  unsigned char digest[MD5_DIGEST_LEN];
  char response[MAX_CURL_USER_LENGTH + 2 * MD5_DIGEST_LEN + 1];

  /* Decode the challenge if necessary */
  if(chlg64len && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &chlg, &chlglen);

    if(result)
      return result;
  }

  /* Compute the digest using the password as the key */
  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
                        (const unsigned char *) passwdp,
                        curlx_uztoui(strlen(passwdp)));

  if(!ctxt) {
    Curl_safefree(chlg);
    return CURLE_OUT_OF_MEMORY;
  }

  /* Update the digest with the given challenge */
  if(chlglen > 0)
    Curl_HMAC_update(ctxt, chlg, curlx_uztoui(chlglen));

  Curl_safefree(chlg);

  /* Finalise the digest */
  Curl_HMAC_final(ctxt, digest);

  /* Prepare the response */
  snprintf(response, sizeof(response),
      "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
           userp, digest[0], digest[1], digest[2], digest[3], digest[4],
           digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
           digest[11], digest[12], digest[13], digest[14], digest[15]);

  /* Base64 encode the reply */
  return Curl_base64_encode(data, response, 0, outptr, outlen);
}
예제 #9
0
static
char *appendstring(char *string, /* original string */
                   char *buffer, /* to append */
                   size_t *stringlen, /* length of string */
                   size_t *stralloc,  /* allocated size */
                   char base64) /* 1 if base64 encoded */
{
  union {
    unsigned char * as_uchar;
             char * as_char;
  } buf64;

  size_t len = strlen(buffer);
  size_t needed_len = len + *stringlen + 1;

  buf64.as_char = NULL;

  if(base64) {
    /* decode the given buffer first */
    len = Curl_base64_decode(buffer, &buf64.as_uchar); /* updated len */
    buffer = buf64.as_char;
    needed_len = len + *stringlen + 1; /* recalculate */
  }

  if(needed_len >= *stralloc) {
    char *newptr;
    size_t newsize = needed_len*2; /* get twice the needed size */

    newptr = realloc(string, newsize);
    if(newptr) {
      string = newptr;
      *stralloc = newsize;
    }
    else {
      if(buf64.as_char)
        free(buf64.as_char);
      return NULL;
    }
  }
  /* memcpy to support binary blobs */
  memcpy(&string[*stringlen], buffer, len);
  *stringlen += len;
  string[*stringlen]=0;

  if(buf64.as_char)
    free(buf64.as_char);

  return string;
}
예제 #10
0
파일: cram.c 프로젝트: dustymabe/curl
/*
 * sasl_decode_cram_md5_message()
 *
 * This is used to decode an already encoded CRAM-MD5 challenge message.
 *
 * Parameters:
 *
 * chlg64  [in]     - The base64 encoded challenge message.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr,
                                      size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlg64len = strlen(chlg64);

  *outptr = NULL;
  *outlen = 0;

  /* Decode the challenge if necessary */
  if(chlg64len && *chlg64 != '=')
    result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);

  return result;
}
예제 #11
0
static int decodedata(char  **buf,   /* dest buffer */
                      size_t *len)   /* dest buffer data length */
{
  int error = 0;
  unsigned char *buf64 = NULL;
  size_t src_len = 0;

  if(!*len)
    return GPE_OK;

  /* base64 decode the given buffer */
  error = (int) Curl_base64_decode(*buf, &buf64, &src_len);
  if(error)
    return GPE_OUT_OF_MEMORY;

  if(!src_len) {
    /*
    ** currently there is no way to tell apart an OOM condition in
    ** Curl_base64_decode() from zero length decoded data. For now,
    ** let's just assume it is an OOM condition, currently we have
    ** no input for this function that decodes to zero length data.
    */
    free(buf64);

    return GPE_OUT_OF_MEMORY;
  }

  /* memcpy to support binary blobs */
  memcpy(*buf, buf64, src_len);
  *len = src_len;
  *(*buf + src_len) = '\0';

  free(buf64);

  return GPE_OK;
}
예제 #12
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)
{
  struct SessionHandle *data = conn->data;
  struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg:
    &data->state.negotiate;
  OM_uint32 major_status, minor_status, discard_st, min_stat;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  int ret;
  size_t len;
  size_t rawlen = 0;
  bool gss;
  const char* protocol;
  CURLcode error;

  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 successfully 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(data);
    return -1;
  }

	if(neg_ctx->server_name == NULL &&
	  (ret = get_gss_name(conn, proxy, &neg_ctx->server_name)))
	return ret;
  	
  header += strlen(neg_ctx->protocol);
  while(*header && ISSPACE(*header))
    header++;

  len = strlen(header);
  if(len > 0) {
    error = Curl_base64_decode(header,
                               (unsigned char **)&input_token.value, &rawlen);
    if(error || rawlen == 0)
      return -1;
    input_token.length = rawlen;

    DEBUGASSERT(input_token.value != NULL);

#ifdef HAVE_SPNEGO /* Handle SPNEGO */
    if(checkprefix("Negotiate", header)) {
      unsigned char  *spnegoToken       = NULL;
      size_t          spnegoTokenLength = 0;
      gss_buffer_desc mechToken         = GSS_C_EMPTY_BUFFER;

      spnegoToken = malloc(input_token.length);
      if(spnegoToken == NULL) {
        Curl_safefree(input_token.value);
        return CURLE_OUT_OF_MEMORY;
      }
      memcpy(spnegoToken, input_token.value, input_token.length);
      spnegoTokenLength = input_token.length;

      if(!parseSpnegoTargetToken(spnegoToken,
                                 spnegoTokenLength,
                                 NULL,
                                 NULL,
                                 (unsigned char**)&mechToken.value,
                                 &mechToken.length,
                                 NULL,
                                 NULL)) {
        Curl_safefree(spnegoToken);
        infof(data, "Parse SPNEGO Target Token failed\n");
      }
      else if(!mechToken.value || !mechToken.length) {
        Curl_safefree(spnegoToken);
        if(mechToken.value)
          gss_release_buffer(&discard_st, &mechToken);
        infof(data, "Parse SPNEGO Target Token succeeded (NULL token)\n");
      }
      else {
        Curl_safefree(spnegoToken);
        Curl_safefree(input_token.value);
        input_token.value = malloc(mechToken.length);
        if(input_token.value == NULL) {
          gss_release_buffer(&discard_st, &mechToken);
          return CURLE_OUT_OF_MEMORY;
        }
        memcpy(input_token.value, mechToken.value, mechToken.length);
        input_token.length = mechToken.length;
        gss_release_buffer(&discard_st, &mechToken);
        infof(data, "Parse SPNEGO Target Token succeeded\n");
      }
    }
#endif
  }

  major_status = Curl_gss_init_sec_context(conn,
                                           &minor_status,
                                           &neg_ctx->context,
                                           neg_ctx->server_name,
                                           GSS_C_NO_CHANNEL_BINDINGS,
                                           &input_token,
                                           &output_token,
                                           NULL);
  gss_release_cred(&min_stat, &conn->data->curl_gss_creds);
  Curl_safefree(input_token.value);
  /*To remove the memory leak issue*/
  if(neg_ctx->server_name != GSS_C_NO_NAME)
    gss_release_name(&min_stat, &neg_ctx->server_name);

  neg_ctx->status = major_status;
  if(GSS_ERROR(major_status)) {
    if(output_token.value)
      gss_release_buffer(&discard_st, &output_token);
    log_gss_error(conn, minor_status, "KRB5_ERROR: gss_init_sec_context() failed: ");
	printf("\n KRB5_ERROR: gss_init_sec_context() failed error code : %d", minor_status);
    return -1;
  }

  if(!output_token.value || !output_token.length) {
    if(output_token.value)
      gss_release_buffer(&discard_st, &output_token);
    return -1;
  }

  neg_ctx->output_token = output_token;
  return 0;
}
예제 #13
0
/* for AUTH CRAM-MD5 responses. */
static CURLcode smtp_state_authcram_resp(struct connectdata *conn,
        int smtpcode,
        smtpstate instate)
{
    CURLcode result = CURLE_OK;
    struct SessionHandle *data = conn->data;
    char * chlg64 = data->state.buffer;
    unsigned char * chlg;
    size_t chlglen;
    size_t l;
    char * rplyb64;
    HMAC_context * ctxt;
    unsigned char digest[16];
    char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1];

    (void)instate; /* no use for this yet */

    if(smtpcode != 334) {
        failf(data, "Access denied: %d", smtpcode);
        return CURLE_LOGIN_DENIED;
    }

    /* Get the challenge. */
    for (chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
        ;

    chlg = (unsigned char *) NULL;
    chlglen = 0;

    if(*chlg64 != '=') {
        for (l = strlen(chlg64); l--;)
            if(chlg64[l] != '\r' && chlg64[l] != '\n' && chlg64[l] != ' ' &&
                    chlg64[l] != '\t')
                break;

        if(++l) {
            chlg64[l] = '\0';

            if(!(chlglen = Curl_base64_decode(chlg64, &chlg)))
                return CURLE_OUT_OF_MEMORY;
        }
    }

    /* Compute digest. */
    ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
                          (const unsigned char *) conn->passwd,
                          (unsigned int)(strlen(conn->passwd)));

    if(!ctxt) {
        if(chlg)
            free(chlg);

        return CURLE_OUT_OF_MEMORY;
    }

    if(chlglen > 0)
        Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen));

    if(chlg)
        free(chlg);

    Curl_HMAC_final(ctxt, digest);

    /* Prepare the reply. */
    snprintf(reply, sizeof reply,
             "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
             conn->user, digest[0], digest[1], digest[2], digest[3], digest[4], digest[5],
             digest[6], digest[7], digest[8], digest[9], digest[10], digest[11],
             digest[12], digest[13], digest[14], digest[15]);

    /* Encode it to base64 and send it. */
    l = Curl_base64_encode(data, reply, 0, &rplyb64);

    if(!l)
        result = CURLE_OUT_OF_MEMORY;
    else {
        result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
        free(rplyb64);

        if(!result)
            state(conn, SMTP_AUTH);
    }

    return result;
}
예제 #14
0
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;
}
예제 #15
0
파일: spnego_gssapi.c 프로젝트: fzls/curl
/*
 * Curl_auth_decode_spnego_message()
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * 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 www, smtp, pop or imap.
 * host        [in]     - The host name.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data,
                                         const char *user,
                                         const char *password,
                                         const char *service,
                                         const char *host,
                                         const char *chlg64,
                                         struct negotiatedata *nego)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  unsigned char *chlg = NULL;
  OM_uint32 major_status;
  OM_uint32 minor_status;
  OM_uint32 unused_status;
  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

  (void) user;
  (void) password;

  if(nego->context && nego->status == GSS_S_COMPLETE) {
    /* We finished successfully 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_auth_spnego_cleanup(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    char *spn = Curl_auth_build_spn(service, NULL, host);
    if(!spn)
      return CURLE_OUT_OF_MEMORY;

    /* Populate the SPN structure */
    spn_token.value = spn;
    spn_token.length = strlen(spn);

    /* Import the SPN */
    major_status = gss_import_name(&minor_status, &spn_token,
                                   GSS_C_NT_HOSTBASED_SERVICE,
                                   &nego->spn);
    if(GSS_ERROR(major_status)) {
      Curl_gss_log_error(data, "gss_import_name() failed: ",
                         major_status, minor_status);

      free(spn);

      return CURLE_OUT_OF_MEMORY;
    }

    free(spn);
  }

  if(chlg64 && *chlg64) {
    /* Decode the base-64 encoded challenge message */
    if(*chlg64 != '=') {
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }

    /* Ensure we have a valid challenge message */
    if(!chlg) {
      infof(data, "SPNEGO handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    /* Setup the challenge "input" security buffer */
    input_token.value = chlg;
    input_token.length = chlglen;
  }

  /* Generate our challenge-response message */
  major_status = Curl_gss_init_sec_context(data,
                                           &minor_status,
                                           &nego->context,
                                           nego->spn,
                                           &Curl_spnego_mech_oid,
                                           GSS_C_NO_CHANNEL_BINDINGS,
                                           &input_token,
                                           &output_token,
                                           TRUE,
                                           NULL);

  /* Free the decoded challenge as it is not required anymore */
  Curl_safefree(input_token.value);

  nego->status = major_status;
  if(GSS_ERROR(major_status)) {
    if(output_token.value)
      gss_release_buffer(&unused_status, &output_token);

    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
                       major_status, minor_status);

    return CURLE_OUT_OF_MEMORY;
  }

  if(!output_token.value || !output_token.length) {
    if(output_token.value)
      gss_release_buffer(&unused_status, &output_token);

    return CURLE_OUT_OF_MEMORY;
  }

  nego->output_token = output_token;

  return CURLE_OK;
}
예제 #16
0
static int
krb4_auth(void *app_data, struct connectdata *conn)
{
  int ret;
  char *p;
  unsigned char *ptr;
  size_t len;
  KTEXT_ST adat;
  MSG_DAT msg_data;
  int checksum;
  u_int32_t cs;
  struct krb4_data *d = app_data;
  char *host = conn->host.name;
  ssize_t nread;
  int l = sizeof(conn->local_addr);
  struct SessionHandle *data = conn->data;
  CURLcode result;

  if(getsockname(conn->sock[FIRSTSOCKET],
                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
    perror("getsockname()");

  checksum = getpid();
  ret = mk_auth(d, &adat, "ftp", host, checksum);
  if(ret == KDC_PR_UNKNOWN)
    ret = mk_auth(d, &adat, "rcmd", host, checksum);
  if(ret) {
    infof(data, "%s\n", krb_get_err_text(ret));
    return AUTH_CONTINUE;
  }

#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
  if(krb_get_config_bool("nat_in_use")) {
    struct sockaddr_in *localaddr  = (struct sockaddr_in *)LOCAL_ADDR;
    struct in_addr natAddr;

    if(krb_get_our_ip_for_realm(krb_realmofhost(host),
                                 &natAddr) != KSUCCESS
        && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
      infof(data, "Can't get address for realm %s\n",
                 krb_realmofhost(host));
    else {
      if(natAddr.s_addr != localaddr->sin_addr.s_addr) {
        char addr_buf[128];
        if(Curl_inet_ntop(AF_INET, natAddr, addr_buf, sizeof(addr_buf)))
          infof(data, "Using NAT IP address (%s) for kerberos 4\n", addr_buf);
        localaddr->sin_addr = natAddr;
      }
    }
  }
#endif

  if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) {
    Curl_failf(data, "Out of memory base64-encoding");
    return AUTH_CONTINUE;
  }

  result = Curl_ftpsendf(conn, "ADAT %s", p);

  free(p);

  if(result)
    return -2;

  if(Curl_GetFTPResponse(&nread, conn, NULL))
    return -1;

  if(data->state.buffer[0] != '2'){
    Curl_failf(data, "Server didn't accept auth data");
    return AUTH_ERROR;
  }

  p = strstr(data->state.buffer, "ADAT=");
  if(!p) {
    Curl_failf(data, "Remote host didn't send adat reply");
    return AUTH_ERROR;
  }
  p += 5;
  len = Curl_base64_decode(p, &ptr);
  if(len > sizeof(adat.dat)-1) {
    free(ptr);
    len=0;
  }
  if(!len || !ptr) {
    Curl_failf(data, "Failed to decode base64 from server");
    return AUTH_ERROR;
  }
  memcpy((char *)adat.dat, ptr, len);
  free(ptr);
  adat.length = len;
  ret = krb_rd_safe(adat.dat, adat.length, &d->key,
                    (struct sockaddr_in *)hisctladdr,
                    (struct sockaddr_in *)myctladdr, &msg_data);
  if(ret) {
    Curl_failf(data, "Error reading reply from server: %s",
               krb_get_err_text(ret));
    return AUTH_ERROR;
  }
  krb_get_int(msg_data.app_data, &cs, 4, 0);
  if(cs - checksum != 1) {
    Curl_failf(data, "Bad checksum returned from server");
    return AUTH_ERROR;
  }
  return AUTH_OK;
}
예제 #17
0
파일: krb5.c 프로젝트: 0w/moai-dev
static int
krb5_auth(void *app_data, struct connectdata *conn)
{
  int ret;
  char *p;
  const char *host = conn->dns_entry->addr->ai_canonname;
  ssize_t nread;
  curl_socklen_t l = sizeof(conn->local_addr);
  struct SessionHandle *data = conn->data;
  CURLcode result;
  const char *service = "ftp", *srv_host = "host";
  gss_buffer_desc gssbuf, _gssresp, *gssresp;
  OM_uint32 maj, min;
  gss_name_t gssname;
  gss_ctx_id_t *context = app_data;
  struct gss_channel_bindings_struct chan;

  if(getsockname(conn->sock[FIRSTSOCKET],
                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
    perror("getsockname()");

  chan.initiator_addrtype = GSS_C_AF_INET;
  chan.initiator_address.length = l - 4;
  chan.initiator_address.value =
    &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr;
  chan.acceptor_addrtype = GSS_C_AF_INET;
  chan.acceptor_address.length = l - 4;
  chan.acceptor_address.value =
    &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr;
  chan.application_data.length = 0;
  chan.application_data.value = NULL;

  /* this loop will execute twice (once for service, once for host) */
  while(1) {
    /* this really shouldn't be repeated here, but can't help it */
    if(service == srv_host) {
      result = Curl_ftpsendf(conn, "AUTH GSSAPI");

      if(result)
        return -2;
      if(Curl_GetFTPResponse(&nread, conn, NULL))
        return -1;

      if(data->state.buffer[0] != '3')
        return -1;
    }

    gssbuf.value = data->state.buffer;
    gssbuf.length = snprintf(gssbuf.value, BUFSIZE, "%s@%s", service, host);
    maj = gss_import_name(&min, &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &gssname);
    if(maj != GSS_S_COMPLETE) {
      gss_release_name(&min, &gssname);
      if(service == srv_host) {
        Curl_failf(data, "Error importing service name %s", gssbuf.value);
        return AUTH_ERROR;
      }
      service = srv_host;
      continue;
    }
    {
      gss_OID t;
      gss_display_name(&min, gssname, &gssbuf, &t);
      Curl_infof(data, "Trying against %s\n", gssbuf.value);
      gss_release_buffer(&min, &gssbuf);
    }
    gssresp = GSS_C_NO_BUFFER;
    *context = GSS_C_NO_CONTEXT;

    do {
      ret = AUTH_OK;
      maj = gss_init_sec_context(&min,
                                 GSS_C_NO_CREDENTIAL,
                                 context,
                                 gssname,
                                 GSS_C_NO_OID,
                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
                                 0,
                                 &chan,
                                 gssresp,
                                 NULL,
                                 &gssbuf,
                                 NULL,
                                 NULL);

      if(gssresp) {
        free(_gssresp.value);
        gssresp = NULL;
      }

      if(maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
        Curl_infof(data, "Error creating security context");
        ret = AUTH_ERROR;
        break;
      }

      if(gssbuf.length != 0) {
        if(Curl_base64_encode(data, (char *)gssbuf.value, gssbuf.length, &p)
           < 1) {
          Curl_infof(data, "Out of memory base64-encoding");
          ret = AUTH_CONTINUE;
          break;
        }

        result = Curl_ftpsendf(conn, "ADAT %s", p);

        free(p);

        if(result) {
          ret = -2;
          break;
        }

        if(Curl_GetFTPResponse(&nread, conn, NULL)) {
          ret = -1;
          break;
        }

        if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){
          Curl_infof(data, "Server didn't accept auth data\n");
          ret = AUTH_ERROR;
          break;
        }

        p = data->state.buffer + 4;
        p = strstr(p, "ADAT=");
        if(p) {
          _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **)
                                               &_gssresp.value);
          if(_gssresp.length < 1) {
            Curl_failf(data, "Out of memory base64-encoding");
            ret = AUTH_CONTINUE;
            break;
          }
        }

        gssresp = &_gssresp;
      }
    } while(maj == GSS_S_CONTINUE_NEEDED);

    gss_release_name(&min, &gssname);

    if(gssresp)
      free(_gssresp.value);

    if(ret == AUTH_OK || service == srv_host)
      return ret;

    service = srv_host;
  }
}
예제 #18
0
fail_unless( rc == 4 , "return code should be 4" );
verify_memory( output, "aWlp", 4);
Curl_safefree(output);

rc = Curl_base64_encode(data, "iiii", 4, &output);
fail_unless( rc == 8 , "return code should be 8" );
verify_memory( output, "aWlpaQ==", 8);
Curl_safefree(output);

/* 0 length makes it do strlen() */
rc = Curl_base64_encode(data, "iiii", 0, &output);
fail_unless( rc == 8 , "return code should be 8" );
verify_memory( output, "aWlpaQ==", 8);
Curl_safefree(output);

rc = Curl_base64_decode("aWlpaQ==", &decoded);
fail_unless(rc == 4, "return code should be 4");
verify_memory(decoded, "iiii", 4);
Curl_safefree(decoded);

rc = Curl_base64_decode("aWlp", &decoded);
fail_unless(rc == 3, "return code should be 3");
verify_memory(decoded, "iii", 3);
Curl_safefree(decoded);

rc = Curl_base64_decode("aWk=", &decoded);
fail_unless(rc == 2, "return code should be 2");
verify_memory(decoded, "ii", 2);
Curl_safefree(decoded);

rc = Curl_base64_decode("aQ==", &decoded);
예제 #19
0
/*
 * Curl_sasl_create_gssapi_user_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The user name.
 * passdwp     [in]     - The user's password.
 * service     [in]     - The service type such as www, smtp, pop or imap.
 * mutual_auth [in]     - Flag specifing whether or not mutual authentication
 *                        is enabled.
 * chlg64      [in]     - Pointer to the optional base64 encoded challenge
 *                        message.
 * krb5        [in/out] - The gssapi 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.
 * outlen      [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
                                              const char *userp,
                                              const char *passwdp,
                                              const char *service,
                                              const bool mutual_auth,
                                              const char *chlg64,
                                              struct kerberos5data *krb5,
                                              char **outptr, size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  unsigned char *chlg = NULL;
  OM_uint32 gss_status;
  OM_uint32 gss_major_status;
  OM_uint32 gss_minor_status;
  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

  (void) userp;
  (void) passwdp;

  if(krb5->context == GSS_C_NO_CONTEXT) {
    /* Generate our SPN */
    char *spn = Curl_sasl_build_gssapi_spn(service,
                                           data->easy_conn->host.name);
    if(!spn)
      return CURLE_OUT_OF_MEMORY;

    /* Populate the SPN structure */
    spn_token.value = spn;
    spn_token.length = strlen(spn);

    /* Import the SPN */
    gss_major_status = gss_import_name(&gss_minor_status, &spn_token,
                                       gss_nt_service_name, &krb5->spn);
    if(GSS_ERROR(gss_major_status)) {
      Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: ");

      return CURLE_OUT_OF_MEMORY;
    }
  }
  else {
    /* Decode the base-64 encoded challenge message */
    if(strlen(chlg64) && *chlg64 != '=') {
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }

    /* Ensure we have a valid challenge message */
    if(!chlg) {
      infof(data, "GSSAPI handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    /* Setup the challenge "input" security buffer */
    input_token.value = chlg;
    input_token.length = chlglen;
  }

  gss_major_status = Curl_gss_init_sec_context(data,
                                               &gss_minor_status,
                                               &krb5->context,
                                               krb5->spn,
                                               &Curl_krb5_mech_oid,
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               &input_token,
                                               &output_token,
                                               mutual_auth,
                                               NULL);

  Curl_safefree(input_token.value);

  if(GSS_ERROR(gss_major_status)) {
    if(output_token.value)
      gss_release_buffer(&gss_status, &output_token);

    Curl_gss_log_error(data, gss_minor_status,
                       "gss_init_sec_context() failed: ");

    return CURLE_RECV_ERROR;
  }

  if(output_token.value && output_token.length) {
    /* Base64 encode the response */
    result = Curl_base64_encode(data, (char *) output_token.value,
                                output_token.length, outptr, outlen);

    gss_release_buffer(&gss_status, &output_token);
  }

  return result;
}
예제 #20
0
CURLntlm Curl_input_ntlm(struct connectdata *conn,
                         bool proxy,   /* if proxy or not */
                         const char *header) /* rest of the www-authenticate:
                                                header */
{
  /* point to the correct struct with this */
  struct ntlmdata *ntlm;
#ifndef USE_WINDOWS_SSPI
  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
#endif

  ntlm = proxy?&conn->proxyntlm:&conn->ntlm;

  /* skip initial whitespaces */
  while(*header && ISSPACE(*header))
    header++;

  if(checkprefix("NTLM", header)) {
    header += strlen("NTLM");

    while(*header && ISSPACE(*header))
      header++;

    if(*header) {
      /* We got a type-2 message here:

         Index   Description         Content
         0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
                                     (0x4e544c4d53535000)
         8       NTLM Message Type   long (0x02000000)
         12      Target Name         security buffer(*)
         20      Flags               long
         24      Challenge           8 bytes
         (32)    Context (optional)  8 bytes (two consecutive longs)
         (40)    Target Information  (optional) security buffer(*)
         32 (48) start of data block
      */
      size_t size;
      unsigned char *buffer;
      size = Curl_base64_decode(header, &buffer);
      if(!buffer)
        return CURLNTLM_BAD;

      ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */

#ifdef USE_WINDOWS_SSPI
      ntlm->type_2 = malloc(size+1);
      if(ntlm->type_2 == NULL) {
        free(buffer);
        return CURLE_OUT_OF_MEMORY;
      }
      ntlm->n_type_2 = size;
      memcpy(ntlm->type_2, buffer, size);
#else
      ntlm->flags = 0;

      if((size < 32) ||
         (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
         (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
        /* This was not a good enough type-2 message */
        free(buffer);
        return CURLNTLM_BAD;
      }

      ntlm->flags = readint_le(&buffer[20]);
      memcpy(ntlm->nonce, &buffer[24], 8);

      DEBUG_OUT({
        fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
        print_flags(stderr, ntlm->flags);
        fprintf(stderr, "\n                  nonce=");
        print_hex(stderr, (char *)ntlm->nonce, 8);
        fprintf(stderr, "\n****\n");
        fprintf(stderr, "**** Header %s\n ", header);
      });
#endif
      free(buffer);
    }
예제 #21
0
파일: ntlm.c 프로젝트: Audifire/mtasa-blue
/*
 * Curl_auth_decode_ntlm_type2_message()
 *
 * This is used to decode an already encoded NTLM type-2 message. The message
 * is first decoded from a base64 string into a raw NTLM message and checked
 * for validity before the appropriate data for creating a type-3 message is
 * written to the given NTLM data structure.
 *
 * Parameters:
 *
 * data     [in]     - The session handle.
 * type2msg [in]     - The base64 encoded type-2 message.
 * ntlm     [in/out] - The NTLM data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
                                             const char *type2msg,
                                             struct ntlmdata *ntlm)
{
  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };

  /* NTLM type-2 message structure:

          Index  Description            Content
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
                                        (0x4e544c4d53535000)
            8    NTLM Message Type      long (0x02000000)
           12    Target Name            security buffer
           20    Flags                  long
           24    Challenge              8 bytes
          (32)   Context                8 bytes (two consecutive longs) (*)
          (40)   Target Information     security buffer (*)
          (48)   OS Version Structure   8 bytes (*)
  32 (48) (56)   Start of data block    (*)
                                        (*) -> Optional
  */

  CURLcode result = CURLE_OK;
  unsigned char *type2 = NULL;
  size_t type2_len = 0;

#if defined(NTLM_NEEDS_NSS_INIT)
  /* Make sure the crypto backend is initialized */
  result = Curl_nss_force_init(data);
  if(result)
    return result;
#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void)data;
#endif

  /* Decode the base-64 encoded type-2 message */
  if(strlen(type2msg) && *type2msg != '=') {
    result = Curl_base64_decode(type2msg, &type2, &type2_len);
    if(result)
      return result;
  }

  /* Ensure we have a valid type-2 message */
  if(!type2) {
    infof(data, "NTLM handshake failure (empty type-2 message)\n");
    return CURLE_BAD_CONTENT_ENCODING;
  }

  ntlm->flags = 0;

  if((type2_len < 32) ||
     (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
     (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
    /* This was not a good enough type-2 message */
    free(type2);
    infof(data, "NTLM handshake failure (bad type-2 message)\n");
    return CURLE_BAD_CONTENT_ENCODING;
  }

  ntlm->flags = Curl_read32_le(&type2[20]);
  memcpy(ntlm->nonce, &type2[24], 8);

  if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
    result = ntlm_decode_type2_target(data, type2, type2_len, ntlm);
    if(result) {
      free(type2);
      infof(data, "NTLM handshake failure (bad type-2 message)\n");
      return result;
    }
  }

  DEBUG_OUT({
    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
    ntlm_print_flags(stderr, ntlm->flags);
    fprintf(stderr, "\n                  nonce=");
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
    fprintf(stderr, "\n****\n");
    fprintf(stderr, "**** Header %s\n ", header);
  });
예제 #22
0
/*
 * Curl_sasl_create_digest_md5_message()
 *
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - Pointer to the base64 encoded challenge buffer.
 * userp   [in]     - The user name.
 * passdwp [in]     - The user's password.
 * service [in]     - The service type such as www, smtp or pop
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
                                             const char* chlg64,
                                             const char* userp,
                                             const char* passwdp,
                                             const char* service,
                                             char **outptr, size_t *outlen)
{
  static const char table16[] = "0123456789abcdef";

  CURLcode result = CURLE_OK;
  unsigned char *chlg = (unsigned char *) NULL;
  size_t chlglen = 0;
  size_t i;
  MD5_context *ctxt;
  unsigned char digest[MD5_DIGEST_LEN];
  char HA1_hex[2 * MD5_DIGEST_LEN + 1];
  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];

  char nonce[64];
  char realm[128];
  char alg[64];
  char nonceCount[] = "00000001";
  char cnonce[]     = "12345678"; /* will be changed */
  char method[]     = "AUTHENTICATE";
  char qop[]        = "auth";
  char uri[128];
  char response[512];

  result = Curl_base64_decode(chlg64, &chlg, &chlglen);

  if(result)
    return result;

  /* Retrieve nonce string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "nonce=\"", nonce,
                                sizeof(nonce), '\"')) {
    Curl_safefree(chlg);
    return CURLE_LOGIN_DENIED;
  }

  /* Retrieve realm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "realm=\"", realm,
                                sizeof(realm), '\"')) {
    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
    strcpy(realm, "");
  }

  /* Retrieve algorithm string from the challenge */
  if(!sasl_digest_get_key_value(chlg, "algorithm=", alg, sizeof(alg), ',')) {
    Curl_safefree(chlg);
    return CURLE_LOGIN_DENIED;
  }

  Curl_safefree(chlg);

  /* We do not support other algorithms */
  if(strcmp(alg, "md5-sess") != 0)
    return CURLE_LOGIN_DENIED;

  /* Generate 64 bits of random data */
  for(i = 0; i < 8; i++)
    cnonce[i] = table16[Curl_rand()%16];

  /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
  if(!ctxt)
    return CURLE_OUT_OF_MEMORY;

  Curl_MD5_update(ctxt, (const unsigned char *) userp,
                  curlx_uztoui(strlen(userp)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) realm,
                  curlx_uztoui(strlen(realm)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
                  curlx_uztoui(strlen(passwdp)));
  Curl_MD5_final(ctxt, digest);

  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
  if(!ctxt)
    return CURLE_OUT_OF_MEMORY;

  Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
                  curlx_uztoui(strlen(nonce)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
                  curlx_uztoui(strlen(cnonce)));
  Curl_MD5_final(ctxt, digest);

  /* Convert calculated 16 octet hex into 32 bytes string */
  for(i = 0; i < MD5_DIGEST_LEN; i++)
    snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);

  /* Prepare the URL string */
  snprintf(uri, sizeof(uri), "%s/%s", service, realm);

  /* Calculate H(A2) */
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
  if(!ctxt)
    return CURLE_OUT_OF_MEMORY;

  Curl_MD5_update(ctxt, (const unsigned char *) method,
                  curlx_uztoui(strlen(method)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) uri,
                  curlx_uztoui(strlen(uri)));
  Curl_MD5_final(ctxt, digest);

  for(i = 0; i < MD5_DIGEST_LEN; i++)
    snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);

  /* Now calculate the response hash */
  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
  if(!ctxt)
    return CURLE_OUT_OF_MEMORY;

  Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
                  curlx_uztoui(strlen(nonce)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);

  Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
                  curlx_uztoui(strlen(nonceCount)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
                  curlx_uztoui(strlen(cnonce)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
  Curl_MD5_update(ctxt, (const unsigned char *) qop,
                  curlx_uztoui(strlen(qop)));
  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);

  Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
  Curl_MD5_final(ctxt, digest);

  for(i = 0; i < MD5_DIGEST_LEN; i++)
    snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);

  snprintf(response, sizeof(response),
           "username=\"%s\",realm=\"%s\",nonce=\"%s\","
           "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s",
           userp, realm, nonce,
           cnonce, nonceCount, uri, resp_hash_hex);

  /* Base64 encode the reply */
  return Curl_base64_encode(data, response, 0, outptr, outlen);
}
예제 #23
0
파일: spnego_sspi.c 프로젝트: 2px/curl
/*
 * Curl_auth_decode_spnego_message()
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * 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.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                         const char *user,
                                         const char *password,
                                         const char *service,
                                         const char *host,
                                         const char *chlg64,
                                         struct negotiatedata *nego)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  unsigned char *chlg = NULL;
  PSecPkgInfo SecurityPackage;
  SecBuffer chlg_buf;
  SecBuffer resp_buf;
  SecBufferDesc chlg_desc;
  SecBufferDesc resp_desc;
  unsigned long attrs;
  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */

#if defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) data;
#endif

  if(nego->context && nego->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
     * can't invent anything better */
    Curl_auth_spnego_cleanup(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    nego->spn = Curl_auth_build_spn(service, host, NULL);
    if(!nego->spn)
      return CURLE_OUT_OF_MEMORY;
  }

  if(!nego->output_token) {
    /* Query the security package for Negotiate */
    nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                      TEXT(SP_NAME_NEGOTIATE),
                                                      &SecurityPackage);
    if(nego->status != SEC_E_OK)
      return CURLE_NOT_BUILT_IN;

    nego->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);

    /* Allocate our output buffer */
    nego->output_token = malloc(nego->token_max);
    if(!nego->output_token)
      return CURLE_OUT_OF_MEMORY;
 }

  if(!nego->credentials) {
    /* Do we have credientials to use or are we using single sign-on? */
    if(user && *user) {
      /* Populate our identity structure */
      result = Curl_create_sspi_identity(user, password, &nego->identity);
      if(result)
        return result;

      /* Allow proper cleanup of the identity structure */
      nego->p_identity = &nego->identity;
    }
    else
      /* Use the current Windows user */
      nego->p_identity = NULL;

    /* Allocate our credentials handle */
    nego->credentials = malloc(sizeof(CredHandle));
    if(!nego->credentials)
      return CURLE_OUT_OF_MEMORY;

    memset(nego->credentials, 0, sizeof(CredHandle));

    /* Acquire our credentials handle */
    nego->status =
      s_pSecFn->AcquireCredentialsHandle(NULL,
                                         (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
                                         SECPKG_CRED_OUTBOUND, NULL,
                                         nego->p_identity, NULL, NULL,
                                         nego->credentials, &expiry);
    if(nego->status != SEC_E_OK)
      return CURLE_LOGIN_DENIED;

    /* Allocate our new context handle */
    nego->context = malloc(sizeof(CtxtHandle));
    if(!nego->context)
      return CURLE_OUT_OF_MEMORY;

    memset(nego->context, 0, sizeof(CtxtHandle));
  }

  if(chlg64 && *chlg64) {
    /* Decode the base-64 encoded challenge message */
    if(*chlg64 != '=') {
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }

    /* Ensure we have a valid challenge message */
    if(!chlg) {
      infof(data, "SPNEGO handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    /* Setup the challenge "input" security buffer */
    chlg_desc.ulVersion = SECBUFFER_VERSION;
    chlg_desc.cBuffers  = 1;
    chlg_desc.pBuffers  = &chlg_buf;
    chlg_buf.BufferType = SECBUFFER_TOKEN;
    chlg_buf.pvBuffer   = chlg;
    chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
  }

  /* Setup the response "output" security buffer */
  resp_desc.ulVersion = SECBUFFER_VERSION;
  resp_desc.cBuffers  = 1;
  resp_desc.pBuffers  = &resp_buf;
  resp_buf.BufferType = SECBUFFER_TOKEN;
  resp_buf.pvBuffer   = nego->output_token;
  resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);

  /* Generate our challenge-response message */
  nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
                                                     chlg ? nego->context :
                                                            NULL,
                                                     nego->spn,
                                                     ISC_REQ_CONFIDENTIALITY,
                                                     0, SECURITY_NATIVE_DREP,
                                                     chlg ? &chlg_desc : NULL,
                                                     0, nego->context,
                                                     &resp_desc, &attrs,
                                                     &expiry);

  /* Free the decoded challenge as it is not required anymore */
  free(chlg);

  if(GSS_ERROR(nego->status)) {
    return CURLE_OUT_OF_MEMORY;
  }

  if(nego->status == SEC_I_COMPLETE_NEEDED ||
     nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
    nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);
    if(GSS_ERROR(nego->status)) {
      return CURLE_RECV_ERROR;
    }
  }

  nego->output_token_length = resp_buf.cbBuffer;

  return result;
}
예제 #24
0
/*
 * Curl_ntlm_decode_type2_message()
 *
 * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP
 * or POP3 server. The message is first decoded from a base64 string into a
 * raw ntlm message and checked for validity before the appropriate data for
 * creating a type-3 message is written to the given ntlm data structure.
 *
 * Parameters:
 *
 * data    [in]     - Pointer to session handle.
 * header  [in]     - Pointer to the input buffer.
 * ntlm    [in]     - Pointer to ntlm data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
                                        const char* header,
                                        struct ntlmdata* ntlm)
{
#ifndef USE_WINDOWS_SSPI
  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
#endif

  /* NTLM type-2 message structure:

          Index  Description            Content
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
                                        (0x4e544c4d53535000)
            8    NTLM Message Type      long (0x02000000)
           12    Target Name            security buffer
           20    Flags                  long
           24    Challenge              8 bytes
          (32)   Context                8 bytes (two consecutive longs) (*)
          (40)   Target Information     security buffer (*)
          (48)   OS Version Structure   8 bytes (*)
  32 (48) (56)   Start of data block    (*)
                                        (*) -> Optional
  */

  size_t size = 0;
  unsigned char *buffer = NULL;
  CURLcode error;

#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
  (void)data;
#endif

  error = Curl_base64_decode(header, &buffer, &size);
  if(error)
    return error;

  if(!buffer) {
    infof(data, "NTLM handshake failure (unhandled condition)\n");
    return CURLE_REMOTE_ACCESS_DENIED;
  }

#ifdef USE_WINDOWS_SSPI
  ntlm->type_2 = malloc(size + 1);
  if(ntlm->type_2 == NULL) {
    free(buffer);
    return CURLE_OUT_OF_MEMORY;
  }
  ntlm->n_type_2 = (unsigned long)size;
  memcpy(ntlm->type_2, buffer, size);
#else
  ntlm->flags = 0;

  if((size < 32) ||
     (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
     (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
    /* This was not a good enough type-2 message */
    free(buffer);
    infof(data, "NTLM handshake failure (bad type-2 message)\n");
    return CURLE_REMOTE_ACCESS_DENIED;
  }

  ntlm->flags = readint_le(&buffer[20]);
  memcpy(ntlm->nonce, &buffer[24], 8);

  DEBUG_OUT({
    fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
    ntlm_print_flags(stderr, ntlm->flags);
    fprintf(stderr, "\n                  nonce=");
    ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
    fprintf(stderr, "\n****\n");
    fprintf(stderr, "**** Header %s\n ", header);
  });
예제 #25
0
/*
 * Curl_sasl_create_gssapi_security_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) security
 * token message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - The optional base64 encoded challenge message.
 * krb5    [in/out] - The gssapi 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.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                                                  const char *chlg64,
                                                  struct kerberos5data *krb5,
                                                  char **outptr,
                                                  size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t offset = 0;
  size_t chlglen = 0;
  size_t messagelen = 0;
  size_t appdatalen = 0;
  unsigned char *chlg = NULL;
  unsigned char *trailer = NULL;
  unsigned char *message = NULL;
  unsigned char *padding = NULL;
  unsigned char *appdata = NULL;
  SecBuffer input_buf[2];
  SecBuffer wrap_buf[3];
  SecBufferDesc input_desc;
  SecBufferDesc wrap_desc;
  unsigned long indata = 0;
  unsigned long outdata = 0;
  unsigned long qop = 0;
  unsigned long sec_layer = 0;
  unsigned long max_size = 0;
  SecPkgContext_Sizes sizes;
  SecPkgCredentials_Names names;
  SECURITY_STATUS status;
  char *user_name;

  /* Decode the base-64 encoded input message */
  if(strlen(chlg64) && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!chlg) {
    infof(data, "GSSAPI handshake failure (empty security message)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Get our response size information */
  status = s_pSecFn->QueryContextAttributes(krb5->context,
                                            SECPKG_ATTR_SIZES,
                                            &sizes);
  if(status != SEC_E_OK) {
    free(chlg);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Get the fully qualified username back from the context */
  status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
                                                SECPKG_CRED_ATTR_NAMES,
                                                &names);
  if(status != SEC_E_OK) {
    free(chlg);

    return CURLE_RECV_ERROR;
  }

  /* Setup the "input" security buffer */
  input_desc.ulVersion = SECBUFFER_VERSION;
  input_desc.cBuffers = 2;
  input_desc.pBuffers = input_buf;
  input_buf[0].BufferType = SECBUFFER_STREAM;
  input_buf[0].pvBuffer = chlg;
  input_buf[0].cbBuffer = curlx_uztoul(chlglen);
  input_buf[1].BufferType = SECBUFFER_DATA;
  input_buf[1].pvBuffer = NULL;
  input_buf[1].cbBuffer = 0;

  /* Decrypt the inbound challenge and obtain the qop */
  status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
  if(status != SEC_E_OK) {
    infof(data, "GSSAPI handshake failure (empty security message)\n");

    free(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
  if(input_buf[1].cbBuffer != 4) {
    infof(data, "GSSAPI handshake failure (invalid security data)\n");

    free(chlg);

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Copy the data out and free the challenge as it is not required anymore */
  memcpy(&indata, input_buf[1].pvBuffer, 4);
  s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
  free(chlg);

  /* Extract the security layer */
  sec_layer = indata & 0x000000FF;
  if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
    infof(data, "GSSAPI handshake failure (invalid security layer)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Extract the maximum message size the server can receive */
  max_size = ntohl(indata & 0xFFFFFF00);
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we don't require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate the trailer */
  trailer = malloc(sizes.cbSecurityTrailer);
  if(!trailer)
    return CURLE_OUT_OF_MEMORY;

  /* Convert the user name to UTF8 when operating with Unicode */
  user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
  if(!user_name) {
    free(trailer);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Allocate our message */
  messagelen = sizeof(outdata) + strlen(user_name) + 1;
  message = malloc(messagelen);
  if(!message) {
    free(trailer);
    Curl_unicodefree(user_name);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Populate the message with the security layer, client supported receive
     message size and authorization identity including the 0x00 based
     terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization
     identity is not terminated with the zero-valued (%x00) octet." it seems
     necessary to include it. */
  outdata = htonl(max_size) | sec_layer;
  memcpy(message, &outdata, sizeof(outdata));
  strcpy((char *) message + sizeof(outdata), user_name);
  Curl_unicodefree(user_name);

  /* Allocate the padding */
  padding = malloc(sizes.cbBlockSize);
  if(!padding) {
    free(message);
    free(trailer);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Setup the "authentication data" security buffer */
  wrap_desc.ulVersion    = SECBUFFER_VERSION;
  wrap_desc.cBuffers     = 3;
  wrap_desc.pBuffers     = wrap_buf;
  wrap_buf[0].BufferType = SECBUFFER_TOKEN;
  wrap_buf[0].pvBuffer   = trailer;
  wrap_buf[0].cbBuffer   = sizes.cbSecurityTrailer;
  wrap_buf[1].BufferType = SECBUFFER_DATA;
  wrap_buf[1].pvBuffer   = message;
  wrap_buf[1].cbBuffer   = curlx_uztoul(messagelen);
  wrap_buf[2].BufferType = SECBUFFER_PADDING;
  wrap_buf[2].pvBuffer   = padding;
  wrap_buf[2].cbBuffer   = sizes.cbBlockSize;

  /* Encrypt the data */
  status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
                                    &wrap_desc, 0);
  if(status != SEC_E_OK) {
    free(padding);
    free(message);
    free(trailer);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Allocate the encryption (wrap) buffer */
  appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
               wrap_buf[2].cbBuffer;
  appdata = malloc(appdatalen);
  if(!appdata) {
    free(padding);
    free(message);
    free(trailer);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Populate the encryption buffer */
  memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
  offset += wrap_buf[0].cbBuffer;
  memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
  offset += wrap_buf[1].cbBuffer;
  memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);

  /* Base64 encode the response */
  result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr,
                              outlen);

  /* Free all of our local buffers */
  free(appdata);
  free(padding);
  free(message);
  free(trailer);

  return result;
}
예제 #26
0
CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
                              const char *header)
{
  struct SessionHandle *data = conn->data;
  struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg:
    &data->state.negotiate;
  OM_uint32 major_status, minor_status, discard_st;
  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  size_t len;
  size_t rawlen = 0;
  CURLcode result;

  if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
    /* We finished successfully 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(data);
    return CURLE_LOGIN_DENIED;
  }

  if(!neg_ctx->server_name) {
    /* Generate our SPN */
    char *spn = Curl_sasl_build_gssapi_spn("HTTP", proxy ? conn->proxy.name :
                                                           conn->host.name);
    if(!spn)
      return CURLE_OUT_OF_MEMORY;

    /* Populate the SPN structure */
    spn_token.value = spn;
    spn_token.length = strlen(spn);

    /* Import the SPN */
    major_status = gss_import_name(&minor_status, &spn_token,
                                   GSS_C_NT_HOSTBASED_SERVICE,
                                   &neg_ctx->server_name);
    if(GSS_ERROR(major_status)) {
      Curl_gss_log_error(data, minor_status, "gss_import_name() failed: ");

      free(spn);

      return CURLE_OUT_OF_MEMORY;
    }

    free(spn);
  }

  header += strlen("Negotiate");
  while(*header && ISSPACE(*header))
    header++;

  len = strlen(header);
  if(len > 0) {
    result = Curl_base64_decode(header, (unsigned char **)&input_token.value,
                                &rawlen);
    if(result)
      return result;

    if(!rawlen) {
      infof(data, "Negotiate handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    input_token.length = rawlen;

    DEBUGASSERT(input_token.value != NULL);
  }

  major_status = Curl_gss_init_sec_context(data,
                                           &minor_status,
                                           &neg_ctx->context,
                                           neg_ctx->server_name,
                                           &Curl_spnego_mech_oid,
                                           GSS_C_NO_CHANNEL_BINDINGS,
                                           &input_token,
                                           &output_token,
                                           TRUE,
                                           NULL);
  Curl_safefree(input_token.value);

  neg_ctx->status = major_status;
  if(GSS_ERROR(major_status)) {
    if(output_token.value)
      gss_release_buffer(&discard_st, &output_token);
    Curl_gss_log_error(conn->data, minor_status,
                       "gss_init_sec_context() failed: ");
    return CURLE_OUT_OF_MEMORY;
  }

  if(!output_token.value || !output_token.length) {
    if(output_token.value)
      gss_release_buffer(&discard_st, &output_token);
    return CURLE_OUT_OF_MEMORY;
  }

  neg_ctx->output_token = output_token;

  return CURLE_OK;
}
예제 #27
0
/*
 * Curl_sasl_create_digest_md5_message()
 *
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg64  [in]     - The base64 encoded challenge message.
 * 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 www, smtp, pop or imap.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
                                             const char *chlg64,
                                             const char *userp,
                                             const char *passwdp,
                                             const char *service,
                                             char **outptr, size_t *outlen)
{
  CURLcode result = CURLE_OK;
  TCHAR *spn = NULL;
  size_t chlglen = 0;
  size_t token_max = 0;
  unsigned char *input_token = NULL;
  unsigned char *output_token = NULL;
  CredHandle credentials;
  CtxtHandle context;
  PSecPkgInfo SecurityPackage;
  SEC_WINNT_AUTH_IDENTITY identity;
  SEC_WINNT_AUTH_IDENTITY *p_identity;
  SecBuffer chlg_buf;
  SecBuffer resp_buf;
  SecBufferDesc chlg_desc;
  SecBufferDesc resp_desc;
  SECURITY_STATUS status;
  unsigned long attrs;
  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */

  /* Decode the base-64 encoded challenge message */
  if(strlen(chlg64) && *chlg64 != '=') {
    result = Curl_base64_decode(chlg64, &input_token, &chlglen);
    if(result)
      return result;
  }

  /* Ensure we have a valid challenge message */
  if(!input_token) {
    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");

    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Query the security package for DigestSSP */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    free(input_token);

    return CURLE_NOT_BUILT_IN;
  }

  token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);

  /* Allocate our response buffer */
  output_token = malloc(token_max);
  if(!output_token) {
    free(input_token);

    return CURLE_OUT_OF_MEMORY;
  }

  /* Generate our SPN */
  spn = Curl_sasl_build_spn(service, data->easy_conn->host.name);
  if(!spn) {
    free(output_token);
    free(input_token);

    return CURLE_OUT_OF_MEMORY;
  }

  if(userp && *userp) {
    /* Populate our identity structure */
    result = Curl_create_sspi_identity(userp, passwdp, &identity);
    if(result) {
      free(spn);
      free(output_token);
      free(input_token);

      return result;
    }

    /* Allow proper cleanup of the identity structure */
    p_identity = &identity;
  }
  else
    /* Use the current Windows user */
    p_identity = NULL;

  /* Acquire our credentials handle */
  status = s_pSecFn->AcquireCredentialsHandle(NULL,
                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
                                              SECPKG_CRED_OUTBOUND, NULL,
                                              p_identity, NULL, NULL,
                                              &credentials, &expiry);

  if(status != SEC_E_OK) {
    Curl_sspi_free_identity(p_identity);
    free(spn);
    free(output_token);
    free(input_token);

    return CURLE_LOGIN_DENIED;
  }

  /* Setup the challenge "input" security buffer */
  chlg_desc.ulVersion = SECBUFFER_VERSION;
  chlg_desc.cBuffers  = 1;
  chlg_desc.pBuffers  = &chlg_buf;
  chlg_buf.BufferType = SECBUFFER_TOKEN;
  chlg_buf.pvBuffer   = input_token;
  chlg_buf.cbBuffer   = curlx_uztoul(chlglen);

  /* Setup the response "output" security buffer */
  resp_desc.ulVersion = SECBUFFER_VERSION;
  resp_desc.cBuffers  = 1;
  resp_desc.pBuffers  = &resp_buf;
  resp_buf.BufferType = SECBUFFER_TOKEN;
  resp_buf.pvBuffer   = output_token;
  resp_buf.cbBuffer   = curlx_uztoul(token_max);

  /* Generate our response message */
  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
                                               0, 0, 0, &chlg_desc, 0,
                                               &context, &resp_desc, &attrs,
                                               &expiry);

  if(status == SEC_I_COMPLETE_NEEDED ||
     status == SEC_I_COMPLETE_AND_CONTINUE)
    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
    s_pSecFn->FreeCredentialsHandle(&credentials);
    Curl_sspi_free_identity(p_identity);
    free(spn);
    free(output_token);
    free(input_token);

    return CURLE_RECV_ERROR;
  }

  /* Base64 encode the response */
  result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
                              outptr, outlen);

  /* Free our handles */
  s_pSecFn->DeleteSecurityContext(&context);
  s_pSecFn->FreeCredentialsHandle(&credentials);

  /* Free the identity structure */
  Curl_sspi_free_identity(p_identity);

  /* Free the SPN */
  free(spn);

  /* Free the response buffer */
  free(output_token);

  /* Free the decoded challenge message */
  free(input_token);

  return result;
}
예제 #28
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)
{
  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         lifetime;
  TCHAR             *sname;
  int ret;
  size_t len = 0, input_token_len = 0;
  bool gss = FALSE;
  const char* protocol;
  CURLcode error;

  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 == 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
     * can't invent anything better */
    Curl_cleanup_negotiate(conn->data);
    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("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->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(neg_ctx->protocol);
  while(*header && ISSPACE(*header))
    header++;

  len = strlen(header);
  if(!len) {
    /* first call in a new negotation, 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;

    neg_ctx->status =
      s_pSecFn->AcquireCredentialsHandle(NULL,
                                         (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 == 0)
      return -1;
  }

  /* 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;


  if(input_token) {
    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;
  }

  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 : 0,
    sname,
    ISC_REQ_CONFIDENTIALITY,
    0,
    SECURITY_NATIVE_DREP,
    input_token ? &in_buff_desc : 0,
    0,
    neg_ctx->context,
    &out_buff_desc,
    &context_attributes,
    &lifetime);

  Curl_unicodefree(sname);

  if(GSS_ERROR(neg_ctx->status))
    return -1;

  if(neg_ctx->status == SEC_I_COMPLETE_NEEDED ||
     neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) {
    neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context,
                                                  &out_buff_desc);
    if(GSS_ERROR(neg_ctx->status))
      return -1;
  }

  neg_ctx->output_token_length = out_sec_buff.cbBuffer;

  return 0;
}
예제 #29
0
/*
 * Curl_sasl_create_gssapi_user_message()
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * 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 www, smtp, pop or imap.
 * mutual_auth [in]     - Flag specifing whether or not mutual authentication
 *                        is enabled.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * krb5        [in/out] - The gssapi 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.
 * outlen      [out]    - The length of the output message.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
                                              const char *userp,
                                              const char *passwdp,
                                              const char *service,
                                              const bool mutual_auth,
                                              const char *chlg64,
                                              struct kerberos5data *krb5,
                                              char **outptr, size_t *outlen)
{
  CURLcode result = CURLE_OK;
  size_t chlglen = 0;
  unsigned char *chlg = NULL;
  CtxtHandle context;
  PSecPkgInfo SecurityPackage;
  SecBuffer chlg_buf;
  SecBuffer resp_buf;
  SecBufferDesc chlg_desc;
  SecBufferDesc resp_desc;
  SECURITY_STATUS status;
  unsigned long attrs;
  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */

  if(!krb5->credentials) {
    /* Query the security package for Kerberos */
    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                TEXT(SP_NAME_KERBEROS),
                                                &SecurityPackage);
    if(status != SEC_E_OK) {
      return CURLE_NOT_BUILT_IN;
    }

    krb5->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);

    /* Allocate our response buffer */
    krb5->output_token = malloc(krb5->token_max);
    if(!krb5->output_token)
      return CURLE_OUT_OF_MEMORY;

    /* Generate our SPN */
    krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name);
    if(!krb5->spn)
      return CURLE_OUT_OF_MEMORY;

    if(userp && *userp) {
      /* Populate our identity structure */
      result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
      if(result)
        return result;

      /* Allow proper cleanup of the identity structure */
      krb5->p_identity = &krb5->identity;
    }
    else
      /* Use the current Windows user */
      krb5->p_identity = NULL;

    /* Allocate our credentials handle */
    krb5->credentials = malloc(sizeof(CredHandle));
    if(!krb5->credentials)
      return CURLE_OUT_OF_MEMORY;

    memset(krb5->credentials, 0, sizeof(CredHandle));

    /* Acquire our credentials handle */
    status = s_pSecFn->AcquireCredentialsHandle(NULL,
                                                (TCHAR *)
                                                TEXT(SP_NAME_KERBEROS),
                                                SECPKG_CRED_OUTBOUND, NULL,
                                                krb5->p_identity, NULL, NULL,
                                                krb5->credentials, &expiry);
    if(status != SEC_E_OK)
      return CURLE_LOGIN_DENIED;

    /* Allocate our new context handle */
    krb5->context = malloc(sizeof(CtxtHandle));
    if(!krb5->context)
      return CURLE_OUT_OF_MEMORY;

    memset(krb5->context, 0, sizeof(CtxtHandle));
  }
  else {
    /* Decode the base-64 encoded challenge message */
    if(strlen(chlg64) && *chlg64 != '=') {
      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
      if(result)
        return result;
    }

    /* Ensure we have a valid challenge message */
    if(!chlg) {
      infof(data, "GSSAPI handshake failure (empty challenge message)\n");

      return CURLE_BAD_CONTENT_ENCODING;
    }

    /* Setup the challenge "input" security buffer */
    chlg_desc.ulVersion = SECBUFFER_VERSION;
    chlg_desc.cBuffers  = 1;
    chlg_desc.pBuffers  = &chlg_buf;
    chlg_buf.BufferType = SECBUFFER_TOKEN;
    chlg_buf.pvBuffer   = chlg;
    chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
  }

  /* Setup the response "output" security buffer */
  resp_desc.ulVersion = SECBUFFER_VERSION;
  resp_desc.cBuffers  = 1;
  resp_desc.pBuffers  = &resp_buf;
  resp_buf.BufferType = SECBUFFER_TOKEN;
  resp_buf.pvBuffer   = krb5->output_token;
  resp_buf.cbBuffer   = curlx_uztoul(krb5->token_max);

  /* Generate our challenge-response message */
  status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
                                               chlg ? krb5->context : NULL,
                                               krb5->spn,
                                               (mutual_auth ?
                                                 ISC_REQ_MUTUAL_AUTH : 0),
                                               0, SECURITY_NATIVE_DREP,
                                               chlg ? &chlg_desc : NULL, 0,
                                               &context,
                                               &resp_desc, &attrs,
                                               &expiry);

  if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
    free(chlg);

    return CURLE_RECV_ERROR;
  }

  if(memcmp(&context, krb5->context, sizeof(context))) {
    s_pSecFn->DeleteSecurityContext(krb5->context);

    memcpy(krb5->context, &context, sizeof(context));
  }

  if(resp_buf.cbBuffer) {
    /* Base64 encode the response */
    result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer,
                                resp_buf.cbBuffer, outptr, outlen);
  }

  /* Free the decoded challenge */
  free(chlg);

  return result;
}
예제 #30
0
CURLcode Curl_krb_kauth(struct connectdata *conn)
{
  des_cblock key;
  des_key_schedule schedule;
  KTEXT_ST tkt, tktcopy;
  char *name;
  char *p;
  char passwd[100];
  size_t tmp;
  ssize_t nread;
  int save;
  CURLcode result;
  unsigned char *ptr;

  save = Curl_set_command_prot(conn, prot_private);

  result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);

  if(result)
    return result;

  result = Curl_GetFTPResponse(&nread, conn, NULL);
  if(result)
    return result;

  if(conn->data->state.buffer[0] != '3'){
    Curl_set_command_prot(conn, save);
    return CURLE_FTP_WEIRD_SERVER_REPLY;
  }

  p = strstr(conn->data->state.buffer, "T=");
  if(!p) {
    Curl_failf(conn->data, "Bad reply from server");
    Curl_set_command_prot(conn, save);
    return CURLE_FTP_WEIRD_SERVER_REPLY;
  }

  p += 2;
  tmp = Curl_base64_decode(p, &ptr);
  if(tmp >= sizeof(tkt.dat)) {
    free(ptr);
    tmp=0;
  }
  if(!tmp || !ptr) {
    Curl_failf(conn->data, "Failed to decode base64 in reply");
    Curl_set_command_prot(conn, save);
    return CURLE_FTP_WEIRD_SERVER_REPLY;
  }
  memcpy((char *)tkt.dat, ptr, tmp);
  free(ptr);
  tkt.length = tmp;
  tktcopy.length = tkt.length;

  p = strstr(conn->data->state.buffer, "P=");
  if(!p) {
    Curl_failf(conn->data, "Bad reply from server");
    Curl_set_command_prot(conn, save);
    return CURLE_FTP_WEIRD_SERVER_REPLY;
  }
  name = p + 2;
  for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
  *p = 0;

  des_string_to_key (conn->passwd, &key);
  des_key_sched(&key, schedule);

  des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
                   tkt.length,
                   schedule, &key, DES_DECRYPT);
  if(strcmp ((char*)tktcopy.dat + 8,
              KRB_TICKET_GRANTING_TICKET) != 0) {
    afs_string_to_key(passwd,
                      krb_realmofhost(conn->host.name),
                      &key);
    des_key_sched(&key, schedule);
    des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
                     tkt.length,
                     schedule, &key, DES_DECRYPT);
  }
  memset(key, 0, sizeof(key));
  memset(schedule, 0, sizeof(schedule));
  memset(passwd, 0, sizeof(passwd));
  if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p)
     < 1) {
    failf(conn->data, "Out of memory base64-encoding.");
    Curl_set_command_prot(conn, save);
    return CURLE_OUT_OF_MEMORY;
  }
  memset (tktcopy.dat, 0, tktcopy.length);

  result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p);
  free(p);
  if(result)
    return result;

  result = Curl_GetFTPResponse(&nread, conn, NULL);
  if(result)
    return result;
  Curl_set_command_prot(conn, save);

  return CURLE_OK;
}