struct http_stat;
static char *create_authorization_line (const char *, const char *,
const char *, const char *,
- const char *, bool *);
+ const char *, bool *, uerr_t *);
static char *basic_authentication_encode (const char *, const char *);
static bool known_authentication_scheme_p (const char *, const char *);
static void ensure_extension (struct http_stat *, const char *, int *);
char dlbuf[SKIP_SIZE + 1];
dlbuf[SKIP_SIZE] = '\0'; /* so DEBUGP can safely print it */
- assert (contlen != -1 || contlen);
-
/* If the body is too large, it makes more sense to simply close the
connection than to try to read the body. */
if (contlen > SKIP_THRESHOLD)
} while (0)
#endif /* def __VMS [else] */
-/* The flags that allow clobbering the file (opening with "wb").
- Defined here to avoid repetition later. #### This will require
- rework. */
-#define ALLOW_CLOBBER (opt.noclobber || opt.always_rest || opt.timestamping \
- || opt.dirstruct || opt.output_document)
-
/* Retrieve a document through HTTP protocol. It recognizes status
code, and correctly handles redirections. It closes the network
socket. If it receives an error from the functions below it, it
the regular request below. */
proxyauth = NULL;
}
- /* Examples in rfc2817 use the Host header in CONNECT
- requests. I don't see how that gains anything, given
- that the contents of Host would be exactly the same as
- the contents of CONNECT. */
+ request_set_header (connreq, "Host",
+ aprintf ("%s:%d", u->host, u->port),
+ rel_value);
write_error = request_send (connreq, sock, 0);
request_free (connreq);
}
pconn.authorized = false;
+ uerr_t auth_err = RETROK;
if (!auth_finished && (user && passwd))
{
/* IIS sends multiple copies of WWW-Authenticate, one with
else if (!basic_auth_finished
|| !BEGINS_WITH (www_authenticate, "Basic"))
{
- char *pth;
- pth = url_full_path (u);
- request_set_header (req, "Authorization",
- create_authorization_line (www_authenticate,
- user, passwd,
- request_method (req),
- pth,
- &auth_finished),
- rel_value);
- if (BEGINS_WITH (www_authenticate, "NTLM"))
- ntlm_seen = true;
- else if (!u->user && BEGINS_WITH (www_authenticate, "Basic"))
+ char *pth = url_full_path (u);
+ const char *value;
+ uerr_t *auth_stat;
+ auth_stat = xmalloc (sizeof (uerr_t));
+ *auth_stat = RETROK;
+
+ value = create_authorization_line (www_authenticate,
+ user, passwd,
+ request_method (req),
+ pth,
+ &auth_finished,
+ auth_stat);
+
+ auth_err = *auth_stat;
+ if (auth_err == RETROK)
{
- /* Need to register this host as using basic auth,
- * so we automatically send creds next time. */
- register_basic_auth_host (u->host);
+ 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_null (message);
+ resp_free (resp);
+ xfree (head);
+ xfree (auth_stat);
+ goto retry_with_auth;
+ }
+ else
+ {
+ /* Creating the Authorization header went wrong */
}
- xfree (pth);
- xfree_null (message);
- resp_free (resp);
- xfree (head);
- goto retry_with_auth;
}
else
{
* give up. */
}
}
- logputs (LOG_NOTQUIET, _("Authorization failed.\n"));
request_free (req);
xfree_null (message);
resp_free (resp);
xfree (head);
- return AUTHFAILED;
+ if (auth_err == RETROK)
+ return AUTHFAILED;
+ else
+ return auth_err;
}
else /* statcode != HTTP_STATUS_UNAUTHORIZED */
{
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Cannot write to %s (%s).\n"),
quote (hstat.local_file), strerror (errno));
- case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case AUTHFAILED:
- case SSLINITFAILED: case CONTNOTSUPPORTED: case VERIFCERTERR:
- case FILEBADFILE:
+ case HOSTERR: case CONIMPOSSIBLE: case PROXERR: case SSLINITFAILED:
+ case CONTNOTSUPPORTED: case VERIFCERTERR: case FILEBADFILE:
+ case UNKNOWNATTR:
/* Fatal errors just return from the function. */
ret = err;
goto exit;
+ case ATTRMISSING:
+ /* A missing attribute in a Header is a fatal Protocol error. */
+ logputs (LOG_VERBOSE, "\n");
+ logprintf (LOG_NOTQUIET, _("Required attribute missing from Header received.\n"));
+ ret = err;
+ goto exit;
+ case AUTHFAILED:
+ logputs (LOG_VERBOSE, "\n");
+ logprintf (LOG_NOTQUIET, _("Username/Password Authentication Failed.\n"));
+ ret = err;
+ goto exit;
case WARC_ERR:
/* A fatal WARC error. */
logputs (LOG_VERBOSE, "\n");
static char *
digest_authentication_encode (const char *au, const char *user,
const char *passwd, const char *method,
- const char *path)
+ const char *path, uerr_t *auth_err)
{
static char *realm, *opaque, *nonce, *qop, *algorithm;
static struct {
param_token name, value;
- realm = opaque = nonce = qop = algorithm = NULL;
+ realm = opaque = nonce = algorithm = qop = NULL;
au += 6; /* skip over `Digest' */
while (extract_param (&au, &name, &value, ','))
if (qop != NULL && strcmp(qop,"auth"))
{
logprintf (LOG_NOTQUIET, _("Unsupported quality of protection '%s'.\n"), qop);
- user = NULL; /* force freeing mem and return */
+ xfree_null (qop); /* force freeing mem and return */
+ qop = NULL;
}
-
- if (algorithm != NULL && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
+ else if (algorithm != NULL && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
{
logprintf (LOG_NOTQUIET, _("Unsupported algorithm '%s'.\n"), algorithm);
- user = NULL; /* force freeing mem and return */
+ xfree_null (qop); /* force freeing mem and return */
+ qop = NULL;
}
- if (!realm || !nonce || !user || !passwd || !path || !method)
+ if (!realm || !nonce || !user || !passwd || !path || !method || !qop)
{
xfree_null (realm);
xfree_null (opaque);
xfree_null (nonce);
xfree_null (qop);
xfree_null (algorithm);
+ if (!qop)
+ *auth_err = UNKNOWNATTR;
+ else
+ *auth_err = ATTRMISSING;
return NULL;
}
dump_hash (a1buf, hash);
- if (! strcmp (algorithm, "MD5-sess"))
+ if (algorithm && !strcmp (algorithm, "MD5-sess"))
{
/* A1BUF = H( H(user ":" realm ":" password) ":" nonce ":" cnonce ) */
snprintf (cnonce, sizeof (cnonce), "%08x", random_number(INT_MAX));
md5_finish_ctx (&ctx, hash);
dump_hash (a2buf, hash);
- if (!strcmp(qop, "auth") || !strcmp (qop, "auth-int"))
+ if (qop && (!strcmp(qop, "auth") || !strcmp (qop, "auth-int")))
{
/* RFC 2617 Digest Access Authentication */
/* generate random hex string */
res = xmalloc (res_size);
- if (!strcmp(qop,"auth"))
+ if (qop && !strcmp (qop, "auth"))
{
res_len = snprintf (res, res_size, "Digest "\
"username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\""\
snprintf(res + res_len, res_size - res_len, ", algorithm=\"%s\"", algorithm);
}
}
+
+ xfree_null (realm);
+ xfree_null (opaque);
+ xfree_null (nonce);
+ xfree_null (qop);
+ xfree_null (algorithm);
+
return res;
}
#endif /* ENABLE_DIGEST */
static char *
create_authorization_line (const char *au, const char *user,
const char *passwd, const char *method,
- const char *path, bool *finished)
+ const char *path, bool *finished, uerr_t *auth_err)
{
/* We are called only with known schemes, so we can dispatch on the
first letter. */
#ifdef ENABLE_DIGEST
case 'D': /* Digest */
*finished = true;
- return digest_authentication_encode (au, user, passwd, method, path);
+ return digest_authentication_encode (au, user, passwd, method, path, auth_err);
#endif
#ifdef ENABLE_NTLM
case 'N': /* NTLM */