aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/http.c125
-rw-r--r--lib/http.h1
-rw-r--r--lib/http_ntlm.c5
-rw-r--r--lib/transfer.c24
-rw-r--r--lib/url.c25
-rw-r--r--lib/urldata.h8
6 files changed, 154 insertions, 34 deletions
diff --git a/lib/http.c b/lib/http.c
index a59ed8ac1..35f795725 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -93,6 +93,7 @@
#include "http_negotiate.h"
#include "url.h"
#include "share.h"
+#include "http.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -102,6 +103,8 @@
#include "memdebug.h"
#endif
+static CURLcode Curl_output_basic_proxy(struct connectdata *conn);
+
/* fread() emulation to provide POST and/or request data */
static int readmoredata(char *buffer,
size_t size,
@@ -430,6 +433,13 @@ 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);
+
/* OK, now send the connect request to the proxy */
result =
Curl_sendf(tunnelsocket, conn,
@@ -561,6 +571,8 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
Curl_safefree(conn->allocptr.proxyuserpwd);
conn->allocptr.proxyuserpwd = NULL;
+ Curl_http_auth_stage(data, 401); /* move on to the host auth */
+
infof (data, "Proxy replied to CONNECT request\n");
return CURLE_OK;
}
@@ -672,6 +684,37 @@ static CURLcode Curl_output_basic(struct connectdata *conn)
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)
+{
+ if(stage == 401)
+ data->state.authwant = data->set.httpauth;
+ else if(stage == 407)
+ data->state.authwant = data->set.proxyauth;
+ else
+ return; /* bad input stage */
+ data->state.authstage = stage;
+ data->state.authavail = CURLAUTH_NONE;
+}
+
CURLcode Curl_http(struct connectdata *conn)
{
struct SessionHandle *data=conn->data;
@@ -685,6 +728,13 @@ CURLcode Curl_http(struct connectdata *conn)
char *ptr;
char *request;
+ if(!data->state.authstage) {
+ if(conn->bits.httpproxy)
+ 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! */
@@ -728,40 +778,63 @@ CURLcode Curl_http(struct connectdata *conn)
curl_strequal(data->state.auth_host, conn->hostname) ||
data->set.http_disable_hostname_check_before_authentication) {
-#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
+ /* 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, FALSE);
- if(result)
- return result;
- }
- else
+ if(data->state.authwant == CURLAUTH_NTLM) {
+ result = Curl_output_ntlm(conn, TRUE);
+ 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);
+ 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);
}
- else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */
- conn->bits.user_passwd &&
- !checkheaders(data, "Authorization:")) {
- result = Curl_output_basic(conn);
+ }
+ /* 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);
+ 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;
+ }
+ }
}
}
diff --git a/lib/http.h b/lib/http.h
index da8e5db71..3cbbf841d 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -42,5 +42,6 @@ CURLcode Curl_http_connect(struct connectdata *conn);
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);
#endif
#endif
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index 5c6e3df4f..29615a470 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -551,7 +551,10 @@ CURLcode Curl_output_ntlm(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY; /* FIX TODO */
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
-
+
+ /* Switch to web authentication after proxy authentication is done */
+ if (proxy)
+ Curl_http_auth_stage(conn->data, 401);
}
break;
diff --git a/lib/transfer.c b/lib/transfer.c
index d9f3c8f9b..f33660812 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -726,12 +726,24 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
}
- else if(checkprefix("WWW-Authenticate:", k->p) &&
- (401 == k->httpcode)) {
+ else if((checkprefix("WWW-Authenticate:", k->p) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", k->p) &&
+ (407 == k->httpcode))) {
/*
* This page requires authentication
*/
- char *start = k->p+strlen("WWW-Authenticate:");
+ char *start = (k->httpcode == 407) ?
+ k->p+strlen("Proxy-authenticate:"):
+ k->p+strlen("WWW-Authenticate:");
+ /*
+ * Switch from proxy to web authentication and back if needed
+ */
+ if (k->httpcode == 407 && data->state.authstage != 407)
+ Curl_http_auth_stage(data, 407);
+
+ else if (k->httpcode == 401 && data->state.authstage != 401)
+ Curl_http_auth_stage(data, 401);
/* pass all white spaces */
while(*start && isspace((int)*start))
@@ -757,7 +769,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->state.authwant == CURLAUTH_NTLM) {
/* NTLM authentication is activated */
CURLntlm ntlm =
- Curl_input_ntlm(conn, FALSE, start);
+ Curl_input_ntlm(conn, k->httpcode == 407, start);
if(CURLNTLM_BAD != ntlm)
conn->newurl = strdup(data->change.url); /* clone string */
@@ -1506,8 +1518,8 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
data->state.errorbuf = FALSE; /* no error has occurred */
/* set preferred authentication, default to basic */
- data->state.authwant = data->set.httpauth?data->set.httpauth:CURLAUTH_BASIC;
- data->state.authavail = CURLAUTH_NONE; /* nothing so far */
+
+ data->state.authstage = 0; /* initialize authentication later */
/* If there was a list of cookie files to read and we haven't done it before,
do it now! */
diff --git a/lib/url.c b/lib/url.c
index 03059d84a..46245a5ce 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -312,6 +312,9 @@ CURLcode Curl_open(struct SessionHandle **curl)
data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic authentication */
+ data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic authentication */
+
/* create an array with connection data struct pointers */
data->state.numconnects = 5; /* hard-coded right now */
data->state.connects = (struct connectdata **)
@@ -878,6 +881,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
}
break;
+ case CURLOPT_PROXYAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ long auth = va_arg(param, long);
+ /* switch off bits we can't support */
+#ifndef USE_SSLEAY
+ auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
+#endif
+#ifndef GSSAPI
+ auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
+#endif
+ if(!auth)
+ return CURLE_FAILED_INIT; /* no supported types left! */
+
+ data->set.proxyauth = auth;
+ }
+ break;
+
case CURLOPT_USERPWD:
/*
* user:password to use in the operation
@@ -3066,6 +3089,7 @@ static CURLcode SetupConnection(struct connectdata *conn,
/*************************************************************
* Proxy authentication
*************************************************************/
+#if 0 /* This code is not needed anymore (moved to http.c) */
if(conn->bits.proxy_user_passwd) {
char *authorization;
snprintf(data->state.buffer, BUFSIZE, "%s:%s",
@@ -3078,6 +3102,7 @@ static CURLcode SetupConnection(struct connectdata *conn,
free(authorization);
}
}
+#endif
/*************************************************************
* Send user-agent to HTTP proxies even if the target protocol
diff --git a/lib/urldata.h b/lib/urldata.h
index 877c2e98e..a8c8dd13f 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -686,7 +686,12 @@ struct UrlState {
struct negotiatedata negotiate;
#endif
- long authwant; /* inherited from what the user set with CURLOPT_HTTPAUTH */
+ long authstage; /* 0 - authwant and authavail are still not initialized
+ 401 - web authentication is performed
+ 407 - proxy authentication is performed */
+ long authwant; /* initially set to authentication methods requested by
+ client (either with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH
+ depending on authstage) */
long authavail; /* what the server reports */
#ifdef USE_ARES
@@ -741,6 +746,7 @@ struct UserDefined {
long use_port; /* which port to use (when not using default) */
char *userpwd; /* <user:password>, if used */
long httpauth; /* what kind of HTTP authentication to use (bitmask) */
+ long proxyauth; /* what kind of proxy authentication to use (bitmask) */
char *set_range; /* range, if used. See README for detailed specification
on this syntax. */
long followlocation; /* as in HTTP Location: */