diff options
author | Gavin Atkinson <gavin@FreeBSD.org> | 2013-05-05 15:04:47 +0000 |
---|---|---|
committer | Gavin Atkinson <gavin@FreeBSD.org> | 2013-05-05 15:04:47 +0000 |
commit | f5acf0e0ffbf00e44c2e9848a62e0b6d402b31fa (patch) | |
tree | 53870232aa9935fe0a8870c674dcd78289ab1e2e /src | |
parent | 1d78dcfdf287769fef244c1c78eba60eade69bbb (diff) | |
download | src-f5acf0e0ffbf00e44c2e9848a62e0b6d402b31fa.tar.gz src-f5acf0e0ffbf00e44c2e9848a62e0b6d402b31fa.zip |
Vendor import of tnftp-20130505.vendor/tnftp/20130505
Notes
Notes:
svn path=/vendor/tnftp/dist/; revision=250274
svn path=/vendor/tnftp/20130505/; revision=250275; tag=vendor/tnftp/20130505
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 16 | ||||
-rw-r--r-- | src/Makefile.in | 95 | ||||
-rw-r--r-- | src/cmds.c | 25 | ||||
-rw-r--r-- | src/cmdtab.c | 7 | ||||
-rw-r--r-- | src/extern.h | 15 | ||||
-rw-r--r-- | src/fetch.c | 187 | ||||
-rw-r--r-- | src/ftp.1 | 76 | ||||
-rw-r--r-- | src/ftp.c | 48 | ||||
-rw-r--r-- | src/ftp_var.h | 8 | ||||
-rw-r--r-- | src/main.c | 54 | ||||
-rw-r--r-- | src/progressbar.c | 9 | ||||
-rw-r--r-- | src/ssl.c | 615 | ||||
-rw-r--r-- | src/ssl.h | 63 | ||||
-rw-r--r-- | src/util.c | 126 | ||||
-rw-r--r-- | src/version.h | 6 |
15 files changed, 1107 insertions, 243 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8ac32f98fe24..ee4d5d03f9ef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $NetBSD: Makefile.am,v 1.2 2010/01/04 06:24:20 lukem Exp $ +## $NetBSD: Makefile.am,v 1.4 2013/05/05 13:29:19 lukem Exp $ bin_PROGRAMS = tnftp @@ -35,6 +35,19 @@ tnftp_LDADD += \ endif +if WITH_SSL +tnftp_SOURCES += \ + ssl.c + +tnftp_CPPFLAGS += \ + $(OPENSSL_INCLUDES) + +tnftp_LDADD += \ + $(OPENSSL_LDFLAGS) \ + $(OPENSSL_LIBS) +endif + + man1_MANS = \ tnftp.1 @@ -49,4 +62,5 @@ EXTRA_DIST = \ ftp.1 \ ftp_var.h \ progressbar.h \ + ssl.h \ version.h diff --git a/src/Makefile.in b/src/Makefile.in index e11a81add7ef..0c530d42c55f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11 from Makefile.am. +# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -41,10 +41,26 @@ bin_PROGRAMS = tnftp$(EXEEXT) @USE_LIBEDIT_TRUE@am__append_2 = \ @USE_LIBEDIT_TRUE@ ../libedit/libedit.la +@WITH_SSL_TRUE@am__append_3 = \ +@WITH_SSL_TRUE@ ssl.c + +@WITH_SSL_TRUE@am__append_4 = \ +@WITH_SSL_TRUE@ $(OPENSSL_INCLUDES) + +@WITH_SSL_TRUE@am__append_5 = \ +@WITH_SSL_TRUE@ $(OPENSSL_LDFLAGS) \ +@WITH_SSL_TRUE@ $(OPENSSL_LIBS) + subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/buildaux/ax_check_openssl.m4 \ + $(top_srcdir)/buildaux/libtool.m4 \ + $(top_srcdir)/buildaux/ltoptions.m4 \ + $(top_srcdir)/buildaux/ltsugar.m4 \ + $(top_srcdir)/buildaux/ltversion.m4 \ + $(top_srcdir)/buildaux/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d @@ -53,13 +69,20 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) +am__tnftp_SOURCES_DIST = cmds.c cmdtab.c complete.c domacro.c fetch.c \ + ftp.c main.c progressbar.c ruserpass.c util.c ssl.c +@WITH_SSL_TRUE@am__objects_1 = tnftp-ssl.$(OBJEXT) am_tnftp_OBJECTS = tnftp-cmds.$(OBJEXT) tnftp-cmdtab.$(OBJEXT) \ tnftp-complete.$(OBJEXT) tnftp-domacro.$(OBJEXT) \ tnftp-fetch.$(OBJEXT) tnftp-ftp.$(OBJEXT) tnftp-main.$(OBJEXT) \ tnftp-progressbar.$(OBJEXT) tnftp-ruserpass.$(OBJEXT) \ - tnftp-util.$(OBJEXT) + tnftp-util.$(OBJEXT) $(am__objects_1) tnftp_OBJECTS = $(am_tnftp_OBJECTS) -tnftp_DEPENDENCIES = ../libnetbsd/libnetbsd.la $(am__append_2) +am__DEPENDENCIES_1 = +@WITH_SSL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ +@WITH_SSL_TRUE@ $(am__DEPENDENCIES_1) +tnftp_DEPENDENCIES = ../libnetbsd/libnetbsd.la $(am__append_2) \ + $(am__DEPENDENCIES_2) AM_V_lt = $(am__v_lt_$(V)) am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) am__v_lt_0 = --silent @@ -90,7 +113,7 @@ AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(tnftp_SOURCES) -DIST_SOURCES = $(tnftp_SOURCES) +DIST_SOURCES = $(am__tnftp_SOURCES_DIST) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ @@ -132,39 +155,45 @@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ -ECHO = @ECHO@ +DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ -F77 = @F77@ -FFLAGS = @FFLAGS@ +FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ +NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_INCLUDES = @OPENSSL_INCLUDES@ +OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ @@ -173,6 +202,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ @@ -183,9 +213,9 @@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_F77 = @ac_ct_F77@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -231,23 +261,14 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -tnftp_SOURCES = \ - cmds.c \ - cmdtab.c \ - complete.c \ - domacro.c \ - fetch.c \ - ftp.c \ - main.c \ - progressbar.c \ - ruserpass.c \ - util.c - +tnftp_SOURCES = cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c \ + main.c progressbar.c ruserpass.c util.c $(am__append_3) tnftp_CPPFLAGS = -DHAVE_TNFTPD_H=1 \ -D_DEFAULT_CONFDIR=\"${sysconfdir}\" -I$(srcdir) \ -I$(top_srcdir)/libnetbsd -I$(top_srcdir) -I$(top_builddir) \ - $(am__append_1) -tnftp_LDADD = ../libnetbsd/libnetbsd.la $(am__append_2) + $(am__append_1) $(am__append_4) +tnftp_LDADD = ../libnetbsd/libnetbsd.la $(am__append_2) \ + $(am__append_5) man1_MANS = \ tnftp.1 @@ -259,6 +280,7 @@ EXTRA_DIST = \ ftp.1 \ ftp_var.h \ progressbar.h \ + ssl.h \ version.h all: all-am @@ -357,6 +379,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnftp-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnftp-progressbar.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnftp-ruserpass.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnftp-ssl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnftp-util.Po@am__quote@ .c.o: @@ -543,6 +566,22 @@ tnftp-util.obj: util.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-util.obj `if test -f 'util.c'; then $(CYGPATH_W) 'util.c'; else $(CYGPATH_W) '$(srcdir)/util.c'; fi` +tnftp-ssl.o: ssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ssl.o -MD -MP -MF $(DEPDIR)/tnftp-ssl.Tpo -c -o tnftp-ssl.o `test -f 'ssl.c' || echo '$(srcdir)/'`ssl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ssl.Tpo $(DEPDIR)/tnftp-ssl.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ssl.c' object='tnftp-ssl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ssl.o `test -f 'ssl.c' || echo '$(srcdir)/'`ssl.c + +tnftp-ssl.obj: ssl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tnftp-ssl.obj -MD -MP -MF $(DEPDIR)/tnftp-ssl.Tpo -c -o tnftp-ssl.obj `if test -f 'ssl.c'; then $(CYGPATH_W) 'ssl.c'; else $(CYGPATH_W) '$(srcdir)/ssl.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tnftp-ssl.Tpo $(DEPDIR)/tnftp-ssl.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ssl.c' object='tnftp-ssl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tnftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tnftp-ssl.obj `if test -f 'ssl.c'; then $(CYGPATH_W) 'ssl.c'; else $(CYGPATH_W) '$(srcdir)/ssl.c'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/src/cmds.c b/src/cmds.c index 7be3a7782a17..a8e33bdbc3f6 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -1,5 +1,5 @@ -/* $NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $ */ -/* from NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp */ +/* $NetBSD: cmds.c,v 1.18 2013/05/05 11:17:30 lukem Exp $ */ +/* from NetBSD: cmds.c,v 1.135 2012/12/22 16:57:09 christos Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -101,7 +101,7 @@ #if 0 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; #else -__RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp "); +__RCSID(" NetBSD: cmds.c,v 1.135 2012/12/22 16:57:09 christos Exp "); #endif #endif /* not lint */ @@ -116,6 +116,7 @@ __RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp "); #include <ctype.h> #include <err.h> +#include <errno.h> #include <glob.h> #include <limits.h> #include <netdb.h> @@ -149,7 +150,7 @@ static struct types { static sigjmp_buf jabort; static int confirm(const char *, const char *); -static void mintr(int); +__dead static void mintr(int); static void mabort(const char *); static void set_type(const char *); @@ -563,14 +564,14 @@ void reget(int argc, char *argv[]) { - (void)getit(argc, argv, 1, "r+"); + (void)getit(argc, argv, 1, restart_point ? "r+" : "a"); } void get(int argc, char *argv[]) { - (void)getit(argc, argv, 0, restart_point ? "r+" : "w" ); + (void)getit(argc, argv, 0, restart_point ? "r+" : "w"); } /* @@ -619,10 +620,14 @@ getit(int argc, char *argv[], int restartit, const char *gmode) ret = stat(locfile, &stbuf); if (restartit == 1) { if (ret < 0) { - warn("Can't stat `%s'", locfile); - goto freegetit; + if (errno != ENOENT) { + warn("Can't stat `%s'", locfile); + goto freegetit; + } + restart_point = 0; } - restart_point = stbuf.st_size; + else + restart_point = stbuf.st_size; } else { if (ret == 0) { time_t mtime; @@ -2677,7 +2682,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/src/cmdtab.c b/src/cmdtab.c index dec48e817abb..5a51bd4cf357 100644 --- a/src/cmdtab.c +++ b/src/cmdtab.c @@ -1,5 +1,5 @@ -/* $NetBSD: cmdtab.c,v 1.11 2009/05/20 12:53:47 lukem Exp $ */ -/* from NetBSD: cmdtab.c,v 1.51 2009/04/12 10:18:52 lukem Exp */ +/* $NetBSD: cmdtab.c,v 1.12 2013/05/05 11:17:30 lukem Exp $ */ +/* from NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -68,7 +68,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 */ @@ -306,6 +306,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/src/extern.h b/src/extern.h index 9b6c6458c2ec..d9b7a50df13e 100644 --- a/src/extern.h +++ b/src/extern.h @@ -1,5 +1,5 @@ -/* $NetBSD: extern.h,v 1.12 2009/11/15 10:12:37 lukem Exp $ */ -/* from NetBSD: extern.h,v 1.77 2009/07/13 19:05:41 roy Exp */ +/* $NetBSD: extern.h,v 1.13 2013/05/05 11:17:30 lukem Exp $ */ +/* from NetBSD: extern.h,v 1.80 2012/07/04 06:09:37 is Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -95,9 +95,6 @@ struct tm; struct addrinfo; void abort_remote(FILE *); -void abort_squared(int); -void abortpt(int); -void abortxfer(int); void account(int, char **); void ai_unmapped(struct addrinfo *); int another(int *, char ***, const char *); @@ -146,7 +143,7 @@ void help(int, char **); char *hookup(const char *, const char *); void idlecmd(int, char **); int initconn(void); -void intr(int); +__dead void intr(int); int isipv6addr(const char *); void list_vertical(StringList *); void lcd(int, char **); @@ -167,9 +164,10 @@ const char *onoff(int); void opts(int, char **); void newer(int, char **); void page(int, char **); +const char *parse_rfc2616time(struct tm *, const char *); int parserate(int, char **, int); char *prompt(void); -void proxabort(int); +__dead void proxabort(int); void proxtrans(const char *, const char *, const char *); void psabort(int); void pswitch(int); @@ -241,9 +239,8 @@ int togglevar(int, char **, int *, const char *); void unsetoption(int, char **); void updatelocalcwd(void); void updateremotecwd(void); -void usage(void); void user(int, char **); -int ftp_connect(int, const struct sockaddr *, socklen_t); +int ftp_connect(int, const struct sockaddr *, socklen_t, int); int ftp_listen(int, int); int ftp_poll(struct pollfd *, int, int); void *ftp_malloc(size_t); diff --git a/src/fetch.c b/src/fetch.c index 91b49fd2435a..e9589e044ed1 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -1,5 +1,5 @@ -/* $NetBSD: fetch.c,v 1.18 2009/11/15 10:12:37 lukem Exp $ */ -/* from NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp */ +/* $NetBSD: fetch.c,v 1.19 2013/05/05 11:17:30 lukem Exp $ */ +/* from NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp */ /*- * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. @@ -39,7 +39,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID(" NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp "); +__RCSID(" NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp "); #endif /* not lint */ /* @@ -57,6 +57,7 @@ __RCSID(" NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp "); #include <arpa/ftp.h> #include <arpa/inet.h> +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -70,18 +71,22 @@ __RCSID(" NetBSD: fetch.c,v 1.191 2009/08/17 09:08:16 christos Exp "); #endif /* tnftp */ +#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 } url_t; -void aborthttp(int); +__dead static void aborthttp(int); #ifndef NO_AUTH static int auth_url(const char *, char **, const char *, const char *); static void base64_encode(const unsigned char *, size_t, unsigned char *); @@ -106,7 +111,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). @@ -288,7 +301,7 @@ url_decode(char *url) /* - * Parse URL of form (per RFC3986): + * Parse URL of form (per RFC 3986): * <type>://[<user>[:<password>]@]<host>[:<port>][/<path>] * Returns -1 if a parse error occurred, otherwise 0. * It's the caller's responsibility to url_decode() the returned @@ -298,7 +311,7 @@ url_decode(char *url) * malloc(3)ed strings of the relevant section, and port to * the number given, or ftpport if ftp://, or httpport if http://. * - * XXX: this is not totally RFC3986 compliant; <path> will have the + * XXX: this is not totally RFC 3986 compliant; <path> will have the * leading `/' unless it's an ftp:// URL, as this makes things easier * for file:// and http:// URLs. ftp:// URLs have the `/' between the * host and the URL-path removed, but any additional leading slashes @@ -352,6 +365,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: @@ -401,7 +421,7 @@ parse_url(const char *url, const char *desc, url_t *utype, #ifdef INET6 /* * Check if thost is an encoded IPv6 address, as per - * RFC3986: + * RFC 3986: * `[' ipv6-address ']' */ if (*thost == '[') { @@ -469,7 +489,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 /) @@ -504,17 +524,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; @@ -537,7 +561,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; } @@ -577,17 +601,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; @@ -600,12 +624,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"); @@ -666,7 +697,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) @@ -696,6 +727,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) */ @@ -706,7 +738,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) hints.ai_protocol = 0; error = getaddrinfo(host, port, &hints, &res0); if (error) { - warnx("Can't lookup `%s:%s': %s", host, port, + warnx("Can't LOOKUP `%s:%s': %s", host, port, (error == EAI_SYSTEM) ? strerror(errno) : gai_strerror(error)); goto cleanup_fetch_url; @@ -715,6 +747,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]; @@ -740,12 +775,23 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) continue; } - if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (ftp_connect(s, res->ai_addr, res->ai_addrlen, + verbose || !res->ai_next) < 0) { close(s); s = -1; continue; } +#ifdef WITH_SSL + if (urltype == HTTPS_URL_T) { + if ((ssl = fetch_start_ssl(s)) == NULL) { + close(s); + s = -1; + continue; + } + } +#endif + /* success */ break; } @@ -755,7 +801,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. */ @@ -770,11 +818,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; @@ -787,18 +835,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); @@ -806,12 +859,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) { @@ -821,7 +874,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) { @@ -830,18 +883,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++; @@ -865,7 +918,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++; @@ -941,28 +994,18 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) } else if (match_token(&cp, "Last-Modified:")) { struct tm parsed; - char *t; + const char *t; memset(&parsed, 0, sizeof(parsed)); - /* RFC1123 */ - if ((t = strptime(cp, - "%a, %d %b %Y %H:%M:%S GMT", - &parsed)) - /* RFC0850 */ - || (t = strptime(cp, - "%a, %d-%b-%y %H:%M:%S GMT", - &parsed)) - /* asctime */ - || (t = strptime(cp, - "%a, %b %d %H:%M:%S %Y", - &parsed))) { + t = parse_rfc2616time(&parsed, cp); + if (t != NULL) { parsed.tm_isdst = -1; if (*t == '\0') mtime = timegm(&parsed); #ifndef NO_DEBUG if (ftp_debug && mtime != -1) { fprintf(ttyout, - "parsed date as: %s", + "parsed time as: %s", rfc2822time(localtime(&mtime))); } #endif @@ -1142,6 +1185,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) (void)xsignal(SIGQUIT, psummary); oldintr = xsignal(SIGINT, aborthttp); + assert(rcvbuf_size > 0); if ((size_t)rcvbuf_size > bufsize) { if (xferbuf) (void)free(xferbuf); @@ -1162,7 +1206,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; } @@ -1215,7 +1259,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; @@ -1254,7 +1298,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; } @@ -1274,7 +1318,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; } @@ -1311,7 +1355,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) @@ -1340,7 +1384,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) /* * Abort a HTTP retrieval */ -void +static void aborthttp(int notused) { char msgbuf[100]; @@ -1537,12 +1581,12 @@ fetch_ftp(const char *url) * directories in one step. * * If we are dealing with an `ftp://host/path' URL - * (urltype is FTP_URL_T), then RFC3986 says we need to + * (urltype is FTP_URL_T), then RFC 3986 says we need to * send a separate CWD command for each unescaped "/" * in the path, and we have to interpret %hex escaping * *after* we find the slashes. It's possible to get * empty components here, (from multiple adjacent - * slashes in the path) and RFC3986 says that we should + * slashes in the path) and RFC 3986 says that we should * still do `CWD ' (with a null argument) in such cases. * * Many ftp servers don't support `CWD ', so if there's an @@ -1614,8 +1658,8 @@ fetch_ftp(const char *url) fprintf(stderr, "\n" "ftp: The `CWD ' command (without a directory), which is required by\n" -" RFC3986 to support the empty directory in the URL pathname (`//'),\n" -" conflicts with the server's conformance to RFC0959.\n" +" RFC 3986 to support the empty directory in the URL pathname (`//'),\n" +" conflicts with the server's conformance to RFC 959.\n" " Try the same URL without the `//' in the URL pathname.\n" "\n"); goto cleanup_fetch_ftp; @@ -1702,6 +1746,7 @@ static int go_fetch(const char *url) { char *proxyenv; + char *p; #ifndef NO_ABOUT /* @@ -1742,10 +1787,26 @@ 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)); /* + * If it contains "://" but does not begin with ftp:// + * or something that was already handled, then it's + * unsupported. + * + * If it contains ":" but not "://" then we assume the + * part before the colon is a host name, not an URL scheme, + * so we don't try to match that here. + */ + if ((p = strstr(url, "://")) != NULL && ! STRNEQUAL(url, FTP_URL)) + errx(1, "Unsupported URL scheme `%.*s'", (int)(p - url), url); + + /* * Try FTP URL-style and host:file arguments next. * If ftpproxy is set with an FTP URL, use fetch_url() * Othewise, use fetch_ftp(). diff --git a/src/ftp.1 b/src/ftp.1 index 34a88c23520b..f6a3516d8b39 100644 --- a/src/ftp.1 +++ b/src/ftp.1 @@ -1,7 +1,7 @@ -.\" $NetBSD: ftp.1,v 1.13 2009/11/15 10:12:37 lukem Exp $ -.\" from NetBSD: ftp.1,v 1.130 2009/07/11 18:35:48 joerg Exp +.\" $NetBSD: ftp.1,v 1.14 2013/05/05 11:17:30 lukem Exp $ +.\" from NetBSD: ftp.1,v 1.134 2012/12/22 16:57:10 christos Exp .\" -.\" Copyright (c) 1996-2008 The NetBSD Foundation, Inc. +.\" Copyright (c) 1996-2010 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This code is derived from software contributed to The NetBSD Foundation @@ -58,7 +58,7 @@ .\" .\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 .\" -.Dd May 10, 2008 +.Dd December 22, 2012 .Dt FTP 1 .Os .Sh NAME @@ -67,21 +67,11 @@ .Sh SYNOPSIS .Nm .Op Fl 46AadefginpRtVv -.Bk -words .Op Fl N Ar netrc -.Ek -.Bk -words .Op Fl o Ar output -.Ek -.Bk -words .Op Fl P Ar port -.Ek -.Bk -words .Op Fl q Ar quittime -.Ek -.Bk -words .Op Fl r Ar retry -.Ek .Op Fl s Ar srcaddr .Bk -words .\" [-T dir,max[,inc]] @@ -778,7 +768,7 @@ mode is .Dq stream . .It Ic modtime Ar remote-file Show the last modification time of the file on the remote machine, in -.Li RFC2822 +.Li RFC 2822 format. .It Ic more Ar file A synonym for @@ -999,7 +989,7 @@ traffic. servers are required to support the .Dv PASV command by -.Li RFC1123 , +.Li RFC 1123 , some do not.) .It Ic pdir Op Ar remote-path Perform @@ -1336,7 +1326,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 @@ -1346,6 +1336,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 . @@ -1592,7 +1585,7 @@ ascii or binary (respectively). The default transfer type is binary. .Pp In order to be compliant with -.Li RFC3986 , +.Li RFC 3986 , .Nm interprets the .Ar path @@ -1645,7 +1638,7 @@ Any .Sq Li \&% Ns Ar XX codes (per -.Li RFC3986 ) +.Li RFC 3986 ) within the path components are decoded, with .Ar XX representing a character code in hexadecimal. @@ -1753,6 +1746,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 @@ -1902,7 +1918,7 @@ Failing the above checks, if .Dq globbing is enabled, local file names are expanded according to the rules used in the -.Xr csh 1 ; +.Xr csh 1 ; see the .Ic glob command. @@ -2286,7 +2302,7 @@ URL characters are required in the username or password or .Sq / ) , encode them with -.Li RFC3986 +.Li RFC 3986 .Sq Li \&% Ns Ar XX encoding. .Pp @@ -2331,23 +2347,23 @@ for an example of how to make this automatic. .Nm attempts to be compliant with: .Bl -tag -offset indent -width 8n -.It Li RFC0959 +.It Li RFC 959 .Em File Transfer Protocol -.It Li RFC1123 +.It Li RFC 1123 .Em Requirements for Internet Hosts - Application and Support -.It Li RFC1635 +.It Li RFC 1635 .Em How to Use Anonymous FTP -.It Li RFC2389 +.It Li RFC 2389 .Em Feature negotiation mechanism for the File Transfer Protocol -.It Li RFC2428 +.It Li RFC 2428 .Em FTP Extensions for IPv6 and NATs -.It Li RFC2616 +.It Li RFC 2616 .Em Hypertext Transfer Protocol -- HTTP/1.1 -.It Li RFC2822 +.It Li RFC 2822 .Em Internet Message Format -.It Li RFC3659 +.It Li RFC 3659 .Em Extensions to FTP -.It Li RFC3986 +.It Li RFC 3986 .Em Uniform Resource Identifier (URI) .El .Sh HISTORY diff --git a/src/ftp.c b/src/ftp.c index 4c4942f1bc1d..af236acac1d8 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -1,5 +1,5 @@ -/* $NetBSD: ftp.c,v 1.18 2009/05/20 12:53:47 lukem Exp $ */ -/* from NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp */ +/* $NetBSD: ftp.c,v 1.19 2013/05/05 11:17:31 lukem Exp $ */ +/* from NetBSD: ftp.c,v 1.164 2012/07/04 06:09:37 is Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -98,7 +98,7 @@ #if 0 static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94"; #else -__RCSID(" NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp "); +__RCSID(" NetBSD: ftp.c,v 1.164 2012/07/04 06:09:37 is Exp "); #endif #endif /* not lint */ @@ -114,6 +114,7 @@ __RCSID(" NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp "); #include <arpa/ftp.h> #include <arpa/telnet.h> +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -139,6 +140,7 @@ int ptflag = 0; char pasv[BUFSIZ]; /* passive port for proxy data connection */ static int empty(FILE *, FILE *, int); +__dead static void abort_squared(int); struct sockinet { union sockunion { @@ -214,7 +216,8 @@ hookup(const char *host, const char *port) hname, sname); continue; } - if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (ftp_connect(s, res->ai_addr, res->ai_addrlen, + verbose || !res->ai_next) < 0) { close(s); s = -1; continue; @@ -545,7 +548,7 @@ empty(FILE *ecin, FILE *din, int sec) sigjmp_buf xferabort; -void +__dead static void abortxfer(int notused) { char msgbuf[100]; @@ -772,6 +775,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, if (dout == NULL) goto abort; + assert(sndbuf_size > 0); if ((size_t)sndbuf_size > bufsize) { if (buf) (void)free(buf); @@ -813,7 +817,7 @@ sendrequest(const char *cmd, const char *local, const char *remote, } (void)putc(c, dout); bytes++; -#if 0 /* this violates RFC0959 */ +#if 0 /* this violates RFC 959 */ if (c == '\r') { (void)putc('\0', dout); bytes++; @@ -1033,6 +1037,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote, progress = 0; preserve = 0; } + assert(rcvbuf_size > 0); if ((size_t)rcvbuf_size > bufsize) { if (buf) (void)free(buf); @@ -1160,7 +1165,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote, abort: /* - * abort using RFC0959 recommended IP,SYNC sequence + * abort using RFC 959 recommended IP,SYNC sequence */ if (! sigsetjmp(xferabort, 1)) { /* this is the first call */ @@ -1472,7 +1477,7 @@ initconn(void) goto bad; if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su, - data_addr.su_len) < 0) { + data_addr.su_len, 1) < 0) { if (activefallback) { (void)close(data); data = -1; @@ -1599,18 +1604,25 @@ initconn(void) UC(p[0]), UC(p[1])); break; #ifdef INET6 - case AF_INET6: - a = (char *)&data_addr.si_su.su_sin6.sin6_addr; - p = (char *)&data_addr.su_port; + case AF_INET6: { + uint8_t ua[sizeof(data_addr.si_su.su_sin6.sin6_addr)]; + uint8_t up[sizeof(data_addr.su_port)]; + + memcpy(ua, &data_addr.si_su.su_sin6.sin6_addr, + sizeof(ua)); + memcpy(up, &data_addr.su_port, sizeof(up)); + result = command( "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 6, 16, - UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]), - UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]), - UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]), - UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]), - 2, UC(p[0]), UC(p[1])); + ua[0], ua[1], ua[2], ua[3], + ua[4], ua[5], ua[6], ua[7], + ua[8], ua[9], ua[10], ua[11], + ua[12], ua[13], ua[14], ua[15], + 2, + up[0], up[1]); break; + } #endif default: result = COMPLETE + 1; /* xxx */ @@ -1820,7 +1832,7 @@ pswitch(int flag) } } -void +__dead static void abortpt(int notused) { @@ -2032,7 +2044,7 @@ gunique(const char *local) * too impatient to wait or there's another problem then ftp really * needs to get back to a known state. */ -void +static void abort_squared(int dummy) { char msgbuf[100]; diff --git a/src/ftp_var.h b/src/ftp_var.h index cd6dcbf2b5cf..79ac75decc61 100644 --- a/src/ftp_var.h +++ b/src/ftp_var.h @@ -1,5 +1,5 @@ -/* $NetBSD: ftp_var.h,v 1.10 2009/05/20 12:53:47 lukem Exp $ */ -/* from NetBSD: ftp_var.h,v 1.81 2009/04/12 10:18:52 lukem Exp */ +/* $NetBSD: ftp_var.h,v 1.11 2013/05/05 11:17:31 lukem Exp $ */ +/* from NetBSD: ftp_var.h,v 1.82 2012/12/21 18:07:36 christos Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -182,6 +182,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 @@ -278,6 +279,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/src/main.c b/src/main.c index c2d922b93dbe..73390671ff37 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ -/* $NetBSD: main.c,v 1.17 2009/11/15 10:12:37 lukem Exp $ */ -/* from NetBSD: main.c,v 1.117 2009/07/13 19:05:41 roy Exp */ +/* $NetBSD: main.c,v 1.19 2013/05/05 11:48:16 lukem Exp $ */ +/* from NetBSD: main.c,v 1.122 2012/12/22 16:57:10 christos Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. @@ -103,7 +103,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.117 2009/07/13 19:05:41 roy Exp "); +__RCSID(" NetBSD: main.c,v 1.122 2012/12/22 16:57:10 christos Exp "); #endif #endif /* not lint */ @@ -133,11 +133,12 @@ __RCSID(" NetBSD: main.c,v 1.117 2009/07/13 19:05:41 roy 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 */ +__dead static void usage(void); static void setupoption(const char *, const char *, const char *); -int main(int, char *[]); int main(int volatile argc, char **volatile argv) @@ -146,20 +147,22 @@ main(int volatile argc, char **volatile argv) struct passwd *pw; char *cp, *ep, *anonpass, *upload_path, *src_addr; const char *anonuser; - int dumbterm, s, isupload; + int dumbterm, isupload; size_t len; - socklen_t slen; tzset(); -#if 0 /* tnftp */ /* XXX */ +#if defined(HAVE_SETLOCALE) setlocale(LC_ALL, ""); -#endif /* tnftp */ +#endif setprogname(argv[0]); sigint_raised = 0; ftpport = "ftp"; httpport = "http"; +#ifdef WITH_SSL + httpsport = "https"; +#endif gateport = NULL; cp = getenv("FTPSERVERPORT"); if (cp != NULL) @@ -213,35 +216,6 @@ main(int volatile argc, char **volatile argv) if (cp != NULL && strlcpy(netrc, cp, sizeof(netrc)) >= sizeof(netrc)) errx(1, "$NETRC `%s': %s", cp, strerror(ENAMETOOLONG)); - /* - * Get the default socket buffer sizes if we don't already have them. - * It doesn't matter which socket we do this to, because on the first - * call no socket buffer sizes will have been modified, so we are - * guaranteed to get the system defaults. - */ - s = socket(AF_INET, SOCK_STREAM, 0); - if (s == -1) - err(1, "Can't create socket to determine default socket sizes"); - slen = sizeof(rcvbuf_size); - if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, - (void *)&rcvbuf_size, &slen) == -1) - err(1, "Unable to get default rcvbuf size"); - slen = sizeof(sndbuf_size); - if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, - (void *)&sndbuf_size, &slen) == -1) - err(1, "Unable to get default sndbuf size"); - (void)close(s); - /* sanity check returned buffer sizes */ - if (rcvbuf_size <= 0) - rcvbuf_size = 8 * 1024; - if (sndbuf_size <= 0) - sndbuf_size = 8 * 1024; - - if (sndbuf_size > 8 * 1024 * 1024) - sndbuf_size = 8 * 1024 * 1024; - if (rcvbuf_size > 8 * 1024 * 1024) - rcvbuf_size = 8 * 1024 * 1024; - marg_sl = ftp_sl_init(); if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = _PATH_TMP; @@ -524,6 +498,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); @@ -746,7 +721,7 @@ cmdscanner(void) */ if (strchr(margv[0], ':') != NULL || !editing || - el_parse(el, margc, (const char **)margv) != 0) + el_parse(el, margc, (void *)margv) != 0) #endif /* !NO_EDITCOMPLETE */ fputs("?Invalid command.\n", ttyout); continue; @@ -1083,6 +1058,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/src/progressbar.c b/src/progressbar.c index bd4d76d46f15..11eae3aa38dd 100644 --- a/src/progressbar.c +++ b/src/progressbar.c @@ -1,5 +1,5 @@ -/* $NetBSD: progressbar.c,v 1.14 2009/05/20 12:53:47 lukem Exp $ */ -/* from NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp */ +/* $NetBSD: progressbar.c,v 1.15 2013/05/05 11:17:31 lukem Exp $ */ +/* from NetBSD: progressbar.c,v 1.22 2012/06/27 22:07:36 riastradh Exp */ /*- * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. @@ -36,14 +36,15 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID(" NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp "); +__RCSID(" NetBSD: progressbar.c,v 1.22 2012/06/27 22:07:36 riastradh Exp "); #endif /* not lint */ /* * FTP User Program -- Misc support routines */ -#include <sys/types.h> #include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> #include <err.h> #include <errno.h> diff --git a/src/ssl.c b/src/ssl.c new file mode 100644 index 000000000000..173db08ebbd2 --- /dev/null +++ b/src/ssl.c @@ -0,0 +1,615 @@ +/* $NetBSD: ssl.c,v 1.2 2013/05/05 13:17:06 lukem Exp $ */ +/* from 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 "tnftp.h" + +#if 0 /* tnftp */ + +#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> +#endif /* tnftp */ + +#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; +} diff --git a/src/ssl.h b/src/ssl.h new file mode 100644 index 000000000000..8e4f25082813 --- /dev/null +++ b/src/ssl.h @@ -0,0 +1,63 @@ +/* $NetBSD: ssl.h,v 1.1.1.1 2013/05/05 10:40:57 lukem Exp $ */ +/* from NetBSD: ssl.h,v 1.1 2012/12/21 18:07:36 christos Exp */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ +#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 + +#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) + +#endif /* !WITH_SSL */ diff --git a/src/util.c b/src/util.c index 366b19450b84..531712c3ded1 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,5 @@ -/* $NetBSD: util.c,v 1.21 2009/11/15 10:12:37 lukem Exp $ */ -/* from NetBSD: util.c,v 1.152 2009/07/13 19:05:41 roy Exp */ +/* $NetBSD: util.c,v 1.23 2013/05/05 11:51:43 lukem Exp $ */ +/* from NetBSD: util.c,v 1.158 2013/02/19 23:29:15 dsl Exp */ /*- * Copyright (c) 1997-2009 The NetBSD Foundation, Inc. @@ -69,7 +69,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID(" NetBSD: util.c,v 1.152 2009/07/13 19:05:41 roy Exp "); +__RCSID(" NetBSD: util.c,v 1.158 2013/02/19 23:29:15 dsl Exp "); #endif /* not lint */ /* @@ -90,6 +90,7 @@ __RCSID(" NetBSD: util.c,v 1.152 2009/07/13 19:05:41 roy Exp "); #include <signal.h> #include <libgen.h> #include <limits.h> +#include <locale.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> @@ -175,7 +176,7 @@ parse_feat(const char *fline) /* * work-around broken ProFTPd servers that can't - * even obey RFC2389. + * even obey RFC 2389. */ while (*fline && isspace((int)*fline)) fline++; @@ -208,25 +209,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 @@ -399,7 +395,7 @@ ftp_login(const char *host, const char *luser, const char *lpass) */ if (anonftp) { FREEPTR(fuser); - fuser = ftp_strdup("anonymous"); /* as per RFC1635 */ + fuser = ftp_strdup("anonymous"); /* as per RFC 1635 */ FREEPTR(pass); pass = ftp_strdup(getoptionvalue("anonpass")); } @@ -763,7 +759,7 @@ remotemodtime(const char *file, int noisy) else goto cleanup_parse_time; } else { - DPRINTF("remotemodtime: parsed date `%s' as " LLF + DPRINTF("remotemodtime: parsed time `%s' as " LLF ", %s", timestr, (LLT)rtime, rfc2822time(localtime(&rtime))); @@ -784,7 +780,7 @@ remotemodtime(const char *file, int noisy) } /* - * Format tm in an RFC2822 compatible manner, with a trailing \n. + * Format tm in an RFC 2822 compatible manner, with a trailing \n. * Returns a pointer to a static string containing the result. */ const char * @@ -794,11 +790,41 @@ rfc2822time(const struct tm *tm) if (strftime(result, sizeof(result), "%a, %d %b %Y %H:%M:%S %z\n", tm) == 0) - errx(1, "Can't convert RFC2822 time: buffer too small"); + errx(1, "Can't convert RFC 2822 time: buffer too small"); return result; } /* + * Parse HTTP-date as per RFC 2616. + * Return a pointer to the next character of the consumed date string, + * or NULL if failed. + */ +const char * +parse_rfc2616time(struct tm *parsed, const char *httpdate) +{ + const char *t; +#if defined(HAVE_SETLOCALE) + const char *curlocale; + + /* The representation of %a depends on the current locale. */ + curlocale = setlocale(LC_TIME, NULL); + (void)setlocale(LC_TIME, "C"); +#endif + /* RFC 1123 */ + if ((t = strptime(httpdate, "%a, %d %b %Y %H:%M:%S GMT", parsed)) || + /* RFC 850 */ + (t = strptime(httpdate, "%a, %d-%b-%y %H:%M:%S GMT", parsed)) || + /* asctime */ + (t = strptime(httpdate, "%a, %b %d %H:%M:%S %Y", parsed))) { + ; /* do nothing */ + } +#if defined(HAVE_SETLOCALE) + (void)setlocale(LC_TIME, curlocale); +#endif + return t; +} + +/* * Update global `localcwd', which contains the state of the local cwd */ void @@ -1060,6 +1086,32 @@ strsuftoi(const char *arg) void setupsockbufsize(int sock) { + socklen_t slen; + + if (0 == rcvbuf_size) { + slen = sizeof(rcvbuf_size); + if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + (void *)&rcvbuf_size, &slen) == -1) + err(1, "Unable to determine rcvbuf size"); + if (rcvbuf_size <= 0) + rcvbuf_size = 8 * 1024; + if (rcvbuf_size > 8 * 1024 * 1024) + rcvbuf_size = 8 * 1024 * 1024; + DPRINTF("setupsockbufsize: rcvbuf_size determined as %d\n", + rcvbuf_size); + } + if (0 == sndbuf_size) { + slen = sizeof(sndbuf_size); + if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, + (void *)&sndbuf_size, &slen) == -1) + err(1, "Unable to determine sndbuf size"); + if (sndbuf_size <= 0) + sndbuf_size = 8 * 1024; + if (sndbuf_size > 8 * 1024 * 1024) + sndbuf_size = 8 * 1024 * 1024; + DPRINTF("setupsockbufsize: sndbuf_size determined as %d\n", + sndbuf_size); + } if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&sndbuf_size, sizeof(sndbuf_size)) == -1) @@ -1078,9 +1130,8 @@ ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen) { size_t di, si; - for (di = si = 0; - src[si] != '\0' && di < dstlen && si < srclen; - di++, si++) { + di = si = 0; + while (src[si] != '\0' && di < dstlen && si < srclen) { switch (src[si]) { case '\\': case ' ': @@ -1088,12 +1139,18 @@ ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen) case '\r': case '\n': case '"': - dst[di++] = '\\'; - if (di >= dstlen) + /* + * Need room for two characters and NUL, avoiding + * incomplete escape sequences at end of dst. + */ + if (di >= dstlen - 3) break; + dst[di++] = '\\'; /* FALLTHROUGH */ default: - dst[di] = src[si]; + dst[di] = src[si++]; + if (di < dstlen) + di++; } } dst[di] = '\0'; @@ -1300,7 +1357,7 @@ get_line(FILE *stream, char *buf, size_t buflen, const char **errormsg) * error message displayed.) */ int -ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen) +ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen, int pe) { int flags, rv, timeout, error; socklen_t slen; @@ -1366,8 +1423,9 @@ ftp_connect(int sock, const struct sockaddr *name, socklen_t namelen) rv = connect(sock, name, namelen); /* inititate the connection */ if (rv == -1) { /* connection error */ if (errno != EINPROGRESS) { /* error isn't "please wait" */ + if (pe || (errno != EHOSTUNREACH)) connecterror: - warn("Can't connect to `%s:%s'", hname, sname); + warn("Can't connect to `%s:%s'", hname, sname); return -1; } diff --git a/src/version.h b/src/version.h index 6bb363103071..6ae9f3f81f79 100644 --- a/src/version.h +++ b/src/version.h @@ -1,5 +1,5 @@ -/* $NetBSD: version.h,v 1.4 2009/11/15 10:12:37 lukem Exp $ */ -/* from NetBSD: version.h,v 1.80 2009/11/15 10:03:16 lukem Exp */ +/* $NetBSD: version.h,v 1.5 2013/05/05 11:17:31 lukem Exp $ */ +/* from NetBSD: version.h,v 1.84 2013/05/05 10:40:19 lukem Exp */ /*- * Copyright (c) 1999-2009 The NetBSD Foundation, Inc. @@ -35,5 +35,5 @@ #endif #ifndef FTP_VERSION -#define FTP_VERSION "20090915" +#define FTP_VERSION "20130220" #endif |