summaryrefslogtreecommitdiff
path: root/usr.bin/ftp
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2002-11-08 03:30:18 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2002-11-08 03:30:18 +0000
commit0a27a97192fc09d92b5f67b3ce4b9b1c6b4c8c56 (patch)
treeb112ce7a0af56d01d4d95d7bf0830d7d68b9b9af /usr.bin/ftp
parent31cdbef371a8b4406ee3f91d30fa66016b8039bd (diff)
http redirect support; adapted from NetBSD.
Diffstat (limited to 'usr.bin/ftp')
-rw-r--r--usr.bin/ftp/Makefile6
-rw-r--r--usr.bin/ftp/extern.h4
-rw-r--r--usr.bin/ftp/fetch.c176
-rw-r--r--usr.bin/ftp/util.c8
4 files changed, 102 insertions, 92 deletions
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 <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <util.h>
#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;
{