Add rudimentary support for an authentication callback function.

This commit is contained in:
Dag-Erling Smørgrav 2001-05-26 19:37:15 +00:00
parent 2b26f942d3
commit 6490b215b3
4 changed files with 91 additions and 59 deletions

View File

@ -39,7 +39,7 @@
#include "fetch.h"
#include "common.h"
auth_t fetchAuthMethod;
int fetchLastErrCode;
char fetchLastErrString[MAXERRSTRING];
int fetchTimeout;

View File

@ -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

View File

@ -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 */

View File

@ -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;