aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/lukemftp/src/fetch.c
diff options
context:
space:
mode:
authorMike Heffner <mikeh@FreeBSD.org>2005-02-20 17:33:34 +0000
committerMike Heffner <mikeh@FreeBSD.org>2005-02-20 17:33:34 +0000
commit90580277219d71354d55ed572fca05ccbec50a31 (patch)
treeb3e525aeb6db7ad0b9e566173c63af30b14693ce /contrib/lukemftp/src/fetch.c
parent7e475d60f53f104292ac3b1c0015eeb52678c424 (diff)
downloadsrc-90580277219d71354d55ed572fca05ccbec50a31.tar.gz
src-90580277219d71354d55ed572fca05ccbec50a31.zip
Import the latest CVS version of lukemftp.
Short list of changes: * SIGINT termination from auto-fetch. * Less trusting of remote filenames during auto mgets. * Improved RFC2616 compliancy. * Fix globs when using ftp reget (from mat@). * Limit send buffer size.
Notes
Notes: svn path=/vendor/lukemftp/dist/; revision=142129
Diffstat (limited to 'contrib/lukemftp/src/fetch.c')
-rw-r--r--contrib/lukemftp/src/fetch.c242
1 files changed, 137 insertions, 105 deletions
diff --git a/contrib/lukemftp/src/fetch.c b/contrib/lukemftp/src/fetch.c
index abb89ce15946..f2e776363858 100644
--- a/contrib/lukemftp/src/fetch.c
+++ b/contrib/lukemftp/src/fetch.c
@@ -1,7 +1,7 @@
-/* $NetBSD: fetch.c,v 1.146 2003/12/10 12:34:28 lukem Exp $ */
+/* $NetBSD: fetch.c,v 1.155 2005/01/12 22:37:41 lukem Exp $ */
/*-
- * Copyright (c) 1997-2003 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -41,7 +41,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: fetch.c,v 1.146 2003/12/10 12:34:28 lukem Exp $");
+__RCSID("$NetBSD: fetch.c,v 1.155 2005/01/12 22:37:41 lukem Exp $");
#endif /* not lint */
/*
@@ -83,11 +83,14 @@ typedef enum {
} url_t;
void aborthttp(int);
+#ifndef NO_AUTH
static int auth_url(const char *, char **, const char *, const char *);
-static void base64_encode(const u_char *, size_t, u_char *);
+static void base64_encode(const unsigned char *, size_t, unsigned char *);
+#endif
static int go_fetch(const char *);
static int fetch_ftp(const char *);
static int fetch_url(const char *, const char *, char *, char *);
+static const char *match_token(const char **, const char *);
static int parse_url(const char *, const char *, url_t *, char **,
char **, char **, char **, in_port_t *, char **);
static void url_decode(char *);
@@ -95,6 +98,11 @@ static void url_decode(char *);
static int redirect_loop;
+#define STRNEQUAL(a,b) (strncasecmp((a), (b), sizeof((b))-1) == 0)
+#define ISLWS(x) ((x)=='\r' || (x)=='\n' || (x)==' ' || (x)=='\t')
+#define SKIPLWS(x) do { while (ISLWS((*x))) x++; } while (0)
+
+
#define ABOUT_URL "about:" /* propaganda */
#define FILE_URL "file://" /* file URL prefix */
#define FTP_URL "ftp://" /* ftp URL prefix */
@@ -102,6 +110,35 @@ static int redirect_loop;
/*
+ * Determine if token is the next word in buf (case insensitive).
+ * If so, advance buf past the token and any trailing LWS, and
+ * return a pointer to the token (in buf). Otherwise, return NULL.
+ * token may be preceeded by LWS.
+ * token must be followed by LWS or NUL. (I.e, don't partial match).
+ */
+static const char *
+match_token(const char **buf, const char *token)
+{
+ const char *p, *orig;
+ size_t tlen;
+
+ tlen = strlen(token);
+ p = *buf;
+ SKIPLWS(p);
+ orig = p;
+ if (strncasecmp(p, token, tlen) != 0)
+ return NULL;
+ p += tlen;
+ if (*p != '\0' && !ISLWS(*p))
+ return NULL;
+ SKIPLWS(p);
+ orig = *buf;
+ *buf = p;
+ return orig;
+}
+
+#ifndef NO_AUTH
+/*
* Generate authorization response based on given authentication challenge.
* Returns -1 if an error occurred, otherwise 0.
* Sets response to a malloc(3)ed string; caller should free.
@@ -110,52 +147,52 @@ static int
auth_url(const char *challenge, char **response, const char *guser,
const char *gpass)
{
- char *cp, *ep, *clear, *line, *realm, *scheme;
+ const char *cp, *scheme;
+ char *ep, *clear, *realm;
char user[BUFSIZ], *pass;
int rval;
size_t len, clen, rlen;
*response = NULL;
- clear = realm = scheme = NULL;
+ clear = realm = NULL;
rval = -1;
- line = xstrdup(challenge);
- cp = line;
+ cp = challenge;
+ scheme = "Basic"; /* only support Basic authentication */
if (debug)
fprintf(ttyout, "auth_url: challenge `%s'\n", challenge);
- scheme = strsep(&cp, " ");
-#define SCHEME_BASIC "Basic"
- if (strncasecmp(scheme, SCHEME_BASIC, sizeof(SCHEME_BASIC) - 1) != 0) {
- warnx("Unsupported WWW Authentication challenge - `%s'",
+ if (! match_token(&cp, scheme)) {
+ warnx("Unsupported authentication challenge - `%s'",
challenge);
goto cleanup_auth_url;
}
- cp += strspn(cp, " ");
#define REALM "realm=\""
- if (strncasecmp(cp, REALM, sizeof(REALM) - 1) == 0)
+ if (STRNEQUAL(cp, REALM))
cp += sizeof(REALM) - 1;
else {
- warnx("Unsupported WWW Authentication challenge - `%s'",
+ warnx("Unsupported authentication challenge - `%s'",
challenge);
goto cleanup_auth_url;
}
+/* XXX: need to improve quoted-string parsing to support \ quoting, etc. */
if ((ep = strchr(cp, '\"')) != NULL) {
size_t len = ep - cp;
realm = (char *)xmalloc(len + 1);
(void)strlcpy(realm, cp, len + 1);
} else {
- warnx("Unsupported WWW Authentication challenge - `%s'",
+ warnx("Unsupported authentication challenge - `%s'",
challenge);
goto cleanup_auth_url;
}
- if (guser != NULL)
+ fprintf(ttyout, "Username for `%s': ", realm);
+ if (guser != NULL) {
(void)strlcpy(user, guser, sizeof(user));
- else {
- fprintf(ttyout, "Username for `%s': ", realm);
+ fprintf(ttyout, "%s\n", user);
+ } else {
(void)fflush(ttyout);
if (fgets(user, sizeof(user) - 1, stdin) == NULL) {
clearerr(stdin);
@@ -181,13 +218,13 @@ auth_url(const char *challenge, char **response, const char *guser,
*response = (char *)xmalloc(rlen);
(void)strlcpy(*response, scheme, rlen);
len = strlcat(*response, " ", rlen);
- base64_encode(clear, clen, (u_char *)*response + len);
+ /* use `clen - 1' to not encode the trailing NUL */
+ base64_encode(clear, clen - 1, (unsigned char *)*response + len);
memset(clear, 0, clen);
rval = 0;
cleanup_auth_url:
FREEPTR(clear);
- FREEPTR(line);
FREEPTR(realm);
return (rval);
}
@@ -197,11 +234,11 @@ auth_url(const char *challenge, char **response, const char *guser,
* which should be at least ((len + 2) * 4 / 3 + 1) in size.
*/
static void
-base64_encode(const u_char *clear, size_t len, u_char *encoded)
+base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded)
{
- static const u_char enc[] =
+ static const unsigned char enc[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- u_char *cp;
+ unsigned char *cp;
int i;
cp = encoded;
@@ -217,6 +254,7 @@ base64_encode(const u_char *clear, size_t len, u_char *encoded)
while (i-- > len)
*(--cp) = '=';
}
+#endif
/*
* Decode %xx escapes in given string, `in-place'.
@@ -295,17 +333,17 @@ parse_url(const char *url, const char *desc, url_t *type,
*portnum = 0;
tport = NULL;
- if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
+ if (STRNEQUAL(url, HTTP_URL)) {
url += sizeof(HTTP_URL) - 1;
*type = HTTP_URL_T;
*portnum = HTTP_PORT;
tport = httpport;
- } else if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
+ } else if (STRNEQUAL(url, FTP_URL)) {
url += sizeof(FTP_URL) - 1;
*type = FTP_URL_T;
*portnum = FTP_PORT;
tport = ftpport;
- } else if (strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
+ } else if (STRNEQUAL(url, FILE_URL)) {
url += sizeof(FILE_URL) - 1;
*type = FILE_URL_T;
} else {
@@ -347,6 +385,9 @@ parse_url(const char *url, const char *desc, url_t *type,
*cp = '\0';
*pass = xstrdup(cp + 1);
}
+ url_decode(*user);
+ if (*pass)
+ url_decode(*pass);
}
#ifdef INET6
@@ -435,7 +476,8 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
size_t len;
static size_t bufsize;
static char *xferbuf;
- char *cp, *ep, *buf, *savefile;
+ const char *cp, *token;
+ char *ep, *buf, *savefile;
char *auth, *location, *message;
char *user, *pass, *host, *port, *path, *decodedpath;
char *puser, *ppass, *useragent;
@@ -515,7 +557,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
goto cleanup_fetch_url;
} else {
if (debug)
- fprintf(ttyout, "got savefile as `%s'\n", savefile);
+ fprintf(ttyout, "savefile `%s'\n", savefile);
}
restart_point = 0;
@@ -788,7 +830,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
warn("Receiving HTTP reply");
goto cleanup_fetch_url;
}
- while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))
+ while (len > 0 && (ISLWS(buf[len-1])))
buf[--len] = '\0';
if (debug)
fprintf(ttyout, "received `%s'\n", buf);
@@ -805,28 +847,27 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
message = xstrdup(cp);
/* Read the rest of the header. */
- FREEPTR(buf);
while (1) {
+ FREEPTR(buf);
if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0))
== NULL) {
warn("Receiving HTTP reply");
goto cleanup_fetch_url;
}
- while (len > 0 &&
- (buf[len-1] == '\r' || buf[len-1] == '\n'))
+ while (len > 0 && (ISLWS(buf[len-1])))
buf[--len] = '\0';
if (len == 0)
break;
if (debug)
fprintf(ttyout, "received `%s'\n", buf);
- /* Look for some headers */
+ /*
+ * Look for some headers
+ */
+
cp = buf;
-#define CONTENTLEN "Content-Length: "
- if (strncasecmp(cp, CONTENTLEN,
- sizeof(CONTENTLEN) - 1) == 0) {
- cp += sizeof(CONTENTLEN) - 1;
+ if (match_token(&cp, "Content-Length:")) {
filesize = STRTOLL(cp, &ep, 10);
if (filesize < 0 || *ep != '\0')
goto improper;
@@ -835,13 +876,12 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
"parsed len as: " LLF "\n",
(LLT)filesize);
-#define CONTENTRANGE "Content-Range: bytes "
- } else if (strncasecmp(cp, CONTENTRANGE,
- sizeof(CONTENTRANGE) - 1) == 0) {
- cp += sizeof(CONTENTRANGE) - 1;
- if (*cp == '*') {
- ep = cp + 1;
- }
+ } else if (match_token(&cp, "Content-Range:")) {
+ if (! match_token(&cp, "bytes"))
+ goto improper;
+
+ if (*cp == '*')
+ cp++;
else {
rangestart = STRTOLL(cp, &ep, 10);
if (rangestart < 0 || *ep != '-')
@@ -850,19 +890,20 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
rangeend = STRTOLL(cp, &ep, 10);
if (rangeend < 0 || rangeend < rangestart)
goto improper;
+ cp = ep;
}
- if (*ep != '/')
+ if (*cp != '/')
goto improper;
- cp = ep + 1;
- if (*cp == '*') {
- ep = cp + 1;
- }
+ cp++;
+ if (*cp == '*')
+ cp++;
else {
entitylen = STRTOLL(cp, &ep, 10);
if (entitylen < 0)
goto improper;
+ cp = ep;
}
- if (*ep != '\0')
+ if (*cp != '\0')
goto improper;
if (debug) {
@@ -881,13 +922,10 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
goto cleanup_fetch_url;
}
-#define LASTMOD "Last-Modified: "
- } else if (strncasecmp(cp, LASTMOD,
- sizeof(LASTMOD) - 1) == 0) {
+ } else if (match_token(&cp, "Last-Modified:")) {
struct tm parsed;
char *t;
- cp += sizeof(LASTMOD) - 1;
/* RFC 1123 */
if ((t = strptime(cp,
"%a, %d %b %Y %H:%M:%S GMT",
@@ -910,29 +948,22 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
}
-#define LOCATION "Location: "
- } else if (strncasecmp(cp, LOCATION,
- sizeof(LOCATION) - 1) == 0) {
- cp += sizeof(LOCATION) - 1;
+ } else if (match_token(&cp, "Location:")) {
location = xstrdup(cp);
if (debug)
fprintf(ttyout,
- "parsed location as: %s\n", cp);
+ "parsed location as `%s'\n", cp);
-#define TRANSENC "Transfer-Encoding: "
- } else if (strncasecmp(cp, TRANSENC,
- sizeof(TRANSENC) - 1) == 0) {
- cp += sizeof(TRANSENC) - 1;
- if (strcasecmp(cp, "binary") == 0) {
+ } else if (match_token(&cp, "Transfer-Encoding:")) {
+ if (match_token(&cp, "binary")) {
warnx(
- "Bogus transfer encoding - `%s' (fetching anyway)",
- cp);
+ "Bogus transfer encoding - `binary' (fetching anyway)");
continue;
}
- if (strcasecmp(cp, "chunked") != 0) {
+ if (! (token = match_token(&cp, "chunked"))) {
warnx(
"Unsupported transfer encoding - `%s'",
- cp);
+ token);
goto cleanup_fetch_url;
}
ischunked++;
@@ -940,26 +971,20 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
fprintf(ttyout,
"using chunked encoding\n");
-#define PROXYAUTH "Proxy-Authenticate: "
- } else if (strncasecmp(cp, PROXYAUTH,
- sizeof(PROXYAUTH) - 1) == 0) {
- cp += sizeof(PROXYAUTH) - 1;
- FREEPTR(auth);
- auth = xstrdup(cp);
- if (debug)
- fprintf(ttyout,
- "parsed proxy-auth as: %s\n", cp);
-
-#define WWWAUTH "WWW-Authenticate: "
- } else if (strncasecmp(cp, WWWAUTH,
- sizeof(WWWAUTH) - 1) == 0) {
- cp += sizeof(WWWAUTH) - 1;
+ } else if (match_token(&cp, "Proxy-Authenticate:")
+ || match_token(&cp, "WWW-Authenticate:")) {
+ if (! (token = match_token(&cp, "Basic"))) {
+ if (debug)
+ fprintf(ttyout,
+ "skipping unknown auth scheme `%s'\n",
+ token);
+ continue;
+ }
FREEPTR(auth);
- auth = xstrdup(cp);
+ auth = xstrdup(token);
if (debug)
fprintf(ttyout,
- "parsed www-auth as: %s\n", cp);
-
+ "parsed auth as `%s'\n", cp);
}
}
@@ -1002,18 +1027,13 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
rval = go_fetch(location);
}
goto cleanup_fetch_url;
+#ifndef NO_AUTH
case 401:
case 407:
{
char **authp;
char *auser, *apass;
- fprintf(ttyout, "%s\n", message);
- if (EMPTYSTRING(auth)) {
- warnx(
- "No authentication challenge provided by server");
- goto cleanup_fetch_url;
- }
if (hcode == 401) {
authp = &wwwauth;
auser = user;
@@ -1023,6 +1043,14 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
auser = puser;
apass = ppass;
}
+ if (verbose || *authp == NULL ||
+ auser == NULL || apass == NULL)
+ fprintf(ttyout, "%s\n", message);
+ if (EMPTYSTRING(auth)) {
+ warnx(
+ "No authentication challenge provided by server");
+ goto cleanup_fetch_url;
+ }
if (*authp != NULL) {
char reply[10];
@@ -1032,10 +1060,9 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
== NULL) {
clearerr(stdin);
goto cleanup_fetch_url;
- } else {
- if (tolower(reply[0]) != 'y')
- goto cleanup_fetch_url;
}
+ if (tolower((unsigned char)reply[0]) != 'y')
+ goto cleanup_fetch_url;
auser = NULL;
apass = NULL;
}
@@ -1047,6 +1074,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
goto cleanup_fetch_url;
}
+#endif
default:
if (message)
warnx("Error retrieving file - `%s'", message);
@@ -1273,6 +1301,7 @@ aborthttp(int notused)
char msgbuf[100];
int len;
+ sigint_raised = 1;
alarmtimer(0);
len = strlcpy(msgbuf, "\nHTTP fetch aborted.\n", sizeof(msgbuf));
write(fileno(ttyout), msgbuf, len);
@@ -1299,7 +1328,7 @@ fetch_ftp(const char *url)
rval = 1;
type = TYPE_I;
- if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
+ if (STRNEQUAL(url, FTP_URL)) {
if ((parse_url(url, "URL", &urltype, &user, &pass,
&host, &port, &portnum, &path) == -1) ||
(user != NULL && *user == '\0') ||
@@ -1307,8 +1336,6 @@ fetch_ftp(const char *url)
warnx("Invalid URL `%s'", url);
goto cleanup_fetch_ftp;
}
- url_decode(user);
- url_decode(pass);
/*
* Note: Don't url_decode(path) here. We need to keep the
* distinction between "/" and "%2F" until later.
@@ -1570,7 +1597,10 @@ fetch_ftp(const char *url)
ointeractive = interactive;
interactive = 0;
- xargv[0] = "mget";
+ if (restartautofetch)
+ xargv[0] = "mreget";
+ else
+ xargv[0] = "mget";
mget(xargc, xargv);
interactive = ointeractive;
} else {
@@ -1618,10 +1648,11 @@ go_fetch(const char *url)
{
char *proxy;
+#ifndef NO_ABOUT
/*
* Check for about:*
*/
- if (strncasecmp(url, ABOUT_URL, sizeof(ABOUT_URL) - 1) == 0) {
+ if (STRNEQUAL(url, ABOUT_URL)) {
url += sizeof(ABOUT_URL) -1;
if (strcasecmp(url, "ftp") == 0 ||
strcasecmp(url, "tnftp") == 0) {
@@ -1651,12 +1682,12 @@ go_fetch(const char *url)
fputs("\n", ttyout);
return (0);
}
+#endif
/*
* Check for file:// and http:// URLs.
*/
- if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
- strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0)
+ if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL))
return (fetch_url(url, NULL, NULL, NULL));
/*
@@ -1665,8 +1696,7 @@ go_fetch(const char *url)
* Othewise, use fetch_ftp().
*/
proxy = getoptionvalue("ftp_proxy");
- if (!EMPTYSTRING(proxy) &&
- strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0)
+ if (!EMPTYSTRING(proxy) && STRNEQUAL(url, FTP_URL))
return (fetch_url(url, NULL, NULL, NULL));
return (fetch_ftp(url));
@@ -1695,7 +1725,9 @@ auto_fetch(int argc, char *argv[])
if (sigsetjmp(toplevel, 1)) {
if (connected)
disconnect(0, NULL);
- return (argpos + 1);
+ if (rval > 0)
+ rval = argpos + 1;
+ return (rval);
}
(void)xsignal(SIGINT, intr);
(void)xsignal(SIGPIPE, lostpeer);