summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ftp/Makefile4
-rw-r--r--usr.bin/ftp/cookie.c231
-rw-r--r--usr.bin/ftp/extern.h4
-rw-r--r--usr.bin/ftp/fetch.c25
-rw-r--r--usr.bin/ftp/ftp.117
-rw-r--r--usr.bin/ftp/ftp_var.h3
-rw-r--r--usr.bin/ftp/main.c21
7 files changed, 289 insertions, 16 deletions
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile
index 3cb50c7b584..b2e4e802d96 100644
--- a/usr.bin/ftp/Makefile
+++ b/usr.bin/ftp/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.21 2006/05/16 16:20:42 deraadt Exp $
+# $OpenBSD: Makefile,v 1.22 2007/06/13 13:52:26 pyr Exp $
# Define SMALL to disable command line editing and https support
#CFLAGS+=-DSMALL
@@ -13,7 +13,7 @@ LDADD += -lsocks5
PROG= ftp
SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c ruserpass.c \
- stringlist.c util.c
+ cookie.c stringlist.c util.c
CPPFLAGS+= -DINET6
diff --git a/usr.bin/ftp/cookie.c b/usr.bin/ftp/cookie.c
new file mode 100644
index 00000000000..34ee3569d1d
--- /dev/null
+++ b/usr.bin/ftp/cookie.c
@@ -0,0 +1,231 @@
+/* $OpenBSD: cookie.c,v 1.1 2007/06/13 13:52:26 pyr Exp $ */
+/*
+ * Copyright (c) 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SMALL
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "ftp_var.h"
+
+struct cookie {
+ TAILQ_ENTRY(cookie) entry;
+ TAILQ_ENTRY(cookie) tempentry;
+ u_int8_t flags;
+#define F_SECURE 0x01
+#define F_TAILMATCH 0x02
+#define F_NOEXPIRY 0x04
+#define F_MATCHPATH 0x08
+ time_t expires;
+ char *domain;
+ char *path;
+ char *key;
+ char *val;
+};
+TAILQ_HEAD(cookiejar, cookie);
+
+typedef enum {
+ DOMAIN = 0, TAILMATCH = 1, PATH = 2, SECURE = 3,
+ EXPIRES = 4, NAME = 5, VALUE = 6, DONE = 7
+} field_t;
+
+static struct cookiejar jar;
+
+void
+cookie_load(void)
+{
+ field_t field;
+ size_t len;
+ time_t date;
+ char *line;
+ char *lbuf;
+ char *param;
+ const char *estr;
+ FILE *fp;
+ struct cookie *ck;
+
+ if (cookiefile == NULL)
+ return;
+
+ TAILQ_INIT(&jar);
+ fp = fopen(cookiefile, "r");
+ if (fp == NULL)
+ err(1, "cannot open cookie file %s", cookiefile);
+ date = time(NULL);
+ lbuf = NULL;
+ while ((line = fgetln(fp, &len)) != NULL) {
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ --len;
+ } else {
+ if ((lbuf = malloc(len + 1)) == NULL)
+ err(1, NULL);
+ memcpy(lbuf, line, len);
+ lbuf[len] = '\0';
+ line = lbuf;
+ }
+ if (len > 0 && line[len - 1] == '\r') {
+ line[len - 1] = '\0';
+ --len;
+ }
+
+ line += strspn(line, " \t");
+ if ((*line == '#') || (*line == '\0')) {
+ continue;
+ }
+ field = DOMAIN;
+ ck = calloc(1, sizeof(*ck));
+ if (ck == NULL)
+ err(1, NULL);
+ while ((param = strsep(&line, "\t")) != NULL) {
+ switch (field) {
+ case DOMAIN:
+ if (*param == '.') {
+ if (asprintf(&ck->domain,
+ "*%s", param) == -1)
+ err(1, NULL);
+ } else {
+ ck->domain = strdup(param);
+ if (ck->domain == NULL)
+ err(1, NULL);
+ }
+ break;
+ case TAILMATCH:
+ if (strcasecmp(param, "TRUE") == 0) {
+ ck->flags |= F_TAILMATCH;
+ } else if (strcasecmp(param, "FALSE") != 0) {
+ errx(1, "invalid cookie file");
+ }
+ break;
+ case PATH:
+ if (strcmp(param, "/") != 0) {
+ ck->flags |= F_MATCHPATH;
+ if (asprintf(&ck->path,
+ "%s*", param) == -1)
+ err(1, NULL);
+ }
+ break;
+ case SECURE:
+ if (strcasecmp(param, "TRUE") == 0) {
+ ck->flags |= F_SECURE;
+ } else if (strcasecmp(param, "FALSE") != 0) {
+ errx(1, "invalid cookie file");
+ }
+ break;
+ case EXPIRES:
+ /*
+ * rely on sizeof(time_t) being 4
+ */
+ ck->expires = strtonum(param, 0,
+ UINT_MAX, &estr);
+ if (estr) {
+ if (errno == ERANGE)
+ ck->flags |= F_NOEXPIRY;
+ else
+ errx(1, "invalid cookie file");
+ }
+ break;
+ case NAME:
+ ck->key = strdup(param);
+ if (ck->key == NULL)
+ err(1, NULL);
+ break;
+ case VALUE:
+ ck->val = strdup(param);
+ if (ck->val == NULL)
+ err(1, NULL);
+ break;
+ case DONE:
+ errx(1, "invalid cookie file");
+ break;
+ }
+ field++;
+ }
+ if (field != DONE)
+ errx(1, "invalid cookie file");
+ if (ck->expires < date && !(ck->flags & F_NOEXPIRY)) {
+ free(ck->val);
+ free(ck->key);
+ free(ck->path);
+ free(ck->domain);
+ free(ck);
+ } else
+ TAILQ_INSERT_TAIL(&jar, ck, entry);
+ }
+ free(lbuf);
+ fclose(fp);
+}
+
+void
+cookie_get(const char *domain, const char *path, int secure, char **pstr)
+{
+ size_t len;
+ size_t headlen;
+ char *head;
+ char *str;
+ struct cookie *ck;
+ struct cookiejar tempjar;
+
+ *pstr = NULL;
+
+ if (cookiefile == NULL)
+ return;
+
+ TAILQ_INIT(&tempjar);
+ len = strlen("Cookie\r\n");
+
+ TAILQ_FOREACH(ck, &jar, entry) {
+ if (fnmatch(ck->domain, domain, 0) == 0 &&
+ (secure || !(ck->flags & F_SECURE))) {
+
+ if (ck->flags & F_MATCHPATH &&
+ fnmatch(ck->path, path, 0) != 0)
+ continue;
+
+ len += strlen(ck->key) + strlen(ck->val) +
+ strlen("; =");
+ TAILQ_INSERT_TAIL(&tempjar, ck, tempentry);
+ }
+ }
+ if (TAILQ_EMPTY(&tempjar))
+ return;
+ len += 1;
+ str = malloc(len);
+ if (str == NULL)
+ err(1, NULL);
+
+ (void)strlcpy(str, "Cookie:", len);
+ TAILQ_FOREACH(ck, &tempjar, tempentry) {
+ head = str + strlen(str);
+ headlen = len - strlen(str);
+
+ snprintf(head, headlen, "%s %s=%s",
+ (ck == TAILQ_FIRST(&tempjar))? "" : ";", ck->key, ck->val);
+ }
+ if (strlcat(str, "\r\n", len) >= len)
+ errx(1, "cookie header truncated");
+ *pstr = str;
+}
+
+#endif /* ! SMALL */
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index 37287a60f60..864913387d6 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.29 2007/06/06 19:15:33 pyr Exp $ */
+/* $OpenBSD: extern.h,v 1.30 2007/06/13 13:52:26 pyr Exp $ */
/* $NetBSD: extern.h,v 1.17 1997/08/18 10:20:19 lukem Exp $ */
/*
@@ -191,6 +191,8 @@ void user(int, char **);
#ifndef SMALL
int ruserpass(const char *, char **, char **, char **);
+void cookie_load(void);
+void cookie_get(const char *, const char *, int, char **);
#endif
diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c
index 2497798f9ac..efc018a386d 100644
--- a/usr.bin/ftp/fetch.c
+++ b/usr.bin/ftp/fetch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fetch.c,v 1.73 2007/04/17 14:58:51 drahn Exp $ */
+/* $OpenBSD: fetch.c,v 1.74 2007/06/13 13:52:26 pyr Exp $ */
/* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */
/*-
@@ -38,7 +38,7 @@
*/
#if !defined(lint) && !defined(SMALL)
-static const char rcsid[] = "$OpenBSD: fetch.c,v 1.73 2007/04/17 14:58:51 drahn Exp $";
+static const char rcsid[] = "$OpenBSD: fetch.c,v 1.74 2007/06/13 13:52:26 pyr Exp $";
#endif /* not lint and not SMALL */
/*
@@ -448,6 +448,9 @@ again:
/*
* Construct and send the request. Proxy requests don't want leading /.
*/
+#ifndef SMALL
+ cookie_get(host, path, ishttpsurl, &buf);
+#endif
if (proxyurl) {
if (verbose)
fprintf(ttyout, " (via %s)\n", proxyenv);
@@ -457,11 +460,11 @@ again:
*/
if (cookie)
ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n"
- "Proxy-Authorization: Basic %s\r\n%s\r\n\r\n",
- path, cookie, HTTP_USER_AGENT);
+ "Proxy-Authorization: Basic %s%s\r\n%s\r\n\r\n",
+ path, cookie, buf ? buf : "", HTTP_USER_AGENT);
else
- ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n%s\r\n\r\n",
- path, HTTP_USER_AGENT);
+ ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n%s%s\r\n\r\n",
+ path, buf ? buf : "", HTTP_USER_AGENT);
} else {
ftp_printf(fin, ssl, "GET /%s HTTP/1.0\r\nHost: ", path);
@@ -494,10 +497,18 @@ again:
if (port && strcmp(port, "80") != 0)
ftp_printf(fin, ssl, ":%s", port);
#endif
- ftp_printf(fin, ssl, "\r\n%s\r\n\r\n", HTTP_USER_AGENT);
+ ftp_printf(fin, ssl, "\r\n%s%s\r\n\r\n",
+ buf ? buf : "", HTTP_USER_AGENT);
if (verbose)
fprintf(ttyout, "\n");
}
+
+
+#ifndef SMALL
+ free(buf);
+#endif
+ buf = NULL;
+
if (fin != NULL && fflush(fin) == EOF) {
warn("Writing HTTP request");
goto cleanup_url_get;
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index b9af65178ca..6ccbb8f0f47 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ftp.1,v 1.58 2007/05/31 19:20:10 jmc Exp $
+.\" $OpenBSD: ftp.1,v 1.59 2007/06/13 13:52:26 pyr Exp $
.\" $NetBSD: ftp.1,v 1.22 1997/08/18 10:20:22 lukem Exp $
.\"
.\" Copyright (c) 1985, 1989, 1990, 1993
@@ -30,7 +30,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: June 13 2007 $
.Dt FTP 1
.Os
.Sh NAME
@@ -39,6 +39,7 @@
.Sh SYNOPSIS
.Nm ftp
.Op Fl 46AadEegimnptVv
+.Op Fl c Ar cookiefile
.Op Fl P Ar port
.Op Fl r Ar seconds
.Op Ar host Op Ar port
@@ -108,6 +109,15 @@ to very old servers that do not implement passive mode properly.
Causes
.Nm
to bypass the normal login procedure and use an anonymous login instead.
+.It Fl c
+Load a Netscape type cookiejar file.
+This option is only useful for HTTP and HTTPS transfers.
+With this option relevant cookies from the jar are sent with each HTTP(S)
+request.
+Setting the http_cookies environment variable has the same effect.
+If both the http_cookies environment variable is set and the
+.Fl c
+argument is given, the latter will take precedence.
.It Fl d
Enables debugging.
.It Fl E
@@ -1505,6 +1515,9 @@ URL of FTP proxy to use when making FTP URL requests
(if not defined, use the standard FTP protocol).
.It Ev http_proxy
URL of HTTP proxy to use when making HTTP or HTTPS URL requests.
+.It Ev http_cookies
+Path of a Netscape like cookiejar to use when making
+HTTP or HTTPS URL requests.
.El
.Sh PORT ALLOCATION
For active mode data connections,
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index 606a786abb3..1f32c43d158 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftp_var.h,v 1.23 2006/05/16 16:20:42 deraadt Exp $ */
+/* $OpenBSD: ftp_var.h,v 1.24 2007/06/13 13:52:26 pyr Exp $ */
/* $NetBSD: ftp_var.h,v 1.18 1997/08/18 10:20:25 lukem Exp $ */
/*
@@ -160,6 +160,7 @@ History *hist; /* editline(3) history structure */
char *cursor_pos; /* cursor position we're looking for */
size_t cursor_argc; /* location of cursor in margv */
size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */
+char *cookiefile; /* cookie jar to use */
#endif /* !SMALL */
off_t bytes; /* current # of bytes read */
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index 708e929971b..958b71a3de2 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.62 2007/04/07 23:20:18 tedu Exp $ */
+/* $OpenBSD: main.c,v 1.63 2007/06/13 13:52:26 pyr Exp $ */
/* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
/*
@@ -66,7 +66,7 @@ static const char copyright[] =
#endif /* not lint */
#if !defined(lint) && !defined(SMALL)
-static const char rcsid[] = "$OpenBSD: main.c,v 1.62 2007/04/07 23:20:18 tedu Exp $";
+static const char rcsid[] = "$OpenBSD: main.c,v 1.63 2007/06/13 13:52:26 pyr Exp $";
#endif /* not lint and not SMALL */
/*
@@ -120,6 +120,7 @@ main(volatile int argc, char *argv[])
editing = 0;
el = NULL;
hist = NULL;
+ cookiefile = NULL;
#endif
mark = HASHBYTES;
marg_sl = sl_init();
@@ -176,7 +177,11 @@ main(volatile int argc, char *argv[])
if (isatty(fileno(ttyout)) && !dumb_terminal && foregroundproc())
progress = 1; /* progress bar on if tty is usable */
- while ((ch = getopt(argc, argv, "46AadEegimno:pP:r:tvV")) != -1) {
+#ifndef SMALL
+ cookiefile = getenv("http_cookies");
+#endif
+
+ while ((ch = getopt(argc, argv, "46Aac:dEegimno:pP:r:tvV")) != -1) {
switch (ch) {
case '4':
family = PF_INET;
@@ -193,6 +198,12 @@ main(volatile int argc, char *argv[])
anonftp = 1;
break;
+ case 'c':
+#ifndef SMALL
+ cookiefile = optarg;
+#endif
+ break;
+
case 'd':
options |= SO_DEBUG;
debug++;
@@ -265,6 +276,10 @@ main(volatile int argc, char *argv[])
argc -= optind;
argv += optind;
+#ifndef SMALL
+ cookie_load();
+#endif
+
cpend = 0; /* no pending replies */
proxy = 0; /* proxy not active */
crflag = 1; /* strip c.r. on ascii gets */