Пример #1
0
static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
                         const char *buffer, size_t length)
{
  ssize_t tx = 0, len = conn->buffer_size;

  len -= conn->mech->overhead(conn->app_data, conn->data_prot,
                              curlx_sztosi(len));
  if(len <= 0)
    len = length;
  while(length) {
    if(length < (size_t)len)
      len = length;

    do_sec_send(conn, fd, buffer, curlx_sztosi(len));
    length -= len;
    buffer += len;
    tx += len;
  }
  return tx;
}
Пример #2
0
static int getMicroSecondTimeout(struct timeval* timeout)
{
  struct timeval now;
  ssize_t result;
  now = tutil_tvnow();
  result = (timeout->tv_sec - now.tv_sec) * 1000000 +
    timeout->tv_usec - now.tv_usec;
  if (result < 0)
    result = 0;

  return curlx_sztosi(result);
}
Пример #3
0
/* return the number of microseconds between two time stamps */
static int elapsed(struct timeval *before,
                   struct timeval *after)
{
    ssize_t result;

    result = (after->tv_sec - before->tv_sec) * 1000000 +
             after->tv_usec - before->tv_usec;
    if (result < 0)
        result = 0;

    return curlx_sztosi(result);
}
Пример #4
0
static size_t callback(char* ptr, size_t size, size_t nmemb, void* data)
{
    ssize_t idx = ((CURL **) data) - easy;
    curl_socket_t sock;
    long longdata;
    CURLcode code;

    const size_t failure = (size * nmemb) ? 0 : 1;

    char *output = malloc(size * nmemb + 1);
    if(!output) {
        fprintf(stderr, "output, malloc() failed\n");
        res = TEST_ERR_MAJOR_BAD;
        return failure;
    }

    memcpy(output, ptr, size * nmemb);
    output[size * nmemb] = '\0';
    fprintf(stdout, "%s", output);
    free(output);

    /* Get socket being used for this easy handle, otherwise CURL_SOCKET_BAD */
    code = curl_easy_getinfo(easy[idx], CURLINFO_LASTSOCKET, &longdata);
    if(CURLE_OK != code) {
        fprintf(stderr, "%s:%d curl_easy_getinfo() failed, "
                "with code %d (%s)\n",
                __FILE__, __LINE__, (int)code, curl_easy_strerror(code));
        res = TEST_ERR_MAJOR_BAD;
        return failure;
    }
    if(longdata == -1L)
        sock = CURL_SOCKET_BAD;
    else
        sock = (curl_socket_t)longdata;

    if(sock != CURL_SOCKET_BAD) {
        /* Track relationship between this easy handle and the socket. */
        if(sockets[idx] == CURL_SOCKET_BAD) {
            /* An easy handle without previous socket, record the socket. */
            sockets[idx] = sock;
        }
        else if(sock != sockets[idx]) {
            /* An easy handle with a socket different to previously
               tracked one, log and fail right away. Known bug #37. */
            fprintf(stderr, "Handle %d started on socket %d and moved to %d\n",
                    curlx_sztosi(idx), (int)sockets[idx], (int)sock);
            res = TEST_ERR_MAJOR_BAD;
            return failure;
        }
    }
    return size * nmemb;
}
CURLcode Curl_output_digest(struct connectdata *conn,
                            bool proxy,
                            const unsigned char *request,
                            const unsigned char *uripath)
{
  /* We have a Digest setup for this, use it!  Now, to get all the details for
     this sorted out, I must urge you dear friend to read up on the RFC2617
     section 3.2.2, */
  unsigned char md5buf[16]; /* 16 bytes/128 bits */
  unsigned char request_digest[33];
  unsigned char *md5this;
  unsigned char *ha1;
  unsigned char ha2[33];/* 32 digits and 1 zero byte */
  char cnoncebuf[33];
  char *cnonce = NULL;
  size_t cnonce_sz = 0;
  char *tmp = NULL;
  struct timeval now;

  char **allocuserpwd;
  const char *userp;
  const char *passwdp;
  struct auth *authp;

  struct SessionHandle *data = conn->data;
  struct digestdata *d;
  CURLcode rc;
/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
   It converts digest text to ASCII so the MD5 will be correct for
   what ultimately goes over the network.
*/
#define CURL_OUTPUT_DIGEST_CONV(a, b) \
  rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
  if(rc != CURLE_OK) { \
    free(b); \
    return rc; \
  }

  if(proxy) {
    d = &data->state.proxydigest;
    allocuserpwd = &conn->allocptr.proxyuserpwd;
    userp = conn->proxyuser;
    passwdp = conn->proxypasswd;
    authp = &data->state.authproxy;
  }
  else {
    d = &data->state.digest;
    allocuserpwd = &conn->allocptr.userpwd;
    userp = conn->user;
    passwdp = conn->passwd;
    authp = &data->state.authhost;
  }

  if(*allocuserpwd) {
    Curl_safefree(*allocuserpwd);
    *allocuserpwd = NULL;
  }

  /* not set means empty */
  if(!userp)
    userp="";

  if(!passwdp)
    passwdp="";

  if(!d->nonce) {
    authp->done = FALSE;
    return CURLE_OK;
  }
  authp->done = TRUE;

  if(!d->nc)
    d->nc = 1;

  if(!d->cnonce) {
    /* Generate a cnonce */
    now = Curl_tvnow();
    snprintf(cnoncebuf, sizeof(cnoncebuf), "%32ld",
             (long)now.tv_sec + now.tv_usec);

    rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
                            &cnonce, &cnonce_sz);
    if(rc)
      return rc;
    d->cnonce = cnonce;
  }

  /*
    if the algorithm is "MD5" or unspecified (which then defaults to MD5):

    A1 = unq(username-value) ":" unq(realm-value) ":" passwd

    if the algorithm is "MD5-sess" then:

    A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
         ":" unq(nonce-value) ":" unq(cnonce-value)
  */

  md5this = (unsigned char *)
    aprintf("%s:%s:%s", userp, d->realm, passwdp);
  if(!md5this)
    return CURLE_OUT_OF_MEMORY;

  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
  Curl_md5it(md5buf, md5this);
  free(md5this); /* free this again */

  ha1 = malloc(33); /* 32 digits and 1 zero byte */
  if(!ha1)
    return CURLE_OUT_OF_MEMORY;

  md5_to_ascii(md5buf, ha1);

  if(d->algo == CURLDIGESTALGO_MD5SESS) {
    /* nonce and cnonce are OUTSIDE the hash */
    tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
    if(!tmp)
      return CURLE_OUT_OF_MEMORY;
    CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
    Curl_md5it(md5buf, (unsigned char *)tmp);
    free(tmp); /* free this again */
    md5_to_ascii(md5buf, ha1);
  }

  /*
    If the "qop" directive's value is "auth" or is unspecified, then A2 is:

      A2       = Method ":" digest-uri-value

          If the "qop" value is "auth-int", then A2 is:

      A2       = Method ":" digest-uri-value ":" H(entity-body)

    (The "Method" value is the HTTP request method as specified in section
    5.1.1 of RFC 2616)
  */

  /* So IE browsers < v7 cut off the URI part at the query part when they
     evaluate the MD5 and some (IIS?) servers work with them so we may need to
     do the Digest IE-style. Note that the different ways cause different MD5
     sums to get sent.

     Apache servers can be set to do the Digest IE-style automatically using
     the BrowserMatch feature:
     http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie

     Further details on Digest implementation differences:
     http://www.fngtps.com/2006/09/http-authentication
  */
  if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) {
    md5this = (unsigned char *)aprintf("%s:%.*s", request,
                                       curlx_sztosi(tmp - (char *)uripath),
                                       uripath);
  }
  else
    md5this = (unsigned char *)aprintf("%s:%s", request, uripath);

  if(!md5this) {
    free(ha1);
    return CURLE_OUT_OF_MEMORY;
  }

  if(d->qop && Curl_raw_equal(d->qop, "auth-int")) {
    /* We don't support auth-int at the moment. I can't see a easy way to get
       entity-body here */
    /* TODO: Append H(entity-body)*/
  }
  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
  Curl_md5it(md5buf, md5this);
  free(md5this); /* free this again */
  md5_to_ascii(md5buf, ha2);

  if(d->qop) {
    md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
                                       ha1,
                                       d->nonce,
                                       d->nc,
                                       d->cnonce,
                                       d->qop,
                                       ha2);
  }
  else {
    md5this = (unsigned char *)aprintf("%s:%s:%s",
                                       ha1,
                                       d->nonce,
                                       ha2);
  }
  free(ha1);
  if(!md5this)
    return CURLE_OUT_OF_MEMORY;

  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
  Curl_md5it(md5buf, md5this);
  free(md5this); /* free this again */
  md5_to_ascii(md5buf, request_digest);

  /* for test case 64 (snooped from a Mozilla 1.3a request)

    Authorization: Digest username="******", realm="testrealm", \
    nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
  */

  if(d->qop) {
    *allocuserpwd =
      aprintf( "%sAuthorization: Digest "
               "username=\"%s\", "
               "realm=\"%s\", "
               "nonce=\"%s\", "
               "uri=\"%s\", "
               "cnonce=\"%s\", "
               "nc=%08x, "
               "qop=%s, "
               "response=\"%s\"",
               proxy?"Proxy-":"",
               userp,
               d->realm,
               d->nonce,
               uripath, /* this is the PATH part of the URL */
               d->cnonce,
               d->nc,
               d->qop,
               request_digest);

    if(Curl_raw_equal(d->qop, "auth"))
      d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
                  which tells to the server how many times you are using the
                  same nonce in the qop=auth mode. */
  }
  else {
    *allocuserpwd =
      aprintf( "%sAuthorization: Digest "
               "username=\"%s\", "
               "realm=\"%s\", "
               "nonce=\"%s\", "
               "uri=\"%s\", "
               "response=\"%s\"",
               proxy?"Proxy-":"",
               userp,
               d->realm,
               d->nonce,
               uripath, /* this is the PATH part of the URL */
               request_digest);
  }
  if(!*allocuserpwd)
    return CURLE_OUT_OF_MEMORY;

  /* Add optional fields */
  if(d->opaque) {
    /* append opaque */
    tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
    if(!tmp)
      return CURLE_OUT_OF_MEMORY;
    free(*allocuserpwd);
    *allocuserpwd = tmp;
  }

  if(d->algorithm) {
    /* append algorithm */
    tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
    if(!tmp)
      return CURLE_OUT_OF_MEMORY;
    free(*allocuserpwd);
    *allocuserpwd = tmp;
  }

  /* append CRLF + zero (3 bytes) to the userpwd header */
  tmp = realloc(*allocuserpwd, strlen(*allocuserpwd) + 3);
  if(!tmp)
    return CURLE_OUT_OF_MEMORY;
  strcat(tmp, "\r\n");
  *allocuserpwd = tmp;

  return CURLE_OK;
}