diff options
-rw-r--r-- | usr.bin/ftp/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/ftp/cookie.c | 231 | ||||
-rw-r--r-- | usr.bin/ftp/extern.h | 4 | ||||
-rw-r--r-- | usr.bin/ftp/fetch.c | 25 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.1 | 17 | ||||
-rw-r--r-- | usr.bin/ftp/ftp_var.h | 3 | ||||
-rw-r--r-- | usr.bin/ftp/main.c | 21 |
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 */ |