summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libfetch/fetch.c2
-rw-r--r--lib/libfetch/fetch.h6
-rw-r--r--lib/libfetch/ftp.c86
-rw-r--r--lib/libfetch/http.c56
4 files changed, 91 insertions, 59 deletions
diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c
index de23f00..720c745 100644
--- a/lib/libfetch/fetch.c
+++ b/lib/libfetch/fetch.c
@@ -39,7 +39,7 @@
#include "fetch.h"
#include "common.h"
-
+auth_t fetchAuthMethod;
int fetchLastErrCode;
char fetchLastErrString[MAXERRSTRING];
int fetchTimeout;
diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h
index dc5fc05..cca0d1f 100644
--- a/lib/libfetch/fetch.h
+++ b/lib/libfetch/fetch.h
@@ -55,7 +55,7 @@ struct url_stat {
};
struct url_ent {
- char name[MAXPATHLEN];
+ char name[PATH_MAX];
struct url_stat stat;
};
@@ -125,6 +125,10 @@ struct url *fetchMakeURL(const char *, const char *, int,
struct url *fetchParseURL(const char *);
void fetchFreeURL(struct url *);
+/* Authentication */
+typedef int (*auth_t)(struct url *);
+extern auth_t fetchAuthMethod;
+
/* Last error code */
extern int fetchLastErrCode;
#define MAXERRSTRING 256
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
index 0cc9910..ff7bf86 100644
--- a/lib/libfetch/ftp.c
+++ b/lib/libfetch/ftp.c
@@ -712,6 +712,49 @@ ouch:
}
/*
+ * Authenticate
+ */
+static int
+_ftp_authenticate(int cd, struct url *url, struct url *purl)
+{
+ char *user, *pwd, *logname;
+ char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
+ int e, len;
+
+ /* XXX FTP_AUTH, and maybe .netrc */
+
+ /* send user name and password */
+ user = url->user;
+ if (!user || !*user)
+ user = getenv("FTP_LOGIN");
+ if (!user || !*user)
+ user = FTP_ANONYMOUS_USER;
+ if (purl && url->port == _fetch_default_port(url->scheme))
+ e = _ftp_cmd(cd, "USER %s@%s", user, url->host);
+ else if (purl)
+ e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port);
+ else
+ e = _ftp_cmd(cd, "USER %s", user);
+
+ /* did the server request a password? */
+ if (e == FTP_NEED_PASSWORD) {
+ pwd = url->pwd;
+ if (!pwd || !*pwd)
+ pwd = getenv("FTP_PASSWORD");
+ if (!pwd || !*pwd) {
+ if ((logname = getlogin()) == 0)
+ logname = FTP_ANONYMOUS_USER;
+ len = snprintf(pbuf, MAXLOGNAME + 1, "%s@", logname);
+ gethostname(pbuf + len, sizeof pbuf - len);
+ pwd = pbuf;
+ }
+ e = _ftp_cmd(cd, "PASS %s", pwd);
+ }
+
+ return e;
+}
+
+/*
* Log on to FTP server
*/
static int
@@ -723,11 +766,6 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
#else
int af = AF_INET;
#endif
- const char *logname;
- const char *user;
- const char *pwd;
- char localhost[MAXHOSTNAMELEN];
- char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
direct = CHECK_FLAG('d');
verbose = CHECK_FLAG('v');
@@ -758,45 +796,11 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
/* expect welcome message */
if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY)
goto fouch;
-
- /* XXX FTP_AUTH, and maybe .netrc */
- /* send user name and password */
- user = url->user;
- if (!user || !*user)
- user = getenv("FTP_LOGIN");
- if (!user || !*user)
- user = FTP_ANONYMOUS_USER;
- if (purl && url->port == _fetch_default_port(url->scheme))
- e = _ftp_cmd(cd, "USER %s@%s", user, url->host);
- else if (purl)
- e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port);
- else
- e = _ftp_cmd(cd, "USER %s", user);
-
- /* did the server request a password? */
- if (e == FTP_NEED_PASSWORD) {
- pwd = url->pwd;
- if (!pwd || !*pwd)
- pwd = getenv("FTP_PASSWORD");
- if (!pwd || !*pwd) {
- if ((logname = getlogin()) == 0)
- logname = FTP_ANONYMOUS_USER;
- gethostname(localhost, sizeof localhost);
- snprintf(pbuf, sizeof pbuf, "%s@%s", logname, localhost);
- pwd = pbuf;
- }
- e = _ftp_cmd(cd, "PASS %s", pwd);
- }
-
- /* did the server request an account? */
- if (e == FTP_NEED_ACCOUNT)
+ /* authenticate */
+ if ((e = _ftp_authenticate(cd, url, purl)) != FTP_LOGGED_IN)
goto fouch;
- /* we should be done by now */
- if (e != FTP_LOGGED_IN)
- goto fouch;
-
/* might as well select mode and type at once */
#ifdef FTP_FORCE_STREAM_MODE
if ((e = _ftp_cmd(cd, "MODE S")) != FTP_OK) /* default is S */
diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c
index b1332b3..77c3a2d 100644
--- a/lib/libfetch/http.c
+++ b/lib/libfetch/http.c
@@ -294,7 +294,8 @@ typedef enum {
hdr_content_range,
hdr_last_modified,
hdr_location,
- hdr_transfer_encoding
+ hdr_transfer_encoding,
+ hdr_www_authenticate
} hdr;
/* Names of interesting headers */
@@ -307,6 +308,7 @@ static struct {
{ hdr_last_modified, "Last-Modified" },
{ hdr_location, "Location" },
{ hdr_transfer_encoding, "Transfer-Encoding" },
+ { hdr_www_authenticate, "WWW-Authenticate" },
{ hdr_unknown, NULL },
};
@@ -564,6 +566,8 @@ _http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
char *upw, *auth;
int r;
+ DEBUG(fprintf(stderr, "usr: [\033[1m%s\033[m]\n", usr));
+ DEBUG(fprintf(stderr, "pwd: [\033[1m%s\033[m]\n", pwd));
if (asprintf(&upw, "%s:%s", usr, pwd) == -1)
return -1;
auth = _http_base64(upw);
@@ -705,16 +709,16 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
n = noredirect ? 1 : MAX_REDIRECT;
i = 0;
+ need_auth = 0;
do {
new = NULL;
chunked = 0;
- need_auth = 0;
offset = 0;
clength = -1;
length = -1;
size = -1;
mtime = 0;
- retry:
+
/* check port */
if (!url->port)
url->port = _fetch_default_port(url->scheme);
@@ -743,6 +747,12 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
op, url->doc);
}
+ /* virtual host */
+ if (url->port == _fetch_default_port(url->scheme))
+ _http_cmd(fd, "Host: %s", host);
+ else
+ _http_cmd(fd, "Host: %s:%d", host, url->port);
+
/* proxy authorization */
if (purl) {
if (*purl->user || *purl->pwd)
@@ -753,22 +763,20 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
}
/* server authorization */
- if (need_auth) {
+ if (need_auth || *url->user || *url->pwd) {
if (*url->user || *url->pwd)
_http_basic_auth(fd, "Authorization", url->user, url->pwd);
else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0')
_http_authorize(fd, "Authorization", p);
- else {
+ else if (fetchAuthMethod && fetchAuthMethod(url) == 0) {
+ _http_basic_auth(fd, "Authorization", url->user, url->pwd);
+ } else {
_http_seterr(HTTP_NEED_AUTH);
goto ouch;
}
}
/* other headers */
- if (url->port == _fetch_default_port(url->scheme))
- _http_cmd(fd, "Host: %s", host);
- else
- _http_cmd(fd, "Host: %s:%d", host, url->port);
_http_cmd(fd, "User-Agent: %s " _LIBFETCH_VER, __progname);
if (url->offset)
_http_cmd(fd, "Range: bytes=%lld-", url->offset);
@@ -800,9 +808,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
/* try again, but send the password this time */
if (verbose)
_fetch_info("server requires authorization");
- need_auth = 1;
- close(fd);
- goto retry;
+ break;
case HTTP_NEED_PROXY_AUTH:
/*
* If we're talking to a proxy, we already sent our proxy
@@ -867,6 +873,11 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
/* XXX weak test*/
chunked = (strcasecmp(p, "chunked") == 0);
break;
+ case hdr_www_authenticate:
+ if (code != HTTP_NEED_AUTH)
+ break;
+ /* if we were smarter, we'd check the method and realm */
+ break;
case hdr_end:
/* fall through */
case hdr_unknown:
@@ -875,19 +886,32 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
}
} while (h > hdr_end);
- /* we either have a hit, or a redirect with no Location: header */
- if (code == HTTP_OK || code == HTTP_PARTIAL || !new)
+ /* we have a hit */
+ if (code == HTTP_OK || code == HTTP_PARTIAL)
break;
- /* we have a redirect */
+ /* we need to provide authentication */
+ if (code == HTTP_NEED_AUTH) {
+ need_auth = 1;
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ /* all other cases: we got a redirect */
+ need_auth = 0;
close(fd);
fd = -1;
+ if (!new) {
+ DEBUG(fprintf(stderr, "redirect with no new location\n"));
+ break;
+ }
if (url != URL)
fetchFreeURL(url);
url = new;
} while (++i < n);
- /* no success */
+ /* we failed, or ran out of retries */
if (fd == -1) {
_http_seterr(code);
goto ouch;
OpenPOWER on IntegriCloud