Loading lib/http.c +432 −249 Original line number Diff line number Diff line Loading @@ -105,6 +105,278 @@ static CURLcode Curl_output_basic_proxy(struct connectdata *conn); /* * This function checks the linked list of custom HTTP headers for a particular * header (prefix). */ static char *checkheaders(struct SessionHandle *data, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); for(head = data->set.headers; head; head=head->next) { if(strnequal(head->data, thisheader, thislen)) return head->data; } return NULL; } static CURLcode Curl_output_basic(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { if(conn->allocptr.userpwd) free(conn->allocptr.userpwd); conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static CURLcode Curl_output_basic_proxy(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->proxyuser, conn->proxypasswd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = aprintf("Proxy-authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } void Curl_http_auth_act(struct connectdata *conn) { struct SessionHandle *data = conn->data; if(data->state.authavail) { if(data->state.authavail & CURLAUTH_GSSNEGOTIATE) data->state.authwant = CURLAUTH_GSSNEGOTIATE; else if(data->state.authavail & CURLAUTH_DIGEST) data->state.authwant = CURLAUTH_DIGEST; else if(data->state.authavail & CURLAUTH_NTLM) data->state.authwant = CURLAUTH_NTLM; else if(data->state.authavail & CURLAUTH_BASIC) data->state.authwant = CURLAUTH_BASIC; else data->state.authwant = CURLAUTH_NONE; /* none */ if(data->state.authwant) conn->newurl = strdup(data->change.url); /* clone string */ data->state.authavail = CURLAUTH_NONE; /* clear it here */ } } /* * Setup the authentication headers for the host/proxy and the correct * authentication method. */ CURLcode http_auth_headers(struct connectdata *conn, char *request, char *path) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; if(!data->state.authstage) { if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) Curl_http_auth_stage(data, 407); else Curl_http_auth_stage(data, 401); } /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || !data->state.auth_host || curl_strequal(data->state.auth_host, conn->hostname) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ if (data->state.authstage == 407) { #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, TRUE); if(result) return result; } else #endif if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.proxy_user_passwd && !checkheaders(data, "Proxy-authorization:")) { result = Curl_output_basic_proxy(conn); if(result) return result; /* Switch to web authentication after proxy authentication is done */ Curl_http_auth_stage(data, 401); } } /* Send web authentication header if needed */ if (data->state.authstage == 401) { #ifdef GSSAPI if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) && data->state.negotiate.context && !GSS_ERROR(data->state.negotiate.status)) { result = Curl_output_negotiate(conn); if (result) return result; } else #endif #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, FALSE); if(result) return result; } else #endif { if((data->state.authwant == CURLAUTH_DIGEST) && data->state.digest.nonce) { result = Curl_output_digest(conn, (unsigned char *)request, (unsigned char *)path); if(result) return result; } else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.user_passwd && !checkheaders(data, "Authorization:")) { result = Curl_output_basic(conn); if(result) return result; } } } } return result; } /* * Curl_http_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the * proxy CONNECT loop. */ CURLcode Curl_http_auth(struct connectdata *conn, int httpcode, char *header) /* pointing to the first non-space */ { /* * This resource requires authentication */ struct SessionHandle *data = conn->data; char *start = (httpcode == 407) ? header+strlen("Proxy-authenticate:"): header+strlen("WWW-Authenticate:"); /* * Switch from proxy to web authentication and back if needed */ if (httpcode == 407 && data->state.authstage != 407) Curl_http_auth_stage(data, 407); else if (httpcode == 401 && data->state.authstage != 401) Curl_http_auth_stage(data, 401); /* pass all white spaces */ while(*start && isspace((int)*start)) start++; #ifdef GSSAPI if (checkprefix("GSS-Negotiate", start)) { if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) { /* if exactly this is wanted, go */ int neg = Curl_input_negotiate(conn, start); if (neg == 0) conn->newurl = strdup(data->change.url); } else if(data->state.authwant & CURLAUTH_GSSNEGOTIATE) data->state.authavail |= CURLAUTH_GSSNEGOTIATE; } else #endif #ifdef USE_SSLEAY /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", start)) { if(data->state.authwant == CURLAUTH_NTLM) { /* NTLM authentication is activated */ CURLntlm ntlm = Curl_input_ntlm(conn, (bool)(httpcode == 407), start); if(CURLNTLM_BAD != ntlm) conn->newurl = strdup(data->change.url); /* clone string */ else infof(data, "Authentication problem. Ignoring this.\n"); } else if(data->state.authwant & CURLAUTH_NTLM) data->state.authavail |= CURLAUTH_NTLM; } else #endif if(checkprefix("Digest", start)) { if(data->state.authwant == CURLAUTH_DIGEST) { /* Digest authentication is activated */ CURLdigest dig = CURLDIGEST_BAD; if(data->state.digest.nonce) infof(data, "Authentication problem. Ignoring this.\n"); else dig = Curl_input_digest(conn, start); if(CURLDIGEST_FINE == dig) /* We act on it. Store our new url, which happens to be the same one we already use! */ conn->newurl = strdup(data->change.url); /* clone string */ } else if(data->state.authwant & CURLAUTH_DIGEST) { /* We don't know if Digest is what we're gonna use, but we call this function anyway to store the digest data that is provided on this line, to skip the extra round-trip we need to do otherwise. We must sure to free this data! */ Curl_input_digest(conn, start); data->state.authavail |= CURLAUTH_DIGEST; } } else if(checkprefix("Basic", start)) { if((data->state.authwant == CURLAUTH_BASIC) && (httpcode == 401)) { /* We asked for Basic authentication but got a 401 back anyway, which basicly means our name+password isn't valid. */ data->state.authavail = CURLAUTH_NONE; infof(data, "Authentication problem. Ignoring this.\n"); } else if(data->state.authwant & CURLAUTH_BASIC) { data->state.authavail |= CURLAUTH_BASIC; } } return CURLE_OK; } /* fread() emulation to provide POST and/or request data */ static int readmoredata(char *buffer, size_t size, Loading Loading @@ -383,22 +655,6 @@ Curl_compareheader(char *headerline, /* line to check */ return FALSE; /* no match */ } /* * This function checks the linked list of custom HTTP headers for a particular * header (prefix). */ static char *checkheaders(struct SessionHandle *data, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); for(head = data->set.headers; head; head=head->next) { if(strnequal(head->data, thisheader, thislen)) return head->data; } return NULL; } /* * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through Loading @@ -407,9 +663,10 @@ static char *checkheaders(struct SessionHandle *data, const char *thisheader) CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, int tunnelsocket, char *hostname, int remote_port) char *hostname, int remote_port) { int httperror=0; int httpcode=0; int subversion=0; struct SessionHandle *data=conn->data; CURLcode result; Loading @@ -425,6 +682,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, fd_set rkeepfd; fd_set readfd; char *line_start; char *host_port; #define SELECT_OK 0 #define SELECT_ERROR 1 Loading @@ -433,12 +691,22 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); /* * This code currently only supports Basic authentication for this CONNECT * request to a proxy. */ if(conn->bits.proxy_user_passwd) Curl_output_basic_proxy(conn); do { if(conn->newurl) { /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ free(conn->newurl); conn->newurl = NULL; } host_port = aprintf("%s:%d", hostname, remote_port); if(!host_port) return CURLE_OUT_OF_MEMORY; /* Setup the proxy-authorization header, if any */ result = http_auth_headers(conn, (char *)"CONNECT", host_port); if(CURLE_OK == result) { /* OK, now send the connect request to the proxy */ result = Loading @@ -448,32 +716,22 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, "%s" "\r\n", hostname, remote_port, (conn->bits.proxy_user_passwd)?conn->allocptr.proxyuserpwd:"", (data->set.useragent?conn->allocptr.uagent:"") conn->bits.proxy_user_passwd? conn->allocptr.proxyuserpwd:"", data->set.useragent?conn->allocptr.uagent:"" ); if(result) { if(result) failf(data, "Failed sending CONNECT to proxy"); return result; } /* Now, read the full reply we get from the proxy */ if(data->set.timeout) { /* if timeout is requested, find out how much remaining time we have */ timeout = data->set.timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ if(timeout <=0 ) { failf(data, "Transfer aborted due to timeout"); return -SELECT_TIMEOUT; /* already too little time */ } } free(host_port); if(result) return result; FD_ZERO (&readfd); /* clear it */ FD_SET (tunnelsocket, &readfd); /* read socket */ /* get this in a backup variable to be able to restore it on each lap in the select() loop */ /* get this in a backup variable to be able to restore it on each lap in the select() loop */ rkeepfd = readfd; ptr=data->state.buffer; Loading @@ -485,17 +743,26 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, while((nread<BUFSIZE) && (keepon && !error)) { readfd = rkeepfd; /* set every lap */ interval.tv_sec = timeout; interval.tv_sec = 1; /* timeout each second and check the timeout */ interval.tv_usec = 0; if(data->set.timeout) { /* if timeout is requested, find out how much remaining time we have */ timeout = data->set.timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ if(timeout <=0 ) { failf(data, "Proxy connection aborted due to timeout"); error = SELECT_TIMEOUT; /* already too little time */ break; } } switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) { case -1: /* select() error, stop reading */ error = SELECT_ERROR; failf(data, "Transfer aborted due to select() error"); failf(data, "Proxy CONNECT aborted due to select() error"); break; case 0: /* timeout */ error = SELECT_TIMEOUT; failf(data, "Transfer aborted due to timeout"); break; default: /* Loading @@ -503,8 +770,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, * to read, but when we use Curl_read() it may do so. Do confirm * that this is still ok and then remove this comment! */ res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); if(res< 0) /* EWOULDBLOCK */ continue; /* go loop yourself */ Loading @@ -513,39 +779,59 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, else if(gotbytes <= 0) { keepon = FALSE; error = SELECT_ERROR; failf(data, "Connection aborted"); failf(data, "Proxy CONNECT aborted"); } else { /* we got a whole chunk of data, which can be anything from one * byte to a set of lines and possibly just a piece of the last * line */ /* * We got a whole chunk of data, which can be anything from one byte * to a set of lines and possibly just a piece of the last line. * * TODO: To make this code work less error-prone, we need to make * sure that we read and create full lines before we compare them, * as there is really nothing that stops the proxy from delivering * the response lines in multiple parts, each part consisting of * only a little piece of the line(s). */ int i; nread += gotbytes; for(i = 0; i < gotbytes; ptr++, i++) { perline++; /* amount of bytes in this line so far */ if(*ptr=='\n') { /* a newline is CRLF in ftp-talk, so the CR is ignored as the line isn't really terminated until the LF comes */ char letter; /* Newlines are CRLF, so the CR is ignored as the line isn't really terminated until the LF comes */ if('\r' == line_start[0]) { /* end of headers */ /* end of response-headers from the proxy */ keepon=FALSE; break; /* breaks out of loop, not switch */ break; /* breaks out of for-loop, not switch() */ } /* output debug output if that is requested */ if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline); if(2 == sscanf(line_start, "HTTP/1.%d %d", /* keep a backup of the position we are about to blank */ letter = line_start[perline]; line_start[perline]=0; /* zero terminate the buffer */ if((checkprefix("WWW-Authenticate:", line_start) && (401 == httpcode)) || (checkprefix("Proxy-authenticate:", line_start) && (407 == httpcode))) { result = Curl_http_auth(conn, httpcode, line_start); if(result) return result; } else if(2 == sscanf(line_start, "HTTP/1.%d %d", &subversion, &httperror)) { &httpcode)) { ; } /* put back the letter we blanked out before */ line_start[perline]= letter; perline=0; /* line starts over here */ line_start = ptr+1; line_start = ptr+1; /* this skips the zero byte we wrote */ } } } Loading @@ -556,14 +842,17 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, if(error) return CURLE_RECV_ERROR; data->info.httpproxycode = httperror; /* Deal with the possibly already received authenticate headers. 'newurl' is set to a new URL if we must loop. */ Curl_http_auth_act(conn); if(200 != httperror) { if(407 == httperror) /* Added Nov 6 1998 */ failf(data, "Proxy requires authorization!"); else failf(data, "Received error code %d from proxy", httperror); } while(conn->newurl); /* store the HTTP code after the looping is done */ data->info.httpproxycode = httpcode; if(200 != httpcode) { failf(data, "Received HTTP code %d from proxy after CONNECT", httpcode); return CURLE_RECV_ERROR; } Loading @@ -575,7 +864,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, Curl_http_auth_stage(data, 401); /* move on to the host auth */ infof (data, "Proxy replied to CONNECT request\n"); infof (data, "Proxy replied OK to CONNECT request\n"); return CURLE_OK; } Loading Loading @@ -667,43 +956,6 @@ CURLcode Curl_http_done(struct connectdata *conn) return CURLE_OK; } static CURLcode Curl_output_basic(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { if(conn->allocptr.userpwd) free(conn->allocptr.userpwd); conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static CURLcode Curl_output_basic_proxy(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->proxyuser, conn->proxypasswd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = aprintf("Proxy-authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } void Curl_http_auth_stage(struct SessionHandle *data, int stage) { Loading @@ -730,13 +982,6 @@ CURLcode Curl_http(struct connectdata *conn) char *ptr; char *request; if(!data->state.authstage) { if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) Curl_http_auth_stage(data, 407); else Curl_http_auth_stage(data, 401); } if(!conn->proto.http) { /* Only allocate this struct if we don't already have it! */ Loading Loading @@ -773,72 +1018,10 @@ CURLcode Curl_http(struct connectdata *conn) conn->allocptr.uagent=NULL; } /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || !data->state.auth_host || curl_strequal(data->state.auth_host, conn->hostname) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ if (data->state.authstage == 407) { #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, TRUE); if(result) return result; } else #endif if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.proxy_user_passwd && !checkheaders(data, "Proxy-authorization:")) { result = Curl_output_basic_proxy(conn); if(result) return result; /* Switch to web authentication after proxy authentication is done */ Curl_http_auth_stage(data, 401); } } /* Send web authentication header if needed */ if (data->state.authstage == 401) { #ifdef GSSAPI if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) && data->state.negotiate.context && !GSS_ERROR(data->state.negotiate.status)) { result = Curl_output_negotiate(conn); if (result) return result; } else #endif #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, FALSE); if(result) return result; } else #endif { if((data->state.authwant == CURLAUTH_DIGEST) && data->state.digest.nonce) { result = Curl_output_digest(conn, (unsigned char *)request, (unsigned char *)ppath); /* setup the authentication headers */ result = http_auth_headers(conn, request, ppath); if(result) return result; } else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.user_passwd && !checkheaders(data, "Authorization:")) { result = Curl_output_basic(conn); if(result) return result; } } } } if((data->change.referer) && !checkheaders(data, "Referer:")) { if(conn->allocptr.ref) Loading lib/http.h +3 −0 Original line number Diff line number Diff line Loading @@ -43,5 +43,8 @@ void Curl_httpchunk_init(struct connectdata *conn); CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t length, ssize_t *wrote); void Curl_http_auth_stage(struct SessionHandle *data, int stage); CURLcode Curl_http_auth(struct connectdata *conn, int httpcode, char *header); void Curl_http_auth_act(struct connectdata *conn); #endif #endif lib/transfer.c +10 −111 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
lib/http.c +432 −249 Original line number Diff line number Diff line Loading @@ -105,6 +105,278 @@ static CURLcode Curl_output_basic_proxy(struct connectdata *conn); /* * This function checks the linked list of custom HTTP headers for a particular * header (prefix). */ static char *checkheaders(struct SessionHandle *data, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); for(head = data->set.headers; head; head=head->next) { if(strnequal(head->data, thisheader, thislen)) return head->data; } return NULL; } static CURLcode Curl_output_basic(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { if(conn->allocptr.userpwd) free(conn->allocptr.userpwd); conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static CURLcode Curl_output_basic_proxy(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->proxyuser, conn->proxypasswd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = aprintf("Proxy-authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } void Curl_http_auth_act(struct connectdata *conn) { struct SessionHandle *data = conn->data; if(data->state.authavail) { if(data->state.authavail & CURLAUTH_GSSNEGOTIATE) data->state.authwant = CURLAUTH_GSSNEGOTIATE; else if(data->state.authavail & CURLAUTH_DIGEST) data->state.authwant = CURLAUTH_DIGEST; else if(data->state.authavail & CURLAUTH_NTLM) data->state.authwant = CURLAUTH_NTLM; else if(data->state.authavail & CURLAUTH_BASIC) data->state.authwant = CURLAUTH_BASIC; else data->state.authwant = CURLAUTH_NONE; /* none */ if(data->state.authwant) conn->newurl = strdup(data->change.url); /* clone string */ data->state.authavail = CURLAUTH_NONE; /* clear it here */ } } /* * Setup the authentication headers for the host/proxy and the correct * authentication method. */ CURLcode http_auth_headers(struct connectdata *conn, char *request, char *path) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; if(!data->state.authstage) { if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) Curl_http_auth_stage(data, 407); else Curl_http_auth_stage(data, 401); } /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || !data->state.auth_host || curl_strequal(data->state.auth_host, conn->hostname) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ if (data->state.authstage == 407) { #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, TRUE); if(result) return result; } else #endif if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.proxy_user_passwd && !checkheaders(data, "Proxy-authorization:")) { result = Curl_output_basic_proxy(conn); if(result) return result; /* Switch to web authentication after proxy authentication is done */ Curl_http_auth_stage(data, 401); } } /* Send web authentication header if needed */ if (data->state.authstage == 401) { #ifdef GSSAPI if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) && data->state.negotiate.context && !GSS_ERROR(data->state.negotiate.status)) { result = Curl_output_negotiate(conn); if (result) return result; } else #endif #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, FALSE); if(result) return result; } else #endif { if((data->state.authwant == CURLAUTH_DIGEST) && data->state.digest.nonce) { result = Curl_output_digest(conn, (unsigned char *)request, (unsigned char *)path); if(result) return result; } else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.user_passwd && !checkheaders(data, "Authorization:")) { result = Curl_output_basic(conn); if(result) return result; } } } } return result; } /* * Curl_http_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the * proxy CONNECT loop. */ CURLcode Curl_http_auth(struct connectdata *conn, int httpcode, char *header) /* pointing to the first non-space */ { /* * This resource requires authentication */ struct SessionHandle *data = conn->data; char *start = (httpcode == 407) ? header+strlen("Proxy-authenticate:"): header+strlen("WWW-Authenticate:"); /* * Switch from proxy to web authentication and back if needed */ if (httpcode == 407 && data->state.authstage != 407) Curl_http_auth_stage(data, 407); else if (httpcode == 401 && data->state.authstage != 401) Curl_http_auth_stage(data, 401); /* pass all white spaces */ while(*start && isspace((int)*start)) start++; #ifdef GSSAPI if (checkprefix("GSS-Negotiate", start)) { if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) { /* if exactly this is wanted, go */ int neg = Curl_input_negotiate(conn, start); if (neg == 0) conn->newurl = strdup(data->change.url); } else if(data->state.authwant & CURLAUTH_GSSNEGOTIATE) data->state.authavail |= CURLAUTH_GSSNEGOTIATE; } else #endif #ifdef USE_SSLEAY /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", start)) { if(data->state.authwant == CURLAUTH_NTLM) { /* NTLM authentication is activated */ CURLntlm ntlm = Curl_input_ntlm(conn, (bool)(httpcode == 407), start); if(CURLNTLM_BAD != ntlm) conn->newurl = strdup(data->change.url); /* clone string */ else infof(data, "Authentication problem. Ignoring this.\n"); } else if(data->state.authwant & CURLAUTH_NTLM) data->state.authavail |= CURLAUTH_NTLM; } else #endif if(checkprefix("Digest", start)) { if(data->state.authwant == CURLAUTH_DIGEST) { /* Digest authentication is activated */ CURLdigest dig = CURLDIGEST_BAD; if(data->state.digest.nonce) infof(data, "Authentication problem. Ignoring this.\n"); else dig = Curl_input_digest(conn, start); if(CURLDIGEST_FINE == dig) /* We act on it. Store our new url, which happens to be the same one we already use! */ conn->newurl = strdup(data->change.url); /* clone string */ } else if(data->state.authwant & CURLAUTH_DIGEST) { /* We don't know if Digest is what we're gonna use, but we call this function anyway to store the digest data that is provided on this line, to skip the extra round-trip we need to do otherwise. We must sure to free this data! */ Curl_input_digest(conn, start); data->state.authavail |= CURLAUTH_DIGEST; } } else if(checkprefix("Basic", start)) { if((data->state.authwant == CURLAUTH_BASIC) && (httpcode == 401)) { /* We asked for Basic authentication but got a 401 back anyway, which basicly means our name+password isn't valid. */ data->state.authavail = CURLAUTH_NONE; infof(data, "Authentication problem. Ignoring this.\n"); } else if(data->state.authwant & CURLAUTH_BASIC) { data->state.authavail |= CURLAUTH_BASIC; } } return CURLE_OK; } /* fread() emulation to provide POST and/or request data */ static int readmoredata(char *buffer, size_t size, Loading Loading @@ -383,22 +655,6 @@ Curl_compareheader(char *headerline, /* line to check */ return FALSE; /* no match */ } /* * This function checks the linked list of custom HTTP headers for a particular * header (prefix). */ static char *checkheaders(struct SessionHandle *data, const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); for(head = data->set.headers; head; head=head->next) { if(strnequal(head->data, thisheader, thislen)) return head->data; } return NULL; } /* * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through Loading @@ -407,9 +663,10 @@ static char *checkheaders(struct SessionHandle *data, const char *thisheader) CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, int tunnelsocket, char *hostname, int remote_port) char *hostname, int remote_port) { int httperror=0; int httpcode=0; int subversion=0; struct SessionHandle *data=conn->data; CURLcode result; Loading @@ -425,6 +682,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, fd_set rkeepfd; fd_set readfd; char *line_start; char *host_port; #define SELECT_OK 0 #define SELECT_ERROR 1 Loading @@ -433,12 +691,22 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port); /* * This code currently only supports Basic authentication for this CONNECT * request to a proxy. */ if(conn->bits.proxy_user_passwd) Curl_output_basic_proxy(conn); do { if(conn->newurl) { /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ free(conn->newurl); conn->newurl = NULL; } host_port = aprintf("%s:%d", hostname, remote_port); if(!host_port) return CURLE_OUT_OF_MEMORY; /* Setup the proxy-authorization header, if any */ result = http_auth_headers(conn, (char *)"CONNECT", host_port); if(CURLE_OK == result) { /* OK, now send the connect request to the proxy */ result = Loading @@ -448,32 +716,22 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, "%s" "\r\n", hostname, remote_port, (conn->bits.proxy_user_passwd)?conn->allocptr.proxyuserpwd:"", (data->set.useragent?conn->allocptr.uagent:"") conn->bits.proxy_user_passwd? conn->allocptr.proxyuserpwd:"", data->set.useragent?conn->allocptr.uagent:"" ); if(result) { if(result) failf(data, "Failed sending CONNECT to proxy"); return result; } /* Now, read the full reply we get from the proxy */ if(data->set.timeout) { /* if timeout is requested, find out how much remaining time we have */ timeout = data->set.timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ if(timeout <=0 ) { failf(data, "Transfer aborted due to timeout"); return -SELECT_TIMEOUT; /* already too little time */ } } free(host_port); if(result) return result; FD_ZERO (&readfd); /* clear it */ FD_SET (tunnelsocket, &readfd); /* read socket */ /* get this in a backup variable to be able to restore it on each lap in the select() loop */ /* get this in a backup variable to be able to restore it on each lap in the select() loop */ rkeepfd = readfd; ptr=data->state.buffer; Loading @@ -485,17 +743,26 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, while((nread<BUFSIZE) && (keepon && !error)) { readfd = rkeepfd; /* set every lap */ interval.tv_sec = timeout; interval.tv_sec = 1; /* timeout each second and check the timeout */ interval.tv_usec = 0; if(data->set.timeout) { /* if timeout is requested, find out how much remaining time we have */ timeout = data->set.timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ if(timeout <=0 ) { failf(data, "Proxy connection aborted due to timeout"); error = SELECT_TIMEOUT; /* already too little time */ break; } } switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) { case -1: /* select() error, stop reading */ error = SELECT_ERROR; failf(data, "Transfer aborted due to select() error"); failf(data, "Proxy CONNECT aborted due to select() error"); break; case 0: /* timeout */ error = SELECT_TIMEOUT; failf(data, "Transfer aborted due to timeout"); break; default: /* Loading @@ -503,8 +770,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, * to read, but when we use Curl_read() it may do so. Do confirm * that this is still ok and then remove this comment! */ res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes); if(res< 0) /* EWOULDBLOCK */ continue; /* go loop yourself */ Loading @@ -513,39 +779,59 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, else if(gotbytes <= 0) { keepon = FALSE; error = SELECT_ERROR; failf(data, "Connection aborted"); failf(data, "Proxy CONNECT aborted"); } else { /* we got a whole chunk of data, which can be anything from one * byte to a set of lines and possibly just a piece of the last * line */ /* * We got a whole chunk of data, which can be anything from one byte * to a set of lines and possibly just a piece of the last line. * * TODO: To make this code work less error-prone, we need to make * sure that we read and create full lines before we compare them, * as there is really nothing that stops the proxy from delivering * the response lines in multiple parts, each part consisting of * only a little piece of the line(s). */ int i; nread += gotbytes; for(i = 0; i < gotbytes; ptr++, i++) { perline++; /* amount of bytes in this line so far */ if(*ptr=='\n') { /* a newline is CRLF in ftp-talk, so the CR is ignored as the line isn't really terminated until the LF comes */ char letter; /* Newlines are CRLF, so the CR is ignored as the line isn't really terminated until the LF comes */ if('\r' == line_start[0]) { /* end of headers */ /* end of response-headers from the proxy */ keepon=FALSE; break; /* breaks out of loop, not switch */ break; /* breaks out of for-loop, not switch() */ } /* output debug output if that is requested */ if(data->set.verbose) Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline); if(2 == sscanf(line_start, "HTTP/1.%d %d", /* keep a backup of the position we are about to blank */ letter = line_start[perline]; line_start[perline]=0; /* zero terminate the buffer */ if((checkprefix("WWW-Authenticate:", line_start) && (401 == httpcode)) || (checkprefix("Proxy-authenticate:", line_start) && (407 == httpcode))) { result = Curl_http_auth(conn, httpcode, line_start); if(result) return result; } else if(2 == sscanf(line_start, "HTTP/1.%d %d", &subversion, &httperror)) { &httpcode)) { ; } /* put back the letter we blanked out before */ line_start[perline]= letter; perline=0; /* line starts over here */ line_start = ptr+1; line_start = ptr+1; /* this skips the zero byte we wrote */ } } } Loading @@ -556,14 +842,17 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, if(error) return CURLE_RECV_ERROR; data->info.httpproxycode = httperror; /* Deal with the possibly already received authenticate headers. 'newurl' is set to a new URL if we must loop. */ Curl_http_auth_act(conn); if(200 != httperror) { if(407 == httperror) /* Added Nov 6 1998 */ failf(data, "Proxy requires authorization!"); else failf(data, "Received error code %d from proxy", httperror); } while(conn->newurl); /* store the HTTP code after the looping is done */ data->info.httpproxycode = httpcode; if(200 != httpcode) { failf(data, "Received HTTP code %d from proxy after CONNECT", httpcode); return CURLE_RECV_ERROR; } Loading @@ -575,7 +864,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, Curl_http_auth_stage(data, 401); /* move on to the host auth */ infof (data, "Proxy replied to CONNECT request\n"); infof (data, "Proxy replied OK to CONNECT request\n"); return CURLE_OK; } Loading Loading @@ -667,43 +956,6 @@ CURLcode Curl_http_done(struct connectdata *conn) return CURLE_OK; } static CURLcode Curl_output_basic(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { if(conn->allocptr.userpwd) free(conn->allocptr.userpwd); conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } static CURLcode Curl_output_basic_proxy(struct connectdata *conn) { char *authorization; struct SessionHandle *data=conn->data; sprintf(data->state.buffer, "%s:%s", conn->proxyuser, conn->proxypasswd); if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), &authorization) >= 0) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = aprintf("Proxy-authorization: Basic %s\015\012", authorization); free(authorization); } else return CURLE_OUT_OF_MEMORY; return CURLE_OK; } void Curl_http_auth_stage(struct SessionHandle *data, int stage) { Loading @@ -730,13 +982,6 @@ CURLcode Curl_http(struct connectdata *conn) char *ptr; char *request; if(!data->state.authstage) { if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) Curl_http_auth_stage(data, 407); else Curl_http_auth_stage(data, 401); } if(!conn->proto.http) { /* Only allocate this struct if we don't already have it! */ Loading Loading @@ -773,72 +1018,10 @@ CURLcode Curl_http(struct connectdata *conn) conn->allocptr.uagent=NULL; } /* To prevent the user+password to get sent to other than the original host due to a location-follow, we do some weirdo checks here */ if(!data->state.this_is_a_follow || !data->state.auth_host || curl_strequal(data->state.auth_host, conn->hostname) || data->set.http_disable_hostname_check_before_authentication) { /* Send proxy authentication header if needed */ if (data->state.authstage == 407) { #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, TRUE); if(result) return result; } else #endif if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.proxy_user_passwd && !checkheaders(data, "Proxy-authorization:")) { result = Curl_output_basic_proxy(conn); if(result) return result; /* Switch to web authentication after proxy authentication is done */ Curl_http_auth_stage(data, 401); } } /* Send web authentication header if needed */ if (data->state.authstage == 401) { #ifdef GSSAPI if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) && data->state.negotiate.context && !GSS_ERROR(data->state.negotiate.status)) { result = Curl_output_negotiate(conn); if (result) return result; } else #endif #ifdef USE_SSLEAY if(data->state.authwant == CURLAUTH_NTLM) { result = Curl_output_ntlm(conn, FALSE); if(result) return result; } else #endif { if((data->state.authwant == CURLAUTH_DIGEST) && data->state.digest.nonce) { result = Curl_output_digest(conn, (unsigned char *)request, (unsigned char *)ppath); /* setup the authentication headers */ result = http_auth_headers(conn, request, ppath); if(result) return result; } else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */ conn->bits.user_passwd && !checkheaders(data, "Authorization:")) { result = Curl_output_basic(conn); if(result) return result; } } } } if((data->change.referer) && !checkheaders(data, "Referer:")) { if(conn->allocptr.ref) Loading
lib/http.h +3 −0 Original line number Diff line number Diff line Loading @@ -43,5 +43,8 @@ void Curl_httpchunk_init(struct connectdata *conn); CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t length, ssize_t *wrote); void Curl_http_auth_stage(struct SessionHandle *data, int stage); CURLcode Curl_http_auth(struct connectdata *conn, int httpcode, char *header); void Curl_http_auth_act(struct connectdata *conn); #endif #endif