Serge Semashko added CURLOPT_PROXYAUTH support, and now NTLM for proxies
work.
This commit is contained in:
parent
3e122a765d
commit
7a19923afa
127
lib/http.c
127
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,39 +778,62 @@ 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
|
||||
#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_NTLM) {
|
||||
result = Curl_output_ntlm(conn, TRUE);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
else if((data->state.authwant == CURLAUTH_BASIC) && /* Basic */
|
||||
conn->bits.user_passwd &&
|
||||
!checkheaders(data, "Authorization:")) {
|
||||
result = Curl_output_basic(conn);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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! */
|
||||
|
25
lib/url.c
25
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
|
||||
|
@ -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: */
|
||||
|
Loading…
Reference in New Issue
Block a user