From 0a27a97192fc09d92b5f67b3ce4b9b1c6b4c8c56 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Fri, 8 Nov 2002 03:30:18 +0000 Subject: http redirect support; adapted from NetBSD. --- usr.bin/ftp/Makefile | 6 +- usr.bin/ftp/extern.h | 4 +- usr.bin/ftp/fetch.c | 176 +++++++++++++++++++++++++++------------------------ usr.bin/ftp/util.c | 8 +-- 4 files changed, 102 insertions(+), 92 deletions(-) (limited to 'usr.bin/ftp') diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile index d43c32af5cc..2f1dc3a49d4 100644 --- a/usr.bin/ftp/Makefile +++ b/usr.bin/ftp/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.18 2000/09/07 01:57:35 todd Exp $ +# $OpenBSD: Makefile,v 1.19 2002/11/08 03:30:17 fgsch Exp $ # Define SMALL to disable command line editing #CFLAGS+=-DSMALL @@ -17,8 +17,8 @@ SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c ruserpass.c \ CPPFLAGS+= -DINET6 -LDADD+= -ledit -lcurses -DPADD+= ${LIBEDIT} ${LIBCURSES} +LDADD+= -ledit -lcurses -lutil +DPADD+= ${LIBEDIT} ${LIBCURSES} ${LIBUTIL} #COPTS+= -Wall -Wconversion -Wstrict-prototypes -Wmissing-prototypes diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h index 02602055249..92b2a2fcfaf 100644 --- a/usr.bin/ftp/extern.h +++ b/usr.bin/ftp/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.23 2002/05/30 06:51:46 deraadt Exp $ */ +/* $OpenBSD: extern.h,v 1.24 2002/11/08 03:30:17 fgsch Exp $ */ /* $NetBSD: extern.h,v 1.17 1997/08/18 10:20:19 lukem Exp $ */ /* @@ -112,7 +112,7 @@ void intr(void); int isurl(const char *); void list_vertical(StringList *); void lcd(int, char **); -int login(const char *, char *, char *); +int ftp_login(const char *, char *, char *); void lostpeer(void); void lpwd(int, char **); void ls(int, char **); diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c index ad03aa0e807..e0042aa68f6 100644 --- a/usr.bin/ftp/fetch.c +++ b/usr.bin/ftp/fetch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fetch.c,v 1.39 2002/05/30 06:51:46 deraadt Exp $ */ +/* $OpenBSD: fetch.c,v 1.40 2002/11/08 03:30:17 fgsch Exp $ */ /* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */ /*- @@ -38,7 +38,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: fetch.c,v 1.39 2002/05/30 06:51:46 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: fetch.c,v 1.40 2002/11/08 03:30:17 fgsch Exp $"; #endif /* not lint */ /* @@ -66,6 +66,7 @@ static char rcsid[] = "$OpenBSD: fetch.c,v 1.39 2002/05/30 06:51:46 deraadt Exp #include #include #include +#include #include "ftp_var.h" @@ -102,23 +103,29 @@ url_get(origline, proxyenv, outfile) { struct addrinfo hints, *res0, *res; int error; - int i, isftpurl, isfileurl; + int i, isftpurl, isfileurl, isredirect; volatile int s, out; size_t len; - char c, *cp, *ep, *portnum, *path, buf[4096]; + char *cp, *ep, *portnum, *path; char pbuf[NI_MAXSERV]; const char * volatile savefile; - char *line, *host, *port; + char *line, *host, *port, *buf; char * volatile proxy; char *hosttail; volatile sig_t oldintr; off_t hashbytes; char *cause = "unknown"; + FILE *fin; + int rval; s = -1; proxy = NULL; + fin = NULL; + buf = NULL; isftpurl = 0; isfileurl = 0; + isredirect = 0; + rval = -1; line = strdup(origline); if (line == NULL) @@ -224,10 +231,13 @@ url_get(origline, proxyenv, outfile) bytes = 0; hashbytes = mark; progressmeter(-1); + + if ((buf = malloc(4096)) == NULL) + errx(1, "Can't allocate memory for transfer buffer\n"); /* Finally, suck down the file. */ i = 0; - while ((len = read(s, buf, sizeof(buf))) > 0) { + while ((len = read(s, buf, 4096)) > 0) { bytes += len; for (cp = buf; len > 0; len -= i, cp += i) { if ((i = write(out, cp, len)) == -1) { @@ -260,13 +270,8 @@ url_get(origline, proxyenv, outfile) fputs("Successfully retrieved file.\n", ttyout); (void)signal(SIGINT, oldintr); - close(s); - if (out != fileno(stdout)) - close(out); - if (proxy) - free(proxy); - free(line); - return (0); + rval = 0; + goto cleanup_url_get; } if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL && @@ -294,8 +299,6 @@ url_get(origline, proxyenv, outfile) * If the services file is corrupt/missing, fall back * on our hard-coded defines. */ - char pbuf[NI_MAXSERV]; - snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT); error = getaddrinfo(host, pbuf, &hints, &res0); } @@ -306,9 +309,9 @@ url_get(origline, proxyenv, outfile) s = -1; for (res = res0; res; res = res->ai_next) { - getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), + getnameinfo(res->ai_addr, res->ai_addrlen, pbuf, sizeof(pbuf), NULL, 0, NI_NUMERICHOST); - fprintf(ttyout, "Trying %s...\n", buf); + fprintf(ttyout, "Trying %s...\n", pbuf); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { @@ -341,9 +344,10 @@ again: goto cleanup_url_get; } + fin = fdopen(s, "r+"); + /* - * Construct and send the request. We're expecting a return - * status of "200". Proxy requests don't want leading /. + * Construct and send the request. Proxy requests don't want leading /. */ if (proxy) { /* @@ -353,7 +357,7 @@ again: if (verbose) fprintf(ttyout, "Requesting %s (via %s)\n", origline, proxyenv); - snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n%s\r\n\r\n", path, HTTP_USER_AGENT); + fprintf(fin, "GET %s HTTP/1.0\r\n%s\r\n\r\n", path, HTTP_USER_AGENT); } else { if (verbose) fprintf(ttyout, "Requesting %s\n", origline); @@ -372,49 +376,44 @@ again: * send them the port number. */ if (port && strcmp(port, "80") != 0) - snprintf(buf, sizeof(buf), - "GET /%s HTTP/1.0\r\nHost: [%s]:%s\r\n%s\r\n\r\n", + fprintf(fin, "GET /%s HTTP/1.0\r\nHost: [%s]:%s\r\n%s\r\n\r\n", path, h, port, HTTP_USER_AGENT); else - snprintf(buf, sizeof(buf), - "GET /%s HTTP/1.0\r\nHost: [%s]\r\n%s\r\n\r\n", + fprintf(fin, "GET /%s HTTP/1.0\r\nHost: [%s]\r\n%s\r\n\r\n", path, h, HTTP_USER_AGENT); free(h); } else { if (port && strcmp(port, "80") != 0) - snprintf(buf, sizeof(buf), - "GET /%s HTTP/1.0\r\nHost: %s:%s\r\n%s\r\n\r\n", + fprintf(fin, "GET /%s HTTP/1.0\r\nHost: %s:%s\r\n%s\r\n\r\n", path, host, port, HTTP_USER_AGENT); else - snprintf(buf, sizeof(buf), - "GET /%s HTTP/1.0\r\nHost: %s\r\n%s\r\n\r\n", + fprintf(fin, "GET /%s HTTP/1.0\r\nHost: %s\r\n%s\r\n\r\n", path, host, HTTP_USER_AGENT); } } - len = strlen(buf); - if (debug) - fprintf(ttyout, "Sending request:\n%s", buf); - if (write(s, buf, len) < len) { + if (fflush(fin) == EOF) { warn("Writing HTTP request"); goto cleanup_url_get; } - memset(buf, 0, sizeof(buf)); - for (cp = buf; cp < buf + sizeof(buf); ) { - if (read(s, cp, 1) != 1) - goto improper; - if (*cp == '\r') - continue; - if (*cp == '\n') - break; - cp++; + + if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) { + warn("Receiving HTTP reply"); + goto cleanup_url_get; } - buf[sizeof(buf) - 1] = '\0'; /* sanity */ + + while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) + buf[--len] = '\0'; + if (debug) + fprintf(ttyout, "received '%s'\n", buf); + cp = strchr(buf, ' '); if (cp == NULL) goto improper; else cp++; - if (strncmp(cp, "200", 3)) { + if (strncmp(cp, "301", 3) == 0 || strncmp(cp, "302", 3) == 0) { + isredirect++; + } else if (strncmp(cp, "200", 3)) { warnx("Error retrieving file: %s", cp); goto cleanup_url_get; } @@ -422,39 +421,49 @@ again: /* * Read the rest of the header. */ - memset(buf, 0, sizeof(buf)); - c = '\0'; - for (cp = buf; cp < buf + sizeof(buf); ) { - if (read(s, cp, 1) != 1) - goto improper; - if (*cp == '\r') - continue; - if (*cp == '\n' && c == '\n') + free(buf); + filesize = -1; + + while (1) { + if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) { + warn("Receiving HTTP reply"); + goto cleanup_url_get; + } + while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) + buf[--len] = '\0'; + if (len == 0) break; - c = *cp; - cp++; - } - buf[sizeof(buf) - 1] = '\0'; /* sanity */ + if (debug) + fprintf(ttyout, "received '%s'\n", buf); - /* Look for the "Content-length: " header. */ + /* Look for some headers */ + cp = buf; #define CONTENTLEN "Content-Length: " - for (cp = buf; *cp != '\0'; cp++) { - if (tolower(*cp) == 'c' && - strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) - break; + if (strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) { + cp += sizeof(CONTENTLEN) - 1; + filesize = strtol(cp, &ep, 10); + if (filesize < 1 || *ep != '\0') + goto improper; +#define LOCATION "Location: " + } else if (isredirect && + strncasecmp(cp, LOCATION, sizeof(LOCATION) - 1) == 0) { + cp += sizeof(LOCATION) - 1; + if (verbose) + fprintf(ttyout, "Redirected to %s\n", cp); + if (fin != NULL) + fclose(fin); + else if (s != -1) + close(s); + if (proxy) + free(proxy); + free(line); + rval = url_get(cp, proxyenv, outfile); + if (buf) + free(buf); + return (rval); + } } - if (*cp != '\0') { - cp += sizeof(CONTENTLEN) - 1; - ep = strchr(cp, '\n'); - if (ep == NULL) - goto improper; - else - *ep = '\0'; - filesize = strtol(cp, &ep, 10); - if (filesize < 1 || *ep != '\0') - goto improper; - } else - filesize = -1; + free(buf); /* Open the output file. */ if (strcmp(savefile, "-") != 0) { @@ -480,8 +489,10 @@ again: progressmeter(-1); /* Finally, suck down the file. */ + if ((buf = malloc(4096)) == NULL) + errx(1, "Can't allocate memory for transfer buffer\n"); i = 0; - while ((len = read(s, buf, sizeof(buf))) > 0) { + while ((len = fread(buf, sizeof(char), 4096, fin)) > 0) { bytes += len; for (cp = buf; len > 0; len -= i, cp += i) { if ((i = write(out, cp, len)) == -1) { @@ -520,13 +531,8 @@ again: fputs("Successfully retrieved file.\n", ttyout); (void)signal(SIGINT, oldintr); - close(s); - if (out != fileno(stdout)) - close(out); - if (proxy) - free(proxy); - free(line); - return (0); + rval = 0; + goto cleanup_url_get; noftpautologin: warnx( @@ -537,12 +543,16 @@ improper: warnx("Improper response from %s", host); cleanup_url_get: - if (s != -1) + if (fin != NULL) + fclose(fin); + else if (s != -1) close(s); + if (buf) + free(buf); if (proxy) free(proxy); free(line); - return (-1); + return (rval); } /* @@ -781,7 +791,7 @@ bad_ftp_url: setpeer(xargc, xargv); autologin = oautologin; if ((connected == 0) || - ((connected == 1) && !login(host, user, pass))) { + ((connected == 1) && !ftp_login(host, user, pass))) { warnx("Can't connect or login to host `%s'", host); rval = argpos + 1; diff --git a/usr.bin/ftp/util.c b/usr.bin/ftp/util.c index 3874a50c655..ab5dfa03cf2 100644 --- a/usr.bin/ftp/util.c +++ b/usr.bin/ftp/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.30 2002/07/12 00:25:30 deraadt Exp $ */ +/* $OpenBSD: util.c,v 1.31 2002/11/08 03:30:17 fgsch Exp $ */ /* $NetBSD: util.c,v 1.12 1997/08/18 10:20:27 lukem Exp $ */ /* @@ -35,7 +35,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: util.c,v 1.30 2002/07/12 00:25:30 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: util.c,v 1.31 2002/11/08 03:30:17 fgsch Exp $"; #endif /* not lint */ /* @@ -152,7 +152,7 @@ setpeer(argc, argv) curtype = TYPE_A; type = 0; if (autologin) - (void)login(argv[1], NULL, NULL); + (void)ftp_login(argv[1], NULL, NULL); #if (defined(unix) || defined(BSD)) && NBBY == 8 /* @@ -207,7 +207,7 @@ setpeer(argc, argv) * login to remote host, using given username & password if supplied */ int -login(host, user, pass) +ftp_login(host, user, pass) const char *host; char *user, *pass; { -- cgit v1.2.3