Import tnftp-20121224.
authorPeter Avalos <pavalos@dragonflybsd.org>
Sun, 7 Apr 2013 04:34:01 +0000 (21:34 -0700)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sun, 7 Apr 2013 04:34:01 +0000 (21:34 -0700)
* Add https support.
* When using the response to SYST to decide whether to default to
  'binary' be a lot less specific.

Obtained-from:   NetBSD

contrib/tnftp/cmds.c
contrib/tnftp/cmdtab.c
contrib/tnftp/fetch.c
contrib/tnftp/ftp.1
contrib/tnftp/ftp_var.h
contrib/tnftp/main.c
contrib/tnftp/ssl.c [new file with mode: 0644]
contrib/tnftp/ssl.h [copied from contrib/tnftp/version.h with 53% similarity]
contrib/tnftp/util.c
contrib/tnftp/version.h

index 633ab00..66cab2b 100644 (file)
@@ -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,
index 17d7477..13d3f4b 100644 (file)
@@ -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 },
index 30087f8..e837d8f 100644 (file)
@@ -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 <sys/cdefs.h>
 #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 <unistd.h>
 #include <time.h>
 
+#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));
 
        /*
index ac6babe..931f3b8 100644 (file)
@@ -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
index db501cf..7e5040a 100644 (file)
@@ -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 */
 
index 58234ee..c84364d 100644 (file)
@@ -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 (file)
index 0000000..b34c864
--- /dev/null
@@ -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 <joerg@NetBSD.org>
+ * 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 <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $");
+#endif
+
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/select.h>
+#include <sys/uio.h>
+
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#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;
+}
similarity index 53%
copy from contrib/tnftp/version.h
copy to contrib/tnftp/ssl.h
index 9033ce4..9ecc759 100644 (file)
@@ -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:
  * 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 */
index b0e990d..ee610c6 100644 (file)
@@ -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 <sys/cdefs.h>
 #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
index 9033ce4..9d94b43 100644 (file)
@@ -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