diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2003-06-06 06:45:25 +0000 |
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2003-06-06 06:45:25 +0000 |
| commit | c8f917b63af1e5deeb5c4e3e19bd48cc465d3440 (patch) | |
| tree | dbe60d62fdbb88a865a5e56488d0a1ecb60b6244 /lib/libfetch | |
| parent | 65650f20962d6a32092be2cba47ef0c730342802 (diff) | |
Notes
Diffstat (limited to 'lib/libfetch')
| -rw-r--r-- | lib/libfetch/common.c | 134 | ||||
| -rw-r--r-- | lib/libfetch/common.h | 2 | ||||
| -rw-r--r-- | lib/libfetch/fetch.3 | 13 | ||||
| -rw-r--r-- | lib/libfetch/fetch.c | 8 | ||||
| -rw-r--r-- | lib/libfetch/ftp.c | 25 | ||||
| -rw-r--r-- | lib/libfetch/http.c | 13 |
6 files changed, 173 insertions, 22 deletions
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c index 5a2313d914ab..ac67fd0192c6 100644 --- a/lib/libfetch/common.c +++ b/lib/libfetch/common.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <netdb.h> +#include <pwd.h> #include <stdarg.h> #include <stdlib.h> #include <stdio.h> @@ -226,6 +227,28 @@ _fetch_ref(conn_t *conn) /* + * Bind a socket to a specific local address + */ +int +_fetch_bind(int sd, int af, const char *addr) +{ + struct addrinfo hints, *res, *res0; + int err; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) + return (-1); + for (res = res0; res; res = res->ai_next) + if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) + return (0); + return (-1); +} + + +/* * Establish a TCP connection to the specified port on the specified host. */ conn_t * @@ -233,6 +256,7 @@ _fetch_connect(const char *host, int port, int af, int verbose) { conn_t *conn; char pbuf[10]; + const char *bindaddr; struct addrinfo hints, *res, *res0; int sd, err; @@ -251,19 +275,25 @@ _fetch_connect(const char *host, int port, int af, int verbose) _netdb_seterr(err); return (NULL); } + bindaddr = getenv("FETCH_BIND_ADDRESS"); if (verbose) _fetch_info("connecting to %s:%d", host, port); /* try to connect */ - for (sd = -1, res = res0; res; res = res->ai_next) { + for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { if ((sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) continue; - if (connect(sd, res->ai_addr, res->ai_addrlen) != -1) + if (bindaddr != NULL && *bindaddr != '\0' && + _fetch_bind(sd, res->ai_family, bindaddr) != 0) { + _fetch_info("failed to bind to '%s'", bindaddr); + close(sd); + continue; + } + if (connect(sd, res->ai_addr, res->ai_addrlen) == 0) break; close(sd); - sd = -1; } freeaddrinfo(res0); if (sd == -1) { @@ -457,7 +487,7 @@ _fetch_write(conn_t *conn, const char *buf, size_t len) { struct iovec iov; - iov.iov_base = buf; + iov.iov_base = (char *)buf; iov.iov_len = len; return _fetch_writev(conn, &iov, 1); } @@ -531,7 +561,7 @@ _fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) } if (iovcnt > 0) { iov->iov_len -= wlen; - iov->iov_base = iov->iov_base + wlen; + iov->iov_base = (char *)iov->iov_base + wlen; } } return (total); @@ -548,9 +578,9 @@ _fetch_putln(conn_t *conn, const char *str, size_t len) int ret; DEBUG(fprintf(stderr, ">>> %s\n", str)); - iov[0].iov_base = str; + iov[0].iov_base = (char *)str; iov[0].iov_len = len; - iov[1].iov_base = ENDL; + iov[1].iov_base = (char *)ENDL; iov[1].iov_len = sizeof(ENDL); if (len == 0) ret = _fetch_writev(conn, &iov[1], 1); @@ -611,3 +641,93 @@ _fetch_add_entry(struct url_ent **p, int *size, int *len, return (0); } + + +/*** Authentication-related utility functions ********************************/ + +static const char * +_fetch_read_word(FILE *f) +{ + static char word[1024]; + + if (fscanf(f, " %1024s ", word) != 1) + return (NULL); + return (word); +} + +/* + * Get authentication data for a URL from .netrc + */ +int +_fetch_netrc_auth(struct url *url) +{ + char fn[PATH_MAX]; + const char *word; + char *p; + FILE *f; + + if ((p = getenv("NETRC")) != NULL) { + if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { + _fetch_info("$NETRC specifies a file name " + "longer than PATH_MAX"); + return (-1); + } + } else { + if ((p = getenv("HOME")) != NULL) { + struct passwd *pwd; + + if ((pwd = getpwuid(getuid())) == NULL || + (p = pwd->pw_dir) == NULL) + return (-1); + } + if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) + return (-1); + } + + if ((f = fopen(fn, "r")) == NULL) + return (-1); + while ((word = _fetch_read_word(f)) != NULL) { + if (strcmp(word, "default") == 0) { + DEBUG(_fetch_info("Using default .netrc settings")); + break; + } + if (strcmp(word, "machine") == 0 && + (word = _fetch_read_word(f)) != NULL && + strcasecmp(word, url->host) == 0) { + DEBUG(_fetch_info("Using .netrc settings for %s", word)); + break; + } + } + if (word == NULL) + goto ferr; + while ((word = _fetch_read_word(f)) != NULL) { + if (strcmp(word, "login") == 0) { + if ((word = _fetch_read_word(f)) == NULL) + goto ferr; + if (snprintf(url->user, sizeof(url->user), + "%s", word) > (int)sizeof(url->user)) { + _fetch_info("login name in .netrc is too long"); + url->user[0] = '\0'; + } + } else if (strcmp(word, "password") == 0) { + if ((word = _fetch_read_word(f)) == NULL) + goto ferr; + if (snprintf(url->pwd, sizeof(url->pwd), + "%s", word) > (int)sizeof(url->pwd)) { + _fetch_info("password in .netrc is too long"); + url->pwd[0] = '\0'; + } + } else if (strcmp(word, "account") == 0) { + if ((word = _fetch_read_word(f)) == NULL) + goto ferr; + /* XXX not supported! */ + } else { + break; + } + } + fclose(f); + return (0); + ferr: + fclose(f); + return (-1); +} diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h index 4b42bf2324f8..6f652593076a 100644 --- a/lib/libfetch/common.h +++ b/lib/libfetch/common.h @@ -76,6 +76,7 @@ void _fetch_syserr(void); void _fetch_info(const char *, ...); int _fetch_default_port(const char *); int _fetch_default_proxy_port(const char *); +int _fetch_bind(int, int, const char *); conn_t *_fetch_connect(const char *, int, int, int); conn_t *_fetch_reopen(int); conn_t *_fetch_ref(conn_t *); @@ -88,6 +89,7 @@ int _fetch_putln(conn_t *, const char *, size_t); int _fetch_close(conn_t *); int _fetch_add_entry(struct url_ent **, int *, int *, const char *, struct url_stat *); +int _fetch_netrc_auth(struct url *url); #define _ftp_seterr(n) _fetch_seterr(_ftp_errlist, n) #define _http_seterr(n) _fetch_seterr(_http_errlist, n) diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3 index 4bd63bde9594..0e107d07f97a 100644 --- a/lib/libfetch/fetch.3 +++ b/lib/libfetch/fetch.3 @@ -444,7 +444,10 @@ Invalid URL The accompanying error message includes a protocol-specific error code and message, e.g. "File is not available (404 Not Found)" .Sh ENVIRONMENT -.Bl -tag -width FTP_PASSIVE_MODE +.Bl -tag -width ".Ev FETCH_BIND_ADDRESS" +.It Ev FETCH_BIND_ADDRESS +Specifies a hostname or IP address to which sockets used for outgoing +connections will be bound. .It Ev FTP_LOGIN Default FTP login if none was provided in the URL. .It Ev FTP_PASSIVE_MODE @@ -520,6 +523,14 @@ the document URL will be used as referrer URL. Specifies the User-Agent string to use for HTTP requests. This can be useful when working with HTTP origin or proxy servers that differentiate between user agents. +.It Ev NETRC +Specifies a file to use instead of +.Pa ~/.netrc +to look up login names and passwords for FTP sites. +See +.Xr ftp 1 +for a description of the file format. +This feature is experimental. .El .Sh SEE ALSO .Xr fetch 1 , diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c index a7d310bfd39c..59ee8a849f5f 100644 --- a/lib/libfetch/fetch.c +++ b/lib/libfetch/fetch.c @@ -77,6 +77,10 @@ fetchXGet(struct url *URL, struct url_stat *us, const char *flags) int direct; direct = CHECK_FLAG('d'); + if (us != NULL) { + us->size = -1; + us->atime = us->mtime = 0; + } if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) return (fetchXGetFile(URL, us, flags)); else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) @@ -131,6 +135,10 @@ fetchStat(struct url *URL, struct url_stat *us, const char *flags) int direct; direct = CHECK_FLAG('d'); + if (us != NULL) { + us->size = -1; + us->atime = us->mtime = 0; + } if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) return (fetchStatFile(URL, us, flags)); else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index a24a67d90875..91940d3af22b 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -730,10 +730,12 @@ _ftp_authenticate(conn_t *conn, struct url *url, struct url *purl) /* XXX FTP_AUTH, and maybe .netrc */ /* send user name and password */ + if (url->user[0] == '\0') + _fetch_netrc_auth(url); user = url->user; - if (!user || !*user) + if (*user == '\0') user = getenv("FTP_LOGIN"); - if (!user || !*user) + if (user == NULL || *user == '\0') user = FTP_ANONYMOUS_USER; if (purl && url->port == _fetch_default_port(url->scheme)) e = _ftp_cmd(conn, "USER %s@%s", user, url->host); @@ -745,9 +747,9 @@ _ftp_authenticate(conn_t *conn, struct url *url, struct url *purl) /* did the server request a password? */ if (e == FTP_NEED_PASSWORD) { pwd = url->pwd; - if (!pwd || !*pwd) + if (*pwd == '\0') pwd = getenv("FTP_PASSWORD"); - if (!pwd || !*pwd) { + if (pwd == NULL || *pwd == '\0') { if ((logname = getlogin()) == 0) logname = FTP_ANONYMOUS_USER; if ((len = snprintf(pbuf, MAXLOGNAME + 1, "%s@", logname)) < 0) @@ -887,11 +889,13 @@ _ftp_cached_connect(struct url *url, struct url *purl, const char *flags) * Check the proxy settings */ static struct url * -_ftp_get_proxy(void) +_ftp_get_proxy(const char *flags) { struct url *purl; char *p; + if (flags != NULL && strchr(flags, 'd') != NULL) + return (NULL); if (((p = getenv("FTP_PROXY")) || (p = getenv("ftp_proxy")) || (p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) && *p && (purl = fetchParseURL(p)) != NULL) { @@ -968,7 +972,7 @@ _ftp_request(struct url *url, const char *op, struct url_stat *us, FILE * fetchXGetFTP(struct url *url, struct url_stat *us, const char *flags) { - return (_ftp_request(url, "RETR", us, _ftp_get_proxy(), flags)); + return (_ftp_request(url, "RETR", us, _ftp_get_proxy(flags), flags)); } /* @@ -987,8 +991,8 @@ FILE * fetchPutFTP(struct url *url, const char *flags) { - return _ftp_request(url, CHECK_FLAG('a') ? "APPE" : "STOR", NULL, - _ftp_get_proxy(), flags); + return (_ftp_request(url, CHECK_FLAG('a') ? "APPE" : "STOR", NULL, + _ftp_get_proxy(flags), flags)); } /* @@ -997,9 +1001,12 @@ fetchPutFTP(struct url *url, const char *flags) int fetchStatFTP(struct url *url, struct url_stat *us, const char *flags) { + FILE *f; - if (_ftp_request(url, "STAT", us, _ftp_get_proxy(), flags) == NULL) + f = _ftp_request(url, "STAT", us, _ftp_get_proxy(flags), flags); + if (f == NULL) return (-1); + fclose(f); return (0); } diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 7dbcdd75392d..86f7075268fd 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -696,11 +696,13 @@ _http_connect(struct url *URL, struct url *purl, const char *flags) } static struct url * -_http_get_proxy(void) +_http_get_proxy(const char *flags) { struct url *purl; char *p; + if (flags != NULL && strchr(flags, 'd') != NULL) + return (NULL); if (((p = getenv("HTTP_PROXY")) || (p = getenv("http_proxy"))) && (purl = fetchParseURL(p))) { if (!*purl->scheme) @@ -887,7 +889,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us, _http_cmd(conn, "User-Agent: %s", p); else _http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname()); - if (url->offset) + if (url->offset > 0) _http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset); _http_cmd(conn, "Connection: close"); _http_cmd(conn, ""); @@ -1059,7 +1061,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us, } /* too far? */ - if (offset > URL->offset) { + if (URL->offset > 0 && offset > URL->offset) { _http_seterr(HTTP_PROTOCOL_ERROR); goto ouch; } @@ -1108,7 +1110,7 @@ ouch: FILE * fetchXGetHTTP(struct url *URL, struct url_stat *us, const char *flags) { - return (_http_request(URL, "GET", us, _http_get_proxy(), flags)); + return (_http_request(URL, "GET", us, _http_get_proxy(flags), flags)); } /* @@ -1138,7 +1140,8 @@ fetchStatHTTP(struct url *URL, struct url_stat *us, const char *flags) { FILE *f; - if ((f = _http_request(URL, "HEAD", us, _http_get_proxy(), flags)) == NULL) + f = _http_request(URL, "HEAD", us, _http_get_proxy(flags), flags); + if (f == NULL) return (-1); fclose(f); return (0); |
