From: Peter Avalos Date: Sun, 7 Apr 2013 04:34:01 +0000 (-0700) Subject: Import tnftp-20121224. X-Git-Tag: v3.4.0~24^2 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/a83a5d06ce79495c0bd46d5589c69d55ce2b787c Import tnftp-20121224. * Add https support. * When using the response to SYST to decide whether to default to 'binary' be a lot less specific. Obtained-from: NetBSD --- diff --git a/contrib/tnftp/cmds.c b/contrib/tnftp/cmds.c index 633ab0060f..66cab2b55d 100644 --- a/contrib/tnftp/cmds.c +++ b/contrib/tnftp/cmds.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmds.c,v 1.134 2012/01/15 20:43:24 christos Exp $ */ +/* $NetBSD: cmds.c,v 1.135 2012/12/22 16:57:09 christos Exp $ */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -96,7 +96,7 @@ #if 0 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; #else -__RCSID("$NetBSD: cmds.c,v 1.134 2012/01/15 20:43:24 christos Exp $"); +__RCSID("$NetBSD: cmds.c,v 1.135 2012/12/22 16:57:09 christos Exp $"); #endif #endif /* not lint */ @@ -2675,7 +2675,7 @@ setoption(int argc, char *argv[]) return; } -#define OPTIONINDENT ((int) sizeof("http_proxy")) +#define OPTIONINDENT ((int) sizeof("https_proxy")) if (argc == 1) { for (o = optiontab; o->name != NULL; o++) { fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, diff --git a/contrib/tnftp/cmdtab.c b/contrib/tnftp/cmdtab.c index 17d7477958..13d3f4b82c 100644 --- a/contrib/tnftp/cmdtab.c +++ b/contrib/tnftp/cmdtab.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmdtab.c,v 1.51 2009/04/12 10:18:52 lukem Exp $ */ +/* $NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp $ */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -63,7 +63,7 @@ #if 0 static char sccsid[] = "@(#)cmdtab.c 8.4 (Berkeley) 10/9/94"; #else -__RCSID("$NetBSD: cmdtab.c,v 1.51 2009/04/12 10:18:52 lukem Exp $"); +__RCSID("$NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp $"); #endif #endif /* not lint */ @@ -298,6 +298,7 @@ struct option optiontab[] = { { "anonpass", NULL }, { "ftp_proxy", NULL }, { "http_proxy", NULL }, + { "https_proxy",NULL }, { "no_proxy", NULL }, { "pager", NULL }, { "prompt", NULL }, diff --git a/contrib/tnftp/fetch.c b/contrib/tnftp/fetch.c index 30087f894d..e837d8f19c 100644 --- a/contrib/tnftp/fetch.c +++ b/contrib/tnftp/fetch.c @@ -1,4 +1,4 @@ -/* $NetBSD: fetch.c,v 1.198 2012/07/04 06:09:37 is Exp $ */ +/* $NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp $ */ /*- * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include #ifndef lint -__RCSID("$NetBSD: fetch.c,v 1.198 2012/07/04 06:09:37 is Exp $"); +__RCSID("$NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp $"); #endif /* not lint */ /* @@ -64,12 +64,16 @@ __RCSID("$NetBSD: fetch.c,v 1.198 2012/07/04 06:09:37 is Exp $"); #include #include +#include "ssl.h" #include "ftp_var.h" #include "version.h" typedef enum { UNKNOWN_URL_T=-1, HTTP_URL_T, +#ifdef WITH_SSL + HTTPS_URL_T, +#endif FTP_URL_T, FILE_URL_T, CLASSIC_URL_T @@ -100,7 +104,15 @@ static int redirect_loop; #define FILE_URL "file://" /* file URL prefix */ #define FTP_URL "ftp://" /* ftp URL prefix */ #define HTTP_URL "http://" /* http URL prefix */ +#ifdef WITH_SSL +#define HTTPS_URL "https://" /* https URL prefix */ +#define IS_HTTP_TYPE(urltype) \ + (((urltype) == HTTP_URL_T) || ((urltype) == HTTPS_URL_T)) +#else +#define IS_HTTP_TYPE(urltype) \ + ((urltype) == HTTP_URL_T) +#endif /* * Determine if token is the next word in buf (case insensitive). @@ -346,6 +358,13 @@ parse_url(const char *url, const char *desc, url_t *utype, } else if (STRNEQUAL(url, FILE_URL)) { url += sizeof(FILE_URL) - 1; *utype = FILE_URL_T; +#ifdef WITH_SSL + } else if (STRNEQUAL(url, HTTPS_URL)) { + url += sizeof(HTTPS_URL) - 1; + *utype = HTTPS_URL_T; + *portnum = HTTPS_PORT; + tport = httpsport; +#endif } else { warnx("Invalid %s `%s'", desc, url); cleanup_parse_url: @@ -463,7 +482,7 @@ sigjmp_buf httpabort; /* * Retrieve URL, via a proxy if necessary, using HTTP. * If proxyenv is set, use that for the proxy, otherwise try ftp_proxy or - * http_proxy as appropriate. + * http_proxy/https_proxy as appropriate. * Supports HTTP redirects. * Returns 1 on failure, 0 on completed xfer, -1 if ftp connection * is still open (e.g, ftp xfer with trailing /) @@ -498,17 +517,21 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) char *puser, *ppass, *useragent; off_t hashbytes, rangestart, rangeend, entitylen; int (*volatile closefunc)(FILE *); - FILE *volatile fin; + FETCH *volatile fin; FILE *volatile fout; time_t mtime; url_t urltype; in_port_t portnum; +#ifdef WITH_SSL + void *ssl; +#endif DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv)); oldintr = oldintp = NULL; closefunc = NULL; - fin = fout = NULL; + fin = NULL; + fout = NULL; s = -1; savefile = NULL; auth = location = message = NULL; @@ -531,7 +554,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) rval = fetch_ftp(url); goto cleanup_fetch_url; } - if (urltype != HTTP_URL_T || outfile == NULL) { + if (!IS_HTTP_TYPE(urltype) || outfile == NULL) { warnx("Invalid URL (no file after host) `%s'", url); goto cleanup_fetch_url; } @@ -571,17 +594,17 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) } if (urltype == FILE_URL_T) { /* file:// URLs */ direction = "copied"; - fin = fopen(decodedpath, "r"); + fin = fetch_open(decodedpath, "r"); if (fin == NULL) { warn("Can't open `%s'", decodedpath); goto cleanup_fetch_url; } - if (fstat(fileno(fin), &sb) == 0) { + if (fstat(fetch_fileno(fin), &sb) == 0) { mtime = sb.st_mtime; filesize = sb.st_size; } if (restart_point) { - if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { + if (lseek(fetch_fileno(fin), restart_point, SEEK_SET) < 0) { warn("Can't seek to restart `%s'", decodedpath); goto cleanup_fetch_url; @@ -594,12 +617,19 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) (LLT)restart_point); fputs("\n", ttyout); } + if (0 == rcvbuf_size) { + rcvbuf_size = 8 * 1024; /* XXX */ + } } else { /* ftp:// or http:// URLs */ const char *leading; int hasleading; if (proxyenv == NULL) { - if (urltype == HTTP_URL_T) +#ifdef WITH_SSL + if (urltype == HTTPS_URL_T) + proxyenv = getoptionvalue("https_proxy"); +#endif + if (proxyenv == NULL && IS_HTTP_TYPE(urltype)) proxyenv = getoptionvalue("http_proxy"); else if (urltype == FTP_URL_T) proxyenv = getoptionvalue("ftp_proxy"); @@ -660,7 +690,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) &ppath) == -1) goto cleanup_fetch_url; - if ((purltype != HTTP_URL_T + if ((!IS_HTTP_TYPE(purltype) && purltype != FTP_URL_T) || EMPTYSTRING(phost) || (! EMPTYSTRING(ppath) @@ -690,6 +720,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) FREEPTR(path); path = ftp_strdup(url); FREEPTR(ppath); + urltype = purltype; } } /* ! EMPTYSTRING(proxyenv) */ @@ -709,6 +740,9 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) host = res0->ai_canonname; s = -1; +#ifdef WITH_SSL + ssl = NULL; +#endif for (res = res0; res; res = res->ai_next) { char hname[NI_MAXHOST], sname[NI_MAXSERV]; @@ -741,6 +775,16 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) continue; } +#ifdef WITH_SSL + if (urltype == HTTPS_URL_T) { + if ((ssl = fetch_start_ssl(s)) == NULL) { + close(s); + s = -1; + continue; + } + } +#endif + /* success */ break; } @@ -750,7 +794,9 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) goto cleanup_fetch_url; } - fin = fdopen(s, "r+"); + fin = fetch_fdopen(s, "r+"); + fetch_set_ssl(fin, ssl); + /* * Construct and send the request. */ @@ -765,11 +811,11 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) leading = ", "; hasleading++; } - fprintf(fin, "GET %s HTTP/1.0\r\n", path); + fetch_printf(fin, "GET %s HTTP/1.0\r\n", path); if (flushcache) - fprintf(fin, "Pragma: no-cache\r\n"); + fetch_printf(fin, "Pragma: no-cache\r\n"); } else { - fprintf(fin, "GET %s HTTP/1.1\r\n", path); + fetch_printf(fin, "GET %s HTTP/1.1\r\n", path); if (strchr(host, ':')) { char *h, *p; @@ -782,18 +828,23 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) (p = strchr(h, '%')) != NULL) { *p = '\0'; } - fprintf(fin, "Host: [%s]", h); + fetch_printf(fin, "Host: [%s]", h); free(h); } else - fprintf(fin, "Host: %s", host); + fetch_printf(fin, "Host: %s", host); +#ifdef WITH_SSL + if ((urltype == HTTP_URL_T && portnum != HTTP_PORT) || + (urltype == HTTPS_URL_T && portnum != HTTPS_PORT)) +#else if (portnum != HTTP_PORT) - fprintf(fin, ":%u", portnum); - fprintf(fin, "\r\n"); - fprintf(fin, "Accept: */*\r\n"); - fprintf(fin, "Connection: close\r\n"); +#endif + fetch_printf(fin, ":%u", portnum); + fetch_printf(fin, "\r\n"); + fetch_printf(fin, "Accept: */*\r\n"); + fetch_printf(fin, "Connection: close\r\n"); if (restart_point) { fputs(leading, ttyout); - fprintf(fin, "Range: bytes=" LLF "-\r\n", + fetch_printf(fin, "Range: bytes=" LLF "-\r\n", (LLT)restart_point); fprintf(ttyout, "restarting at " LLF, (LLT)restart_point); @@ -801,12 +852,12 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) hasleading++; } if (flushcache) - fprintf(fin, "Cache-Control: no-cache\r\n"); + fetch_printf(fin, "Cache-Control: no-cache\r\n"); } if ((useragent=getenv("FTPUSERAGENT")) != NULL) { - fprintf(fin, "User-Agent: %s\r\n", useragent); + fetch_printf(fin, "User-Agent: %s\r\n", useragent); } else { - fprintf(fin, "User-Agent: %s/%s\r\n", + fetch_printf(fin, "User-Agent: %s/%s\r\n", FTP_PRODUCT, FTP_VERSION); } if (wwwauth) { @@ -816,7 +867,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) leading = ", "; hasleading++; } - fprintf(fin, "Authorization: %s\r\n", wwwauth); + fetch_printf(fin, "Authorization: %s\r\n", wwwauth); } if (proxyauth) { if (verbose) { @@ -825,18 +876,18 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) leading = ", "; hasleading++; } - fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth); + fetch_printf(fin, "Proxy-Authorization: %s\r\n", proxyauth); } if (verbose && hasleading) fputs(")\n", ttyout); - fprintf(fin, "\r\n"); - if (fflush(fin) == EOF) { + fetch_printf(fin, "\r\n"); + if (fetch_flush(fin) == EOF) { warn("Writing HTTP request"); goto cleanup_fetch_url; } /* Read the response */ - len = get_line(fin, buf, sizeof(buf), &errormsg); + len = fetch_getline(fin, buf, sizeof(buf), &errormsg); if (len < 0) { if (*errormsg == '\n') errormsg++; @@ -860,7 +911,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) /* Read the rest of the header. */ while (1) { - len = get_line(fin, buf, sizeof(buf), &errormsg); + len = fetch_getline(fin, buf, sizeof(buf), &errormsg); if (len < 0) { if (*errormsg == '\n') errormsg++; @@ -1148,7 +1199,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) lastchunk = 0; /* read chunk-size */ if (ischunked) { - if (fgets(xferbuf, bufsize, fin) == NULL) { + if (fetch_getln(xferbuf, bufsize, fin) == NULL) { warnx("Unexpected EOF reading chunk-size"); goto cleanup_fetch_url; } @@ -1201,7 +1252,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) if (ischunked) bufrem = MIN(chunksize, bufrem); while (bufrem > 0) { - flen = fread(xferbuf, sizeof(char), + flen = fetch_read(xferbuf, sizeof(char), MIN((off_t)bufsize, bufrem), fin); if (flen <= 0) goto chunkdone; @@ -1240,7 +1291,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) /* read CRLF after chunk*/ chunkdone: if (ischunked) { - if (fgets(xferbuf, bufsize, fin) == NULL) { + if (fetch_getln(xferbuf, bufsize, fin) == NULL) { warnx("Unexpected EOF reading chunk CRLF"); goto cleanup_fetch_url; } @@ -1260,7 +1311,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) (void)putc('#', ttyout); (void)putc('\n', ttyout); } - if (ferror(fin)) { + if (fetch_error(fin)) { warn("Reading file"); goto cleanup_fetch_url; } @@ -1297,7 +1348,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) if (oldintp) (void)xsignal(SIGPIPE, oldintp); if (fin != NULL) - fclose(fin); + fetch_close(fin); else if (s != -1) close(s); if (closefunc != NULL && fout != NULL) @@ -1729,7 +1780,11 @@ go_fetch(const char *url) /* * Check for file:// and http:// URLs. */ - if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL)) + if (STRNEQUAL(url, HTTP_URL) +#ifdef WITH_SSL + || STRNEQUAL(url, HTTPS_URL) +#endif + || STRNEQUAL(url, FILE_URL)) return (fetch_url(url, NULL, NULL, NULL)); /* diff --git a/contrib/tnftp/ftp.1 b/contrib/tnftp/ftp.1 index ac6babe7d2..931f3b8ee8 100644 --- a/contrib/tnftp/ftp.1 +++ b/contrib/tnftp/ftp.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: ftp.1,v 1.133 2012/04/08 22:00:38 wiz Exp $ +.\" $NetBSD: ftp.1,v 1.134 2012/12/22 16:57:10 christos Exp $ .\" .\" Copyright (c) 1996-2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -57,7 +57,7 @@ .\" .\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 .\" -.Dd March 5, 2010 +.Dd December 22, 2012 .Dt FTP 1 .Os .Sh NAME @@ -1325,7 +1325,7 @@ and .Ar value are not given, display all of the options and their values. The currently supported options are: -.Bl -tag -width "http_proxy" -offset indent +.Bl -tag -width "https_proxy" -offset indent .It Cm anonpass Defaults to .Ev $FTPANONPASS @@ -1335,6 +1335,9 @@ Defaults to .It Cm http_proxy Defaults to .Ev $http_proxy . +.It Cm https_proxy +Defaults to +.Ev $https_proxy . .It Cm no_proxy Defaults to .Ev $no_proxy . @@ -1742,6 +1745,29 @@ and (and optionally .Sq password ) is in the URL, use them for the first attempt to authenticate. +.\" https://[user[:password]@]host[:port]/path +.It Li https:// Ns Oo Ar user Ns Oo Li \&: Ns Ar password Oc Ns Li \&@ Oc \ +Ns Ar host Ns Oo Li \&: Ns Ar port Oc Ns Li / Ns Ar path +An +.Tn HTTPS +URL, retrieved using the +.Tn HTTPS +protocol. +If +.Ic "set https_proxy" +is defined, it is used as a URL to an +.Tn HTTPS +proxy server. +If +.Tn HTTPS +authorization is required to retrieve +.Ar path , +and +.Sq user +(and optionally +.Sq password ) +is in the URL, use them for the first attempt to authenticate. +There is currently no certificate validation and verification. .\" file:///path .It Li file:/// Ns Ar path A local URL, copied from diff --git a/contrib/tnftp/ftp_var.h b/contrib/tnftp/ftp_var.h index db501cf2b1..7e5040a7b2 100644 --- a/contrib/tnftp/ftp_var.h +++ b/contrib/tnftp/ftp_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: ftp_var.h,v 1.81 2009/04/12 10:18:52 lukem Exp $ */ +/* $NetBSD: ftp_var.h,v 1.82 2012/12/21 18:07:36 christos Exp $ */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -177,6 +177,7 @@ enum { #define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */ #define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */ +#define HTTPS_PORT 443 /* default if ! getservbyname("https/tcp") */ #ifndef GATE_PORT #define GATE_PORT 21 /* default if ! getservbyname("ftpgate/tcp") */ #endif @@ -273,6 +274,9 @@ GLOBAL char *username; /* name of user logged in as. (dynamic) */ GLOBAL sa_family_t family; /* address family to use for connections */ GLOBAL const char *ftpport; /* port number to use for FTP connections */ GLOBAL const char *httpport; /* port number to use for HTTP connections */ +#ifdef WITH_SSL +GLOBAL const char *httpsport; /* port number to use for HTTPS connections */ +#endif GLOBAL const char *gateport; /* port number to use for gateftp connections */ GLOBAL struct addrinfo *bindai; /* local address to bind as */ diff --git a/contrib/tnftp/main.c b/contrib/tnftp/main.c index 58234eed30..c84364d58d 100644 --- a/contrib/tnftp/main.c +++ b/contrib/tnftp/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.120 2011/12/10 05:53:58 lukem Exp $ */ +/* $NetBSD: main.c,v 1.122 2012/12/22 16:57:10 christos Exp $ */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -98,7 +98,7 @@ __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\ #if 0 static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94"; #else -__RCSID("$NetBSD: main.c,v 1.120 2011/12/10 05:53:58 lukem Exp $"); +__RCSID("$NetBSD: main.c,v 1.122 2012/12/22 16:57:10 christos Exp $"); #endif #endif /* not lint */ @@ -126,6 +126,7 @@ __RCSID("$NetBSD: main.c,v 1.120 2011/12/10 05:53:58 lukem Exp $"); #define FTP_PROXY "ftp_proxy" /* env var with FTP proxy location */ #define HTTP_PROXY "http_proxy" /* env var with HTTP proxy location */ +#define HTTPS_PROXY "https_proxy" /* env var with HTTPS proxy location */ #define NO_PROXY "no_proxy" /* env var with list of non-proxied * hosts, comma or space separated */ @@ -150,6 +151,9 @@ main(int volatile argc, char **volatile argv) ftpport = "ftp"; httpport = "http"; +#ifdef WITH_SSL + httpsport = "https"; +#endif gateport = NULL; cp = getenv("FTPSERVERPORT"); if (cp != NULL) @@ -485,6 +489,7 @@ main(int volatile argc, char **volatile argv) setupoption("anonpass", getenv("FTPANONPASS"), anonpass); setupoption("ftp_proxy", getenv(FTP_PROXY), ""); setupoption("http_proxy", getenv(HTTP_PROXY), ""); + setupoption("https_proxy", getenv(HTTPS_PROXY), ""); setupoption("no_proxy", getenv(NO_PROXY), ""); setupoption("pager", getenv("PAGER"), DEFAULTPAGER); setupoption("prompt", getenv("FTPPROMPT"), DEFAULTPROMPT); @@ -1044,6 +1049,9 @@ usage(void) " [[user@]host [port]] [host:path[/]] [file:///file]\n" " [ftp://[user[:pass]@]host[:port]/path[/]]\n" " [http://[user[:pass]@]host[:port]/path] [...]\n" +#ifdef WITH_SSL +" [https://[user[:pass]@]host[:port]/path] [...]\n" +#endif " %s -u URL file [...]\n", progname, progname); exit(1); } diff --git a/contrib/tnftp/ssl.c b/contrib/tnftp/ssl.c new file mode 100644 index 0000000000..b34c864693 --- /dev/null +++ b/contrib/tnftp/ssl.c @@ -0,0 +1,608 @@ +/* $NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $ */ + +/*- + * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav + * Copyright (c) 2008, 2010 Joerg Sonnenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $ + */ + +#include +#ifndef lint +__RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $"); +#endif + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ssl.h" + +extern int quit_time, verbose, ftp_debug; +extern FILE *ttyout; + +struct fetch_connect { + int sd; /* file/socket descriptor */ + char *buf; /* buffer */ + size_t bufsize; /* buffer size */ + size_t bufpos; /* position of buffer */ + size_t buflen; /* length of buffer contents */ + struct { /* data cached after an + interrupted read */ + char *buf; + size_t size; + size_t pos; + size_t len; + } cache; + int issock; + int iserr; + int iseof; + SSL *ssl; /* SSL handle */ +}; + +/* + * Write a vector to a connection w/ timeout + * Note: can modify the iovec. + */ +static ssize_t +fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt) +{ + struct timeval now, timeout, delta; + fd_set writefds; + ssize_t len, total; + int r; + + if (quit_time > 0) { + FD_ZERO(&writefds); + gettimeofday(&timeout, NULL); + timeout.tv_sec += quit_time; + } + + total = 0; + while (iovcnt > 0) { + while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) { + FD_SET(conn->sd, &writefds); + gettimeofday(&now, NULL); + delta.tv_sec = timeout.tv_sec - now.tv_sec; + delta.tv_usec = timeout.tv_usec - now.tv_usec; + if (delta.tv_usec < 0) { + delta.tv_usec += 1000000; + delta.tv_sec--; + } + if (delta.tv_sec < 0) { + errno = ETIMEDOUT; + return -1; + } + errno = 0; + r = select(conn->sd + 1, NULL, &writefds, NULL, &delta); + if (r == -1) { + if (errno == EINTR) + continue; + return -1; + } + } + errno = 0; + if (conn->ssl != NULL) + len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len); + else + len = writev(conn->sd, iov, iovcnt); + if (len == 0) { + /* we consider a short write a failure */ + /* XXX perhaps we shouldn't in the SSL case */ + errno = EPIPE; + return -1; + } + if (len < 0) { + if (errno == EINTR) + continue; + return -1; + } + total += len; + while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) { + len -= iov->iov_len; + iov++; + iovcnt--; + } + if (iovcnt > 0) { + iov->iov_len -= len; + iov->iov_base = (char *)iov->iov_base + len; + } + } + return total; +} + +/* + * Write to a connection w/ timeout + */ +static int +fetch_write(struct fetch_connect *conn, const char *str, size_t len) +{ + struct iovec iov[1]; + + iov[0].iov_base = (char *)__UNCONST(str); + iov[0].iov_len = len; + return fetch_writev(conn, iov, 1); +} + +/* + * Send a formatted line; optionally echo to terminal + */ +int +fetch_printf(struct fetch_connect *conn, const char *fmt, ...) +{ + va_list ap; + size_t len; + char *msg; + int r; + + va_start(ap, fmt); + len = vasprintf(&msg, fmt, ap); + va_end(ap); + + if (msg == NULL) { + errno = ENOMEM; + return -1; + } + + r = fetch_write(conn, msg, len); + free(msg); + return r; +} + +int +fetch_fileno(struct fetch_connect *conn) +{ + + return conn->sd; +} + +int +fetch_error(struct fetch_connect *conn) +{ + + return conn->iserr; +} + +static void +fetch_clearerr(struct fetch_connect *conn) +{ + + conn->iserr = 0; +} + +int +fetch_flush(struct fetch_connect *conn) +{ + int v; + + if (conn->issock) { +#ifdef TCP_NOPUSH + v = 0; + setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v)); +#endif + v = 1; + setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + } + return 0; +} + +/*ARGSUSED*/ +struct fetch_connect * +fetch_open(const char *fname, const char *fmode) +{ + struct fetch_connect *conn; + int fd; + + fd = open(fname, O_RDONLY); /* XXX: fmode */ + if (fd < 0) + return NULL; + + if ((conn = calloc(1, sizeof(*conn))) == NULL) { + close(fd); + return NULL; + } + + conn->sd = fd; + conn->issock = 0; + return conn; +} + +/*ARGSUSED*/ +struct fetch_connect * +fetch_fdopen(int sd, const char *fmode) +{ + struct fetch_connect *conn; +#if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH) + int opt = 1; +#endif + + if ((conn = calloc(1, sizeof(*conn))) == NULL) + return NULL; + + conn->sd = sd; + conn->issock = 1; + fcntl(sd, F_SETFD, FD_CLOEXEC); +#ifdef SO_NOSIGPIPE + setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif +#ifdef TCP_NOPUSH + setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt)); +#endif + return conn; +} + +int +fetch_close(struct fetch_connect *conn) +{ + int rv = 0; + + if (conn != NULL) { + fetch_flush(conn); + SSL_free(conn->ssl); + rv = close(conn->sd); + if (rv < 0) { + errno = rv; + rv = EOF; + } + free(conn->cache.buf); + free(conn->buf); + free(conn); + } + return rv; +} + +#define FETCH_READ_WAIT -2 +#define FETCH_READ_ERROR -1 + +static ssize_t +fetch_ssl_read(SSL *ssl, void *buf, size_t len) +{ + ssize_t rlen; + int ssl_err; + + rlen = SSL_read(ssl, buf, len); + if (rlen < 0) { + ssl_err = SSL_get_error(ssl, rlen); + if (ssl_err == SSL_ERROR_WANT_READ || + ssl_err == SSL_ERROR_WANT_WRITE) { + return FETCH_READ_WAIT; + } + ERR_print_errors_fp(ttyout); + return FETCH_READ_ERROR; + } + return rlen; +} + +static ssize_t +fetch_nonssl_read(int sd, void *buf, size_t len) +{ + ssize_t rlen; + + rlen = read(sd, buf, len); + if (rlen < 0) { + if (errno == EAGAIN || errno == EINTR) + return FETCH_READ_WAIT; + return FETCH_READ_ERROR; + } + return rlen; +} + +/* + * Cache some data that was read from a socket but cannot be immediately + * returned because of an interrupted system call. + */ +static int +fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes) +{ + + if (conn->cache.size < nbytes) { + char *tmp = realloc(conn->cache.buf, nbytes); + if (tmp == NULL) + return -1; + + conn->cache.buf = tmp; + conn->cache.size = nbytes; + } + + memcpy(conn->cache.buf, src, nbytes); + conn->cache.len = nbytes; + conn->cache.pos = 0; + return 0; +} + +ssize_t +fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn) +{ + struct timeval now, timeout, delta; + fd_set readfds; + ssize_t rlen, total; + size_t len; + char *start, *buf; + + if (quit_time > 0) { + gettimeofday(&timeout, NULL); + timeout.tv_sec += quit_time; + } + + total = 0; + start = buf = ptr; + len = size * nmemb; + + if (conn->cache.len > 0) { + /* + * The last invocation of fetch_read was interrupted by a + * signal after some data had been read from the socket. Copy + * the cached data into the supplied buffer before trying to + * read from the socket again. + */ + total = (conn->cache.len < len) ? conn->cache.len : len; + memcpy(buf, conn->cache.buf, total); + + conn->cache.len -= total; + conn->cache.pos += total; + len -= total; + buf += total; + } + + while (len > 0) { + /* + * The socket is non-blocking. Instead of the canonical + * select() -> read(), we do the following: + * + * 1) call read() or SSL_read(). + * 2) if an error occurred, return -1. + * 3) if we received data but we still expect more, + * update our counters and loop. + * 4) if read() or SSL_read() signaled EOF, return. + * 5) if we did not receive any data but we're not at EOF, + * call select(). + * + * In the SSL case, this is necessary because if we + * receive a close notification, we have to call + * SSL_read() one additional time after we've read + * everything we received. + * + * In the non-SSL case, it may improve performance (very + * slightly) when reading small amounts of data. + */ + if (conn->ssl != NULL) + rlen = fetch_ssl_read(conn->ssl, buf, len); + else + rlen = fetch_nonssl_read(conn->sd, buf, len); + if (rlen == 0) { + break; + } else if (rlen > 0) { + len -= rlen; + buf += rlen; + total += rlen; + continue; + } else if (rlen == FETCH_READ_ERROR) { + if (errno == EINTR) + fetch_cache_data(conn, start, total); + return -1; + } + FD_ZERO(&readfds); + while (!FD_ISSET(conn->sd, &readfds)) { + FD_SET(conn->sd, &readfds); + if (quit_time > 0) { + gettimeofday(&now, NULL); + if (!timercmp(&timeout, &now, >)) { + errno = ETIMEDOUT; + return -1; + } + timersub(&timeout, &now, &delta); + } + errno = 0; + if (select(conn->sd + 1, &readfds, NULL, NULL, + quit_time > 0 ? &delta : NULL) < 0) { + if (errno == EINTR) + continue; + return -1; + } + } + } + return total; +} + +#define MIN_BUF_SIZE 1024 + +/* + * Read a line of text from a connection w/ timeout + */ +char * +fetch_getln(char *str, int size, struct fetch_connect *conn) +{ + size_t tmpsize; + ssize_t len; + char c; + + if (conn->buf == NULL) { + if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { + errno = ENOMEM; + conn->iserr = 1; + return NULL; + } + conn->bufsize = MIN_BUF_SIZE; + } + + if (conn->iserr || conn->iseof) + return NULL; + + if (conn->buflen - conn->bufpos > 0) + goto done; + + conn->buf[0] = '\0'; + conn->bufpos = 0; + conn->buflen = 0; + do { + len = fetch_read(&c, sizeof(c), 1, conn); + if (len == -1) { + conn->iserr = 1; + return NULL; + } + if (len == 0) { + conn->iseof = 1; + break; + } + conn->buf[conn->buflen++] = c; + if (conn->buflen == conn->bufsize) { + char *tmp = conn->buf; + tmpsize = conn->bufsize * 2 + 1; + if ((tmp = realloc(tmp, tmpsize)) == NULL) { + errno = ENOMEM; + conn->iserr = 1; + return NULL; + } + conn->buf = tmp; + conn->bufsize = tmpsize; + } + } while (c != '\n'); + + if (conn->buflen == 0) + return NULL; + done: + tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos)); + memcpy(str, conn->buf + conn->bufpos, tmpsize); + str[tmpsize] = '\0'; + conn->bufpos += tmpsize; + return str; +} + +int +fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen, + const char **errormsg) +{ + size_t len; + int rv; + + if (fetch_getln(buf, buflen, conn) == NULL) { + if (conn->iseof) { /* EOF */ + rv = -2; + if (errormsg) + *errormsg = "\nEOF received"; + } else { /* error */ + rv = -1; + if (errormsg) + *errormsg = "Error encountered"; + } + fetch_clearerr(conn); + return rv; + } + len = strlen(buf); + if (buf[len - 1] == '\n') { /* clear any trailing newline */ + buf[--len] = '\0'; + } else if (len == buflen - 1) { /* line too long */ + while (1) { + char c; + ssize_t rlen = fetch_read(&c, sizeof(c), 1, conn); + if (rlen <= 0 || c == '\n') + break; + } + if (errormsg) + *errormsg = "Input line is too long"; + fetch_clearerr(conn); + return -3; + } + if (errormsg) + *errormsg = NULL; + return len; +} + +void * +fetch_start_ssl(int sock) +{ + SSL *ssl; + SSL_CTX *ctx; + int ret, ssl_err; + + /* Init the SSL library and context */ + if (!SSL_library_init()){ + fprintf(ttyout, "SSL library init failed\n"); + return NULL; + } + + SSL_load_error_strings(); + + ctx = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + + ssl = SSL_new(ctx); + if (ssl == NULL){ + fprintf(ttyout, "SSL context creation failed\n"); + SSL_CTX_free(ctx); + return NULL; + } + SSL_set_fd(ssl, sock); + while ((ret = SSL_connect(ssl)) == -1) { + ssl_err = SSL_get_error(ssl, ret); + if (ssl_err != SSL_ERROR_WANT_READ && + ssl_err != SSL_ERROR_WANT_WRITE) { + ERR_print_errors_fp(ttyout); + SSL_free(ssl); + return NULL; + } + } + + if (ftp_debug && verbose) { + X509 *cert; + X509_NAME *name; + char *str; + + fprintf(ttyout, "SSL connection established using %s\n", + SSL_get_cipher(ssl)); + cert = SSL_get_peer_certificate(ssl); + name = X509_get_subject_name(cert); + str = X509_NAME_oneline(name, 0, 0); + fprintf(ttyout, "Certificate subject: %s\n", str); + free(str); + name = X509_get_issuer_name(cert); + str = X509_NAME_oneline(name, 0, 0); + fprintf(ttyout, "Certificate issuer: %s\n", str); + free(str); + } + + return ssl; +} + + +void +fetch_set_ssl(struct fetch_connect *conn, void *ssl) +{ + conn->ssl = ssl; +} diff --git a/contrib/tnftp/version.h b/contrib/tnftp/ssl.h similarity index 53% copy from contrib/tnftp/version.h copy to contrib/tnftp/ssl.h index 9033ce4779..9ecc75975f 100644 --- a/contrib/tnftp/version.h +++ b/contrib/tnftp/ssl.h @@ -1,12 +1,9 @@ -/* $NetBSD: version.h,v 1.82 2010/06/05 13:59:39 lukem Exp $ */ +/* $NetBSD: ssl.h,v 1.1 2012/12/21 18:07:36 christos Exp $ */ /*- - * Copyright (c) 1999-2009 The NetBSD Foundation, Inc. + * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. * - * This code is derived from software contributed to The NetBSD Foundation - * by Luke Mewburn. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,11 +25,38 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef WITH_SSL + +#define FETCH struct fetch_connect +struct fetch_connect; + +int fetch_printf(struct fetch_connect *, const char *fmt, ...); +int fetch_fileno(struct fetch_connect *); +int fetch_error(struct fetch_connect *); +int fetch_flush(struct fetch_connect *); +struct fetch_connect *fetch_open(const char *, const char *); +struct fetch_connect *fetch_fdopen(int, const char *); +int fetch_close(struct fetch_connect *); +ssize_t fetch_read(void *, size_t, size_t, struct fetch_connect *); +char *fetch_getln(char *, int, struct fetch_connect *); +int fetch_getline(struct fetch_connect *, char *, size_t, const char **); +void fetch_set_ssl(struct fetch_connect *, void *); +void *fetch_start_ssl(int); + +#else /* !WITH_SSL */ + +#define FETCH FILE -#ifndef FTP_PRODUCT -#define FTP_PRODUCT "NetBSD-ftp" -#endif +#define fetch_printf fprintf +#define fetch_fileno fileno +#define fetch_error ferror +#define fetch_flush fflush +#define fetch_open fopen +#define fetch_fdopen fdopen +#define fetch_close fclose +#define fetch_read fread +#define fetch_getln fgets +#define fetch_getline get_line +#define fetch_set_ssl(a, b) -#ifndef FTP_VERSION -#define FTP_VERSION "20100605" -#endif +#endif /* !WITH_SSL */ diff --git a/contrib/tnftp/util.c b/contrib/tnftp/util.c index b0e990dcff..ee610c6278 100644 --- a/contrib/tnftp/util.c +++ b/contrib/tnftp/util.c @@ -1,4 +1,4 @@ -/* $NetBSD: util.c,v 1.157 2012/07/04 06:09:37 is Exp $ */ +/* $NetBSD: util.c,v 1.158 2013/02/19 23:29:15 dsl Exp $ */ /*- * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. @@ -64,7 +64,7 @@ #include #ifndef lint -__RCSID("$NetBSD: util.c,v 1.157 2012/07/04 06:09:37 is Exp $"); +__RCSID("$NetBSD: util.c,v 1.158 2013/02/19 23:29:15 dsl Exp $"); #endif /* not lint */ /* @@ -202,25 +202,20 @@ getremoteinfo(void) /* determine remote system type */ if (command("SYST") == COMPLETE) { if (overbose) { - char *cp, c; - - c = 0; - cp = strchr(reply_string + 4, ' '); - if (cp == NULL) - cp = strchr(reply_string + 4, '\r'); - if (cp) { - if (cp[-1] == '.') - cp--; - c = *cp; - *cp = '\0'; - } - - fprintf(ttyout, "Remote system type is %s.\n", - reply_string + 4); - if (cp) - *cp = c; + int os_len = strcspn(reply_string + 4, " \r\n\t"); + if (os_len > 1 && reply_string[4 + os_len - 1] == '.') + os_len--; + fprintf(ttyout, "Remote system type is %.*s.\n", + os_len, reply_string + 4); } - if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { + /* + * Decide whether we should default to bninary. + * Traditionally checked for "215 UNIX Type: L8", but + * some printers report "Linux" ! so be more forgiving. + * In reality we probably almost never want text any more. + */ + if (!strncasecmp(reply_string + 4, "unix", 4) || + !strncasecmp(reply_string + 4, "linux", 5)) { if (proxy) unix_proxy = 1; else diff --git a/contrib/tnftp/version.h b/contrib/tnftp/version.h index 9033ce4779..9d94b43193 100644 --- a/contrib/tnftp/version.h +++ b/contrib/tnftp/version.h @@ -1,4 +1,4 @@ -/* $NetBSD: version.h,v 1.82 2010/06/05 13:59:39 lukem Exp $ */ +/* $NetBSD: version.h,v 1.83 2013/02/06 16:37:20 christos Exp $ */ /*- * Copyright (c) 1999-2009 The NetBSD Foundation, Inc. @@ -34,5 +34,5 @@ #endif #ifndef FTP_VERSION -#define FTP_VERSION "20100605" +#define FTP_VERSION "20121224" #endif