diff -r 1d593061210b -r c3326e2b8b45 components/ftp-proxy/patches/001-solaris.patch --- a/components/ftp-proxy/patches/001-solaris.patch Wed Mar 09 08:20:13 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,642 +0,0 @@ -# This patch comes from Oracle. It fixes issues preventing ftp-proxy -# from building and running on Solaris. Especially, we: -# - disabled features missing support on Solaris (queuing, rtable..) -# where adding such support is not reasonable -# - used workarounds to deal with missing pieces on Solaris (missing -# structure members in sockaddr, PF not supporting divert-to, -# using Solaris-specific random number generator) -# -# These changes are not going to upstream, they are Solaris-specific. - -diff -Naur ORIGINAL/Makefile ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile ---- ORIGINAL/Makefile 2006-11-26 03:31:13.000000000 -0800 -+++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile 2016-02-10 04:21:21.337202150 -0800 -@@ -1,13 +1,29 @@ - # $OpenBSD: Makefile,v 1.3 2006/11/26 11:31:13 deraadt Exp $ - -+CFLAGS+= -m64 -errwarn -+ - PROG= ftp-proxy - SRCS= ftp-proxy.c filter.c -+OBJS=$(SRCS:.c=.o) - MAN= ftp-proxy.8 - --CFLAGS+= -I${.CURDIR} --CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ -- -Wno-uninitialized --LDADD+= -levent --DPADD+= ${LIBEVENT} -+LDADD+= -levent -luutil -+LDFLAGS+= -z nolazyload -+ -+all: $(SRCS) $(PROG) -+ -+install: $(PROG) -+ $(INSTALL) -d $(PREFIX)/sbin -+ $(INSTALL) -m 755 $(PROG) $(PREFIX)/sbin -+ $(INSTALL) -d $(MANDIR)/man8 -+ $(INSTALL) -m 644 $(MAN) $(MANDIR)/man8 -+ -+$(PROG): $(OBJS) -+ $(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LDADD) -+ -+.c.o: -+ $(CC) $(CFLAGS) -c -o $@ $< - --.include -+clean: -+ rm -rf *.o -+ rm -rf $(PROG) -diff -Naur ORIGINAL/filter.c ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/filter.c ---- ORIGINAL/filter.c 2012-09-18 03:11:53.000000000 -0700 -+++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/filter.c 2016-02-10 04:24:03.599069704 -0800 -@@ -32,6 +32,10 @@ - #include - #include - #include -+#ifdef _SOLARIS_ -+/* we need _IOWR */ -+#include -+#endif /* _SOLARIS_ */ - - #include "filter.h" - -diff -Naur ORIGINAL/ftp-proxy.8 ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.8 ---- ORIGINAL/ftp-proxy.8 2012-06-25 04:49:19.000000000 -0700 -+++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.8 2016-02-24 06:31:17.792565815 -0800 -@@ -30,17 +30,16 @@ - .Op Fl m Ar maxsessions - .Op Fl P Ar port - .Op Fl p Ar port --.Op Fl q Ar queue - .Op Fl R Ar address - .Op Fl T Ar tag - .Op Fl t Ar timeout - .Ek - .Sh DESCRIPTION - .Nm --is a proxy for the Internet File Transfer Protocol. --FTP control connections should be redirected into the proxy using the --.Xr pf 4 --.Ar divert-to -+is a proxy for the Internet File Transfer Protocol making connections -+over IPv4 NAT possible. -+FTP control connections should be redirected into the proxy using the PF -+.Ar rdr-to - command, after which the proxy connects to the server on behalf of - the client. - .Pp -@@ -51,22 +50,20 @@ - Consequently, all connections from the server to the proxy have - their destination address rewritten, so they are redirected to the - client. --The proxy uses the --.Xr pf 4 -+The proxy uses the PF - .Ar anchor - facility for this. - .Pp - Assuming the FTP control connection is from $client to $server, the --proxy connected to the server using the $proxy source address, and --$port is negotiated, then -+proxy is connected to the server using the $proxy source address, and -+$port is negotiated, the - .Nm - adds the following rules to the anchor. - $server and $orig_server are the same unless - .Fl R - is used to force a different $server address for all connections. --(These example rules use inet, but the proxy also supports inet6.) - .Pp --In case of active mode (PORT or EPRT): -+In case of active mode (PORT): - .Bd -literal -offset 2n - pass in from $server to $proxy port $proxy_port \e - rdr-to $client port $port -@@ -74,7 +71,7 @@ - nat-to $orig_server port $natport - .Ed - .Pp --In case of passive mode (PASV or EPSV): -+In case of passive mode (PASV): - .Bd -literal -offset 2n - pass in from $client to $orig_server port $proxy_port \e - rdr-to $server port $port -@@ -83,11 +80,6 @@ - .Pp - The options are as follows: - .Bl -tag -width Ds --.It Fl 6 --IPv6 mode. --The proxy will expect and use IPv6 addresses for all communication. --Only the extended FTP modes EPSV and EPRT are allowed with IPv6. --The proxy is in IPv4 mode by default. - .It Fl A - Only permit anonymous FTP connections. - Either user "ftp" or user "anonymous" is allowed. -@@ -96,14 +88,11 @@ - connection to a server. - .It Fl b Ar address - Address where the proxy will listen for redirected control connections. --The default is 127.0.0.1, or ::1 in IPv6 mode. -+The default is 127.0.0.1. - .It Fl D Ar level - Debug level, ranging from 0 to 7. - Higher is more verbose. - The default is 5. --(These levels correspond to the --.Xr syslog 3 --levels.) - .It Fl d - Do not daemonize. - The process will stay in the foreground, logging to standard error. -@@ -120,10 +109,6 @@ - .It Fl p Ar port - Port where the proxy will listen for redirected connections. - The default is port 8021. --.It Fl q Ar queue --Create rules with queue --.Ar queue --appended, so that data connections can be queued. - .It Fl R Ar address - Fixed server address, also known as reverse mode. - The proxy will always connect to the same server, regardless of -@@ -142,9 +127,8 @@ - keyword can be implemented following the - .Nm - anchor. --These rules can use special --.Xr pf 4 --features like route-to, reply-to, label, rtable, overload, etc. that -+These rules can use special PF -+features like route-to, reply-to, label, overload, etc. that - .Nm - does not implement itself. - There must be a matching pass rule after the -@@ -159,7 +143,9 @@ - .It Fl v - Set the 'log' flag on pf rules committed by - .Nm . --Use twice to set the 'log all' flag. -+Use twice to set the -+.Sq log all -+flag. - The pf rules do not log by default. - .El - .Sh CONFIGURATION -@@ -171,27 +157,23 @@ - necessary. - .Bd -literal -offset 2n - anchor "ftp-proxy/*" --pass in quick inet proto tcp to port ftp divert-to 127.0.0.1 port 8021 -+pass in quick inet proto tcp to port ftp rdr-to 127.0.0.1 port 8021 - pass out inet proto tcp from (self) to any port ftp - .Ed -+.Pp -+To run -+.Nm -+in a non-global zone, the -+.Bd -literal -offset indent -+svc:/network/socket-filter:pf_divert -+.Ed -+instance must be online in the global zone. - .Sh SEE ALSO --.Xr ftp 1 , --.Xr pf 4 , - .Xr pf.conf 5 - .Sh CAVEATS --.Xr pf 4 --does not allow the ruleset to be modified if the system is running at a --.Xr securelevel 7 --higher than 1. --At that level --.Nm --cannot add rules to the anchors and FTP data connections may get blocked. - .Pp - Negotiated data connection ports below 1024 are not allowed. - .Pp - The negotiated IP address for active modes is ignored for security - reasons. - This makes third party file transfers impossible. --.Pp --.Nm --chroots to "/var/empty" and changes to user "proxy" to drop privileges. -diff -Naur ORIGINAL/ftp-proxy.c ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.c ---- ORIGINAL/ftp-proxy.c 2013-03-15 06:31:27.000000000 -0700 -+++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.c 2016-02-10 04:12:16.600723376 -0800 -@@ -38,9 +38,20 @@ - #include - #include - #include -+#ifdef _SOLARIS_ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#endif /* _SOLARIS_ */ - #include - #include -+#ifndef _SOLARIS_ - #include -+#endif /* !_SOLARIS_ */ - - #include "filter.h" - -@@ -60,6 +71,32 @@ - - #define sstosa(ss) ((struct sockaddr *)(ss)) - -+#ifdef _SOLARIS_ -+/* -+ * These constants are used as a range used by pick_proxy_port(). The ftp-proxy -+ * never binds these ports. They are used only within proxy_reply() and add_rdr() -+ * to be put into a FTP-protocol message and to construct the rule to be loaded -+ * into PF, respectively. -+ * -+ * OpenBSD adheres to a convention where these port numbers are reserved for -+ * connections that want to bypass a firewall. Surely, it depends on how the -+ * administrator configures the firewall, too. Let's stick to that convention -+ * here. The idea probably is "if the admin uses this convention, these ports -+ * are not filtered and thus we are not going to clash with current firewall -+ * rules". -+ */ -+#define IPPORT_HIFIRSTAUTO 49152 -+#define IPPORT_HILASTAUTO 65535 -+ -+#define getrtable() 0 -+ -+#ifndef LIST_END -+#define LIST_END(x) NULL -+#endif /* !LIST_END */ -+ -+#define DIVERT_MODULE_NAME "pf_divertf" -+#endif /* _SOLARIS_ */ -+ - enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV }; - - struct session { -@@ -115,12 +152,59 @@ - - struct event listen_ev, pause_accept_ev; - struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; -+#ifdef _SOLARIS_ -+static socklen_t fixed_server_ss_len; -+static socklen_t fixed_proxy_ss_len; -+#endif /* _SOLARIS_ */ - char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, - *qname, *tagname; - int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions, - rfc_mode, session_count, timeout, verbose; - extern char *__progname; - -+#ifdef _SOLARIS_ -+/* -+ * fake_arc4random_uniform() -+ * This is a fake implementation of arc4random_uniform(). The wrapper -+ * provides so called uniform calculation of pseudo random number with -+ * respect to upper bound. -+ * -+ * Function calculates random numbers until it finds one outside -+ * <0, 2^32 % upper_bound) range. Once random number, `rand`, is selected, -+ * function returns rand % upper_bound. -+ * -+ * Arguments: -+ * upper_bound - random number is picked up in range <0, upper_bound) -+ * -+ * Returns: -+ * random number, uniform with respect to upper bound. -+ * Returns UINT32_MAX on error. -+ */ -+static u_int32_t -+fake_arc4random_uniform(u_int32_t upper_bound) -+{ -+ u_int32_t rand, min; -+ -+ if (upper_bound < 2) -+ return (0); -+ -+ /* -+ * 2**32 % x == (2**32 - x) % x -+ * (Trick comes from OpenBSD, arc4random_uniform.c) -+ */ -+ min = -upper_bound % upper_bound; -+ for (;;) { -+ if (getrandom(&rand, sizeof (rand), GRND_NONBLOCK) != -+ sizeof (rand)) -+ return (UINT32_MAX); -+ if (rand >= min) -+ break; -+ } -+ -+ return (rand % upper_bound); -+} -+#endif /* _SOLARIS_ */ -+ - void - client_error(struct bufferevent *bufev, short what, void *arg) - { -@@ -220,6 +304,12 @@ - return (0); - } - s->proxy_port = pick_proxy_port(); -+#ifdef _SOLARIS_ -+ if (s->proxy_port == UINT16_MAX) { -+ logmsg(LOG_CRIT, "pick_proxy_port() failed"); -+ return (0); -+ } -+#endif /* _SOLARIS_ */ - proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port); - logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); - } -@@ -378,13 +468,30 @@ - struct sockaddr *proxy_to_server_sa; - struct session *s; - socklen_t len; -+#ifdef _SOLARIS_ -+ socklen_t client_sa_len, server_sa_len; -+ int one = 1; /* parameter for setsockopt */ -+#endif /* _SOLARIS_ */ - int client_fd, fc, on; -- -+ /* -+ * We experienced big problems when event_add() was called -+ * before accepting the incoming connection - for some reason, -+ * a new event was fired immediately and ftp-proxy was hanged -+ * trying to accept another client that was not there yet. -+ * Moving event_add() call a few lines below resolved this -+ * problem. -+ */ -+#ifndef _SOLARIS_ - event_add(&listen_ev, NULL); -+#endif /* !_SOLARIS_ */ - -- if ((event & EV_TIMEOUT)) -+ if ((event & EV_TIMEOUT)) { -+#ifdef _SOLARIS_ -+ event_add(&listen_ev, NULL); -+#endif /* _SOLARIS_ */ - /* accept() is no longer paused. */ - return; -+ } - - /* - * We _must_ accept the connection, otherwise libevent will keep -@@ -393,6 +500,9 @@ - client_sa = sstosa(&tmp_ss); - len = sizeof(struct sockaddr_storage); - if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) { -+#ifdef _SOLARIS_ -+ event_add(&listen_ev, NULL); -+#endif /* _SOLARIS_ */ - logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno)); - - /* -@@ -410,6 +520,16 @@ - return; - } - -+#ifdef _SOLARIS_ -+ event_add(&listen_ev, NULL); -+ -+ /* -+ * Struct sockaddr does not contain sa_len field on Solaris, -+ * we use client_sa_len instead. -+ */ -+ client_sa_len = len; -+#endif /* _SOLARIS_ */ -+ - /* Refuse connection if the maximum is reached. */ - if (session_count >= max_sessions) { - logmsg(LOG_ERR, "client limit (%d) reached, refusing " -@@ -426,8 +546,11 @@ - return; - } - s->client_fd = client_fd; -+#ifdef _SOLARIS_ -+ memcpy(sstosa(&s->client_ss), client_sa, client_sa_len); -+#else /* !_SOLARIS_ */ - memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len); -- -+#endif /* _SOLARIS_ */ - /* Cast it once, and be done with it. */ - client_sa = sstosa(&s->client_ss); - server_sa = sstosa(&s->server_ss); -@@ -447,6 +570,17 @@ - strerror(errno)); - goto fail; - } -+#ifdef _SOLARIS_ -+ /* -+ * Struct sockaddr does not contain sa_len field on Solaris, -+ * we use server_sa_len instead. -+ */ -+ server_sa_len = len; -+#endif /* _SOLARIS_ */ -+/* SO_RTABLE not defined on Solaris */ -+#ifdef _SOLARIS_ -+ s->client_rd = 0; -+#else /* !_SOLARIS_ */ - len = sizeof(s->client_rd); - if (getsockopt(s->client_fd, SOL_SOCKET, SO_RTABLE, &s->client_rd, - &len) && errno != ENOPROTOOPT) { -@@ -454,10 +588,18 @@ - strerror(errno)); - goto fail; - } -+#endif /* _SOLARIS_ */ - if (fixed_server) { -+#ifdef _SOLARIS_ -+ memcpy(sstosa(&s->orig_server_ss), server_sa, -+ server_sa_len); -+ memcpy(server_sa, fixed_server_sa, fixed_server_ss_len); -+ server_sa_len = fixed_server_ss_len; /* update the length */ -+#else /* !_SOLARIS_ */ - memcpy(sstosa(&s->orig_server_ss), server_sa, - server_sa->sa_len); - memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len); -+#endif /* _SOLARIS_ */ - } - - /* XXX: check we are not connecting to ourself. */ -@@ -471,8 +613,14 @@ - strerror(errno)); - goto fail; - } -+#ifdef _SOLARIS_ - if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss), -- fixed_proxy_ss.ss_len) != 0) { -+ fixed_proxy_ss_len) != 0) -+#else /* !_SOLARIS_ */ -+ if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss), -+ fixed_proxy_ss.ss_len) != 0) -+#endif /* _SOLARIS_ */ -+ { - logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s", - s->id, strerror(errno)); - goto fail; -@@ -485,8 +633,14 @@ - s->id, strerror(errno)); - goto fail; - } -+#ifdef _SOLARIS_ -+ if (connect(s->server_fd, server_sa, server_sa_len) < 0 && -+ errno != EINPROGRESS) -+#else /* !_SOLARIS_ */ - if (connect(s->server_fd, server_sa, server_sa->sa_len) < 0 && -- errno != EINPROGRESS) { -+ errno != EINPROGRESS) -+#endif /* _SOLARIS_ */ -+ { - logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s", - s->id, sock_ntop(server_sa), strerror(errno)); - goto fail; -@@ -592,6 +746,9 @@ - /* syslog does its own vissing. */ - vsyslog(pri, message, ap); - else { -+#ifdef _SOLARIS_ -+ vsyslog(pri, message, ap); -+#else /* !_SOLARIS_ */ - char buf[MAX_LOGLINE]; - char visbuf[2 * MAX_LOGLINE]; - -@@ -599,6 +756,7 @@ - vsnprintf(buf, sizeof buf, message, ap); - strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL); - fprintf(stderr, "%s\n", visbuf); -+#endif /* _SOLARIS_ */ - } - - va_end(ap); -@@ -636,9 +794,11 @@ - - while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) { - switch (ch) { -+#ifndef _SOLARIS_ - case '6': - ipv6_mode = 1; - break; -+#endif /* !_SOLARIS_ */ - case 'A': - anonymous_only = 1; - break; -@@ -668,11 +828,13 @@ - case 'p': - listen_port = optarg; - break; -+#ifndef _SOLARIS_ - case 'q': - if (strlen(optarg) >= PF_QNAME_SIZE) - errx(1, "queuename too long"); - qname = optarg; - break; -+#endif /* !_SOLARIS_ */ - case 'R': - fixed_server = optarg; - break; -@@ -718,9 +880,16 @@ - hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(fixed_proxy, NULL, &hints, &res); - if (error) -- errx(1, "getaddrinfo fixed proxy address failed: %s", -+ errx(1, "getaddrinfo fixed proxy address (%s) failed: %s", fixed_proxy, - gai_strerror(error)); - memcpy(&fixed_proxy_ss, res->ai_addr, res->ai_addrlen); -+#ifdef _SOLARIS_ -+ /* -+ * struct sockaddr_storage does not have the member -+ * ss_len on Solaris, thus we use a global variable. -+ */ -+ fixed_proxy_ss_len = res->ai_addrlen; -+#endif /* _SOLARIS_ */ - logmsg(LOG_INFO, "using %s to connect to servers", - sock_ntop(sstosa(&fixed_proxy_ss))); - freeaddrinfo(res); -@@ -736,6 +905,13 @@ - errx(1, "getaddrinfo fixed server address failed: %s", - gai_strerror(error)); - memcpy(&fixed_server_ss, res->ai_addr, res->ai_addrlen); -+#ifdef _SOLARIS_ -+ /* -+ * struct sockaddr_storage does not have the member -+ * ss_len on Solaris, thus we use a global variable. -+ */ -+ fixed_server_ss_len = res->ai_addrlen; -+#endif /* _SOLARIS_ */ - logmsg(LOG_INFO, "using fixed server %s", - sock_ntop(sstosa(&fixed_server_ss))); - freeaddrinfo(res); -@@ -752,6 +928,11 @@ - gai_strerror(error)); - if ((listenfd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1) - errx(1, "socket failed"); -+#ifdef _SOLARIS_ -+ if (setsockopt(listenfd, SOL_FILTER, FIL_ATTACH, DIVERT_MODULE_NAME, -+ (strlen(DIVERT_MODULE_NAME)+1)) != 0) -+ err(1, "setsockopt failed - unable to attach filter"); -+#endif /* _SOLARIS_ */ - on = 1; - if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, - sizeof on) != 0) -@@ -782,7 +963,11 @@ - event_init(); - - /* Setup signal handler. */ -+#ifdef _SOLARIS_ -+ sigset(SIGPIPE, SIG_IGN); -+#else /* !_SOLARIS_ */ - signal(SIGPIPE, SIG_IGN); -+#endif /* _SOLARIS_ */ - signal_set(&ev_sighup, SIGHUP, handle_signal, NULL); - signal_set(&ev_sigint, SIGINT, handle_signal, NULL); - signal_set(&ev_sigterm, SIGTERM, handle_signal, NULL); -@@ -857,12 +1042,25 @@ - return (0); - } - -+/* -+ * On Solaris, fake_arc4random_uniform() can fail. We return UINT16_MAX -+ * on error. -+ */ - u_int16_t - pick_proxy_port(void) - { -+#ifdef _SOLARIS_ -+ u_int32_t shift; -+ -+ shift = fake_arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO); -+ if (shift == UINT32_MAX) -+ return UINT16_MAX; -+ return (IPPORT_HIFIRSTAUTO + shift); -+#else /* !_SOLARIS_ */ - /* Random should be good enough for avoiding port collisions. */ - return (IPPORT_HIFIRSTAUTO + - arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)); -+#endif /* _SOLARIS_ */ - } - - void -@@ -985,6 +1183,12 @@ - return (0); - } - s->proxy_port = pick_proxy_port(); -+#ifdef _SOLARIS_ -+ if (s->proxy_port == UINT16_MAX) { -+ logmsg(LOG_CRIT, "pick_proxy_port() failed"); -+ return (0); -+ } -+#endif /* _SOLARIS_ */ - logmsg(LOG_INFO, "#%d passive: client to server port %d" - " via port %d", s->id, s->port, s->proxy_port); - -@@ -1126,6 +1330,6 @@ - fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]" - " [-D level] [-m maxsessions]\n [-P port]" - " [-p port] [-q queue] [-R address] [-T tag]\n" -- " [-t timeout]\n", __progname); -+ " [-t timeout]\n", __progname); - exit(1); - }