http: split Curl_http_input_auth into sub functions

Simplifies things. Increases readability a lot.

Fixes #16412
Reported-by: Viktor Szakats
Closes #16416
This commit is contained in:
Daniel Stenberg 2025-02-21 09:07:41 +01:00
parent fc4addbe50
commit e47a94228f
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 153 additions and 113 deletions

View File

@ -884,6 +884,132 @@ static bool authcmp(const char *auth, const char *line)
} }
#endif #endif
#ifdef USE_SPNEGO
static CURLcode auth_spnego(struct Curl_easy *data,
bool proxy,
const char *auth,
struct auth *authp,
unsigned long *availp)
{
if((authp->avail & CURLAUTH_NEGOTIATE) || Curl_auth_is_spnego_supported()) {
*availp |= CURLAUTH_NEGOTIATE;
authp->avail |= CURLAUTH_NEGOTIATE;
if(authp->picked == CURLAUTH_NEGOTIATE) {
struct connectdata *conn = data->conn;
CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
&conn->http_negotiate_state;
if(!result) {
free(data->req.newurl);
data->req.newurl = strdup(data->state.url);
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
data->state.authproblem = FALSE;
/* we received a GSS auth token and we dealt with it fine */
*negstate = GSS_AUTHRECV;
}
else
data->state.authproblem = TRUE;
}
}
return CURLE_OK;
}
#endif
#ifdef USE_NTLM
static CURLcode auth_ntlm(struct Curl_easy *data,
bool proxy,
const char *auth,
struct auth *authp,
unsigned long *availp)
{
/* NTLM support requires the SSL crypto libs */
if((authp->avail & CURLAUTH_NTLM) || Curl_auth_is_ntlm_supported()) {
*availp |= CURLAUTH_NTLM;
authp->avail |= CURLAUTH_NTLM;
if(authp->picked == CURLAUTH_NTLM) {
/* NTLM authentication is picked and activated */
CURLcode result = Curl_input_ntlm(data, proxy, auth);
if(!result)
data->state.authproblem = FALSE;
else {
infof(data, "NTLM authentication problem, ignoring.");
data->state.authproblem = TRUE;
}
}
}
return CURLE_OK;
}
#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
static CURLcode auth_digest(struct Curl_easy *data,
bool proxy,
const char *auth,
struct auth *authp,
unsigned long *availp)
{
if(authp->avail & CURLAUTH_DIGEST)
infof(data, "Ignoring duplicate digest auth header.");
else if(Curl_auth_is_digest_supported()) {
CURLcode result;
*availp |= CURLAUTH_DIGEST;
authp->avail |= CURLAUTH_DIGEST;
/* We call this function on input Digest headers even if Digest
* authentication is not activated yet, as we need to store the
* incoming data from this header in case we are going to use
* Digest */
result = Curl_input_digest(data, proxy, auth);
if(result) {
infof(data, "Digest authentication problem, ignoring.");
data->state.authproblem = TRUE;
}
}
return CURLE_OK;
}
#endif
#ifndef CURL_DISABLE_BASIC_AUTH
static CURLcode auth_basic(struct Curl_easy *data,
struct auth *authp,
unsigned long *availp)
{
*availp |= CURLAUTH_BASIC;
authp->avail |= CURLAUTH_BASIC;
if(authp->picked == CURLAUTH_BASIC) {
/* We asked for Basic authentication but got a 40X back
anyway, which basically means our name+password is not
valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Basic authentication problem, ignoring.");
data->state.authproblem = TRUE;
}
return CURLE_OK;
}
#endif
#ifndef CURL_DISABLE_BEARER_AUTH
static CURLcode auth_bearer(struct Curl_easy *data,
struct auth *authp,
unsigned long *availp)
{
*availp |= CURLAUTH_BEARER;
authp->avail |= CURLAUTH_BEARER;
if(authp->picked == CURLAUTH_BEARER) {
/* We asked for Bearer authentication but got a 40X back
anyway, which basically means our token is not valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Bearer authentication problem, ignoring.");
data->state.authproblem = TRUE;
}
return CURLE_OK;
}
#endif
/* /*
* Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
* headers. They are dealt with both in the transfer.c main loop and in the * headers. They are dealt with both in the transfer.c main loop and in the
@ -895,11 +1021,6 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
/* /*
* This resource requires authentication * This resource requires authentication
*/ */
struct connectdata *conn = data->conn;
#ifdef USE_SPNEGO
curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
&conn->http_negotiate_state;
#endif
#if defined(USE_SPNEGO) || \ #if defined(USE_SPNEGO) || \
defined(USE_NTLM) || \ defined(USE_NTLM) || \
!defined(CURL_DISABLE_DIGEST_AUTH) || \ !defined(CURL_DISABLE_DIGEST_AUTH) || \
@ -908,6 +1029,9 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
unsigned long *availp; unsigned long *availp;
struct auth *authp; struct auth *authp;
CURLcode result = CURLE_OK;
DEBUGASSERT(auth);
DEBUGASSERT(data);
if(proxy) { if(proxy) {
availp = &data->info.proxyauthavail; availp = &data->info.proxyauthavail;
@ -917,11 +1041,6 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
availp = &data->info.httpauthavail; availp = &data->info.httpauthavail;
authp = &data->state.authhost; authp = &data->state.authhost;
} }
#else
(void) proxy;
#endif
(void) conn; /* In case conditionals make it unused. */
/* /*
* Here we check if we want the specific single authentication (using ==) and * Here we check if we want the specific single authentication (using ==) and
@ -941,124 +1060,44 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
while(*auth) { while(*auth) {
#ifdef USE_SPNEGO #ifdef USE_SPNEGO
if(authcmp("Negotiate", auth)) { if(authcmp("Negotiate", auth))
if((authp->avail & CURLAUTH_NEGOTIATE) || result = auth_spnego(data, proxy, auth, authp, availp);
Curl_auth_is_spnego_supported()) {
*availp |= CURLAUTH_NEGOTIATE;
authp->avail |= CURLAUTH_NEGOTIATE;
if(authp->picked == CURLAUTH_NEGOTIATE) {
CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
if(!result) {
free(data->req.newurl);
data->req.newurl = strdup(data->state.url);
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
data->state.authproblem = FALSE;
/* we received a GSS auth token and we dealt with it fine */
*negstate = GSS_AUTHRECV;
}
else
data->state.authproblem = TRUE;
}
}
}
else
#endif #endif
#ifdef USE_NTLM #ifdef USE_NTLM
/* NTLM support requires the SSL crypto libs */ if(!result && authcmp("NTLM", auth))
if(authcmp("NTLM", auth)) { result = auth_ntlm(data, proxy, auth, authp, availp);
if((authp->avail & CURLAUTH_NTLM) ||
Curl_auth_is_ntlm_supported()) {
*availp |= CURLAUTH_NTLM;
authp->avail |= CURLAUTH_NTLM;
if(authp->picked == CURLAUTH_NTLM) {
/* NTLM authentication is picked and activated */
CURLcode result = Curl_input_ntlm(data, proxy, auth);
if(!result) {
data->state.authproblem = FALSE;
}
else {
infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
}
}
else
#endif #endif
#ifndef CURL_DISABLE_DIGEST_AUTH #ifndef CURL_DISABLE_DIGEST_AUTH
if(authcmp("Digest", auth)) { if(!result && authcmp("Digest", auth))
if((authp->avail & CURLAUTH_DIGEST) != 0) result = auth_digest(data, proxy, auth, authp, availp);
infof(data, "Ignoring duplicate digest auth header.");
else if(Curl_auth_is_digest_supported()) {
CURLcode result;
*availp |= CURLAUTH_DIGEST;
authp->avail |= CURLAUTH_DIGEST;
/* We call this function on input Digest headers even if Digest
* authentication is not activated yet, as we need to store the
* incoming data from this header in case we are going to use
* Digest */
result = Curl_input_digest(data, proxy, auth);
if(result) {
infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
}
else
#endif #endif
#ifndef CURL_DISABLE_BASIC_AUTH #ifndef CURL_DISABLE_BASIC_AUTH
if(authcmp("Basic", auth)) { if(!result && authcmp("Basic", auth))
*availp |= CURLAUTH_BASIC; result = auth_basic(data, authp, availp);
authp->avail |= CURLAUTH_BASIC;
if(authp->picked == CURLAUTH_BASIC) {
/* We asked for Basic authentication but got a 40X back
anyway, which basically means our name+password is not
valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
else
#endif #endif
#ifndef CURL_DISABLE_BEARER_AUTH #ifndef CURL_DISABLE_BEARER_AUTH
if(authcmp("Bearer", auth)) { if(authcmp("Bearer", auth))
*availp |= CURLAUTH_BEARER; result = auth_bearer(data, authp, availp);
authp->avail |= CURLAUTH_BEARER;
if(authp->picked == CURLAUTH_BEARER) {
/* We asked for Bearer authentication but got a 40X back
anyway, which basically means our token is not valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
#else
{
/*
* Empty block to terminate the if-else chain correctly.
*
* A semicolon would yield the same result here, but can cause a
* compiler warning when -Wextra is enabled.
*/
}
#endif #endif
if(result)
break;
/* there may be multiple methods on one line, so keep reading */ /* there may be multiple methods on one line, so keep reading */
while(*auth && *auth != ',') /* read up to the next comma */ auth = strchr(auth, ',');
if(auth) /* if we are on a comma, skip it */
auth++; auth++;
if(*auth == ',') /* if we are on a comma, skip it */ else
auth++; break;
while(ISSPACE(*auth)) while(ISBLANK(*auth))
auth++; auth++;
} }
#else
(void) proxy;
/* nothing to do when disabled */
#endif
return CURLE_OK; return result;
} }
/** /**

View File

@ -131,6 +131,7 @@ CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
/* These functions are in http.c */ /* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth); const char *auth);
CURLcode Curl_http_auth_act(struct Curl_easy *data); CURLcode Curl_http_auth_act(struct Curl_easy *data);
/* follow a redirect or not */ /* follow a redirect or not */