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