Add rudimentary support for an authentication callback function.
This commit is contained in:
parent
2b26f942d3
commit
6490b215b3
@ -39,7 +39,7 @@
|
||||
#include "fetch.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
auth_t fetchAuthMethod;
|
||||
int fetchLastErrCode;
|
||||
char fetchLastErrString[MAXERRSTRING];
|
||||
int fetchTimeout;
|
||||
|
@ -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
|
||||
|
@ -711,6 +711,49 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user