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
char *head;
struct response *resp;
- char hdrval[256];
+ char hdrval[512];
char *message;
/* Declare WARC variables. */
exec_name, quote (relevant->host));
return HOSTERR;
}
+ else if (sock != -1)
+ {
+ sock = -1;
+ }
}
if (sock < 0)
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 */
{
/* Send preliminary HEAD request if -N is given and we have an existing
* destination file. */
- file_name = url_file_name (opt.trustservernames ? u : original_url, NULL);
+ if (!opt.output_document)
+ file_name = url_file_name (opt.trustservernames ? u : original_url, NULL);
+ else
+ file_name = xstrdup (opt.output_document);
if (opt.timestamping && (file_exists_p (file_name)
|| opt.content_disposition))
send_head_first = true;
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 */