mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
Factor out some auth gethttp code
* src/http.c (gethttp): Move some code in... (check_auth): ... a new function.
This commit is contained in:
parent
8aa63e482e
commit
14bbc18512
270
src/http.c
270
src/http.c
@ -2114,6 +2114,141 @@ check_file_output (struct url *u, struct http_stat *hs,
|
|||||||
return RETROK;
|
return RETROK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uerr_t
|
||||||
|
check_auth (struct url *u, char *user, char *passwd, struct response *resp,
|
||||||
|
struct request *req, bool *ntlm_seen_ref, bool *retry,
|
||||||
|
bool *basic_auth_finished_ref, bool *auth_finished_ref)
|
||||||
|
{
|
||||||
|
uerr_t auth_err = RETROK;
|
||||||
|
bool basic_auth_finished = *basic_auth_finished_ref;
|
||||||
|
bool auth_finished = *auth_finished_ref;
|
||||||
|
bool ntlm_seen = *ntlm_seen_ref;
|
||||||
|
*retry = false;
|
||||||
|
if (!auth_finished && (user && passwd))
|
||||||
|
{
|
||||||
|
/* IIS sends multiple copies of WWW-Authenticate, one with
|
||||||
|
the value "negotiate", and other(s) with data. Loop over
|
||||||
|
all the occurrences and pick the one we recognize. */
|
||||||
|
int wapos;
|
||||||
|
char *buf;
|
||||||
|
const char *www_authenticate = NULL;
|
||||||
|
const char *wabeg, *waend;
|
||||||
|
const char *digest = NULL, *basic = NULL, *ntlm = NULL;
|
||||||
|
for (wapos = 0; !ntlm
|
||||||
|
&& (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
|
||||||
|
&wabeg, &waend)) != -1;
|
||||||
|
++wapos)
|
||||||
|
{
|
||||||
|
param_token name, value;
|
||||||
|
|
||||||
|
BOUNDED_TO_ALLOCA (wabeg, waend, buf);
|
||||||
|
www_authenticate = buf;
|
||||||
|
|
||||||
|
for (;!ntlm;)
|
||||||
|
{
|
||||||
|
/* extract the auth-scheme */
|
||||||
|
while (c_isspace (*www_authenticate)) www_authenticate++;
|
||||||
|
name.e = name.b = www_authenticate;
|
||||||
|
while (*name.e && !c_isspace (*name.e)) name.e++;
|
||||||
|
|
||||||
|
if (name.b == name.e)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DEBUGP (("Auth scheme found '%.*s'\n", (int) (name.e - name.b), name.b));
|
||||||
|
|
||||||
|
if (known_authentication_scheme_p (name.b, name.e))
|
||||||
|
{
|
||||||
|
if (BEGINS_WITH (name.b, "NTLM"))
|
||||||
|
{
|
||||||
|
ntlm = name.b;
|
||||||
|
break; /* this is the most secure challenge, stop here */
|
||||||
|
}
|
||||||
|
else if (!digest && BEGINS_WITH (name.b, "Digest"))
|
||||||
|
digest = name.b;
|
||||||
|
else if (!basic && BEGINS_WITH (name.b, "Basic"))
|
||||||
|
basic = name.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now advance over the auth-params */
|
||||||
|
www_authenticate = name.e;
|
||||||
|
DEBUGP (("Auth param list '%s'\n", www_authenticate));
|
||||||
|
while (extract_param (&www_authenticate, &name, &value, ',', NULL) && name.b && value.b)
|
||||||
|
{
|
||||||
|
DEBUGP (("Auth param %.*s=%.*s\n",
|
||||||
|
(int) (name.e - name.b), name.b, (int) (value.e - value.b), value.b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!basic && !digest && !ntlm)
|
||||||
|
{
|
||||||
|
/* If the authentication header is missing or
|
||||||
|
unrecognized, there's no sense in retrying. */
|
||||||
|
logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
|
||||||
|
}
|
||||||
|
else if (!basic_auth_finished
|
||||||
|
|| !basic)
|
||||||
|
{
|
||||||
|
char *pth = url_full_path (u);
|
||||||
|
const char *value;
|
||||||
|
uerr_t *auth_stat;
|
||||||
|
auth_stat = xmalloc (sizeof (uerr_t));
|
||||||
|
*auth_stat = RETROK;
|
||||||
|
|
||||||
|
if (ntlm)
|
||||||
|
www_authenticate = ntlm;
|
||||||
|
else if (digest)
|
||||||
|
www_authenticate = digest;
|
||||||
|
else
|
||||||
|
www_authenticate = basic;
|
||||||
|
|
||||||
|
logprintf (LOG_NOTQUIET, _("Authentication selected: %s\n"), www_authenticate);
|
||||||
|
|
||||||
|
value = create_authorization_line (www_authenticate,
|
||||||
|
user, passwd,
|
||||||
|
request_method (req),
|
||||||
|
pth,
|
||||||
|
&auth_finished,
|
||||||
|
auth_stat);
|
||||||
|
|
||||||
|
auth_err = *auth_stat;
|
||||||
|
if (auth_err == RETROK)
|
||||||
|
{
|
||||||
|
request_set_header (req, "Authorization", value, rel_value);
|
||||||
|
|
||||||
|
if (BEGINS_WITH (www_authenticate, "NTLM"))
|
||||||
|
ntlm_seen = true;
|
||||||
|
else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
|
||||||
|
{
|
||||||
|
/* Need to register this host as using basic auth,
|
||||||
|
* so we automatically send creds next time. */
|
||||||
|
register_basic_auth_host (u->host);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (pth);
|
||||||
|
xfree (auth_stat);
|
||||||
|
*retry = true;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Creating the Authorization header went wrong */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We already did Basic auth, and it failed. Gotta
|
||||||
|
* give up. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
*ntlm_seen_ref = ntlm_seen;
|
||||||
|
*basic_auth_finished_ref = basic_auth_finished;
|
||||||
|
*auth_finished_ref = auth_finished;
|
||||||
|
return auth_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Retrieve a document through HTTP protocol. It recognizes status
|
/* Retrieve a document through HTTP protocol. It recognizes status
|
||||||
code, and correctly handles redirections. It closes the network
|
code, and correctly handles redirections. It closes the network
|
||||||
socket. If it receives an error from the functions below it, it
|
socket. If it receives an error from the functions below it, it
|
||||||
@ -2488,7 +2623,7 @@ read_header:
|
|||||||
{
|
{
|
||||||
/* Authorization is required. */
|
/* Authorization is required. */
|
||||||
uerr_t auth_err = RETROK;
|
uerr_t auth_err = RETROK;
|
||||||
|
bool retry;
|
||||||
/* Normally we are not interested in the response body.
|
/* Normally we are not interested in the response body.
|
||||||
But if we are writing a WARC file we are: we like to keep everyting. */
|
But if we are writing a WARC file we are: we like to keep everyting. */
|
||||||
if (warc_enabled)
|
if (warc_enabled)
|
||||||
@ -2525,126 +2660,21 @@ read_header:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pconn.authorized = false;
|
pconn.authorized = false;
|
||||||
if (!auth_finished && (user && passwd))
|
|
||||||
{
|
|
||||||
/* IIS sends multiple copies of WWW-Authenticate, one with
|
|
||||||
the value "negotiate", and other(s) with data. Loop over
|
|
||||||
all the occurrences and pick the one we recognize. */
|
|
||||||
int wapos;
|
|
||||||
char *buf;
|
|
||||||
const char *www_authenticate = NULL;
|
|
||||||
const char *wabeg, *waend;
|
|
||||||
const char *digest = NULL, *basic = NULL, *ntlm = NULL;
|
|
||||||
for (wapos = 0; !ntlm
|
|
||||||
&& (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
|
|
||||||
&wabeg, &waend)) != -1;
|
|
||||||
++wapos)
|
|
||||||
{
|
|
||||||
param_token name, value;
|
|
||||||
|
|
||||||
BOUNDED_TO_ALLOCA (wabeg, waend, buf);
|
{
|
||||||
www_authenticate = buf;
|
auth_err = check_auth (u, user, passwd, resp, req,
|
||||||
|
&ntlm_seen, &retry,
|
||||||
for (;!ntlm;)
|
&basic_auth_finished,
|
||||||
{
|
&auth_finished);
|
||||||
/* extract the auth-scheme */
|
if (auth_err == RETROK && retry)
|
||||||
while (c_isspace (*www_authenticate)) www_authenticate++;
|
{
|
||||||
name.e = name.b = www_authenticate;
|
xfree (hs->message);
|
||||||
while (*name.e && !c_isspace (*name.e)) name.e++;
|
resp_free (resp);
|
||||||
|
xfree (message);
|
||||||
if (name.b == name.e)
|
xfree (head);
|
||||||
break;
|
goto retry_with_auth;
|
||||||
|
}
|
||||||
DEBUGP (("Auth scheme found '%.*s'\n", (int) (name.e - name.b), name.b));
|
}
|
||||||
|
|
||||||
if (known_authentication_scheme_p (name.b, name.e))
|
|
||||||
{
|
|
||||||
if (BEGINS_WITH (name.b, "NTLM"))
|
|
||||||
{
|
|
||||||
ntlm = name.b;
|
|
||||||
break; /* this is the most secure challenge, stop here */
|
|
||||||
}
|
|
||||||
else if (!digest && BEGINS_WITH (name.b, "Digest"))
|
|
||||||
digest = name.b;
|
|
||||||
else if (!basic && BEGINS_WITH (name.b, "Basic"))
|
|
||||||
basic = name.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now advance over the auth-params */
|
|
||||||
www_authenticate = name.e;
|
|
||||||
DEBUGP (("Auth param list '%s'\n", www_authenticate));
|
|
||||||
while (extract_param (&www_authenticate, &name, &value, ',', NULL) && name.b && value.b)
|
|
||||||
{
|
|
||||||
DEBUGP (("Auth param %.*s=%.*s\n",
|
|
||||||
(int) (name.e - name.b), name.b, (int) (value.e - value.b), value.b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!basic && !digest && !ntlm)
|
|
||||||
{
|
|
||||||
/* If the authentication header is missing or
|
|
||||||
unrecognized, there's no sense in retrying. */
|
|
||||||
logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
|
|
||||||
}
|
|
||||||
else if (!basic_auth_finished
|
|
||||||
|| !basic)
|
|
||||||
{
|
|
||||||
char *pth = url_full_path (u);
|
|
||||||
const char *value;
|
|
||||||
uerr_t *auth_stat;
|
|
||||||
auth_stat = xmalloc (sizeof (uerr_t));
|
|
||||||
*auth_stat = RETROK;
|
|
||||||
|
|
||||||
if (ntlm)
|
|
||||||
www_authenticate = ntlm;
|
|
||||||
else if (digest)
|
|
||||||
www_authenticate = digest;
|
|
||||||
else
|
|
||||||
www_authenticate = basic;
|
|
||||||
|
|
||||||
logprintf (LOG_NOTQUIET, _("Authentication selected: %s\n"), www_authenticate);
|
|
||||||
|
|
||||||
value = create_authorization_line (www_authenticate,
|
|
||||||
user, passwd,
|
|
||||||
request_method (req),
|
|
||||||
pth,
|
|
||||||
&auth_finished,
|
|
||||||
auth_stat);
|
|
||||||
|
|
||||||
auth_err = *auth_stat;
|
|
||||||
if (auth_err == RETROK)
|
|
||||||
{
|
|
||||||
request_set_header (req, "Authorization", value, rel_value);
|
|
||||||
|
|
||||||
if (BEGINS_WITH (www_authenticate, "NTLM"))
|
|
||||||
ntlm_seen = true;
|
|
||||||
else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
|
|
||||||
{
|
|
||||||
/* Need to register this host as using basic auth,
|
|
||||||
* so we automatically send creds next time. */
|
|
||||||
register_basic_auth_host (u->host);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree (pth);
|
|
||||||
xfree (message);
|
|
||||||
resp_free (resp);
|
|
||||||
xfree (head);
|
|
||||||
xfree (auth_stat);
|
|
||||||
xfree (hs->message);
|
|
||||||
goto retry_with_auth;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Creating the Authorization header went wrong */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* We already did Basic auth, and it failed. Gotta
|
|
||||||
* give up. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
request_free (req);
|
request_free (req);
|
||||||
xfree (message);
|
xfree (message);
|
||||||
resp_free (resp);
|
resp_free (resp);
|
||||||
|
Loading…
Reference in New Issue
Block a user