ftp-proxy.c revision 126354
1/*	$OpenBSD: ftp-proxy.c,v 1.33 2003/08/22 21:50:34 david Exp $ */
2
3/*
4 * Copyright (c) 1996-2001
5 *	Obtuse Systems Corporation.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Obtuse Systems nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL OBTUSE SYSTEMS CORPORATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33/*
34 * ftp proxy, Originally based on juniper_ftp_proxy from the Obtuse
35 * Systems juniper firewall, written by Dan Boulet <danny@obtuse.com>
36 * and Bob Beck <beck@obtuse.com>
37 *
38 * This version basically passes everything through unchanged except
39 * for the PORT and the * "227 Entering Passive Mode" reply.
40 *
41 * A PORT command is handled by noting the IP address and port number
42 * specified and then configuring a listen port on some very high port
43 * number and telling the server about it using a PORT message.
44 * We then watch for an in-bound connection on the port from the server
45 * and connect to the client's port when it happens.
46 *
47 * A "227 Entering Passive Mode" reply is handled by noting the IP address
48 * and port number specified and then configuring a listen port on some
49 * very high port number and telling the client about it using a
50 * "227 Entering Passive Mode" reply.
51 * We then watch for an in-bound connection on the port from the client
52 * and connect to the server's port when it happens.
53 *
54 * supports tcp wrapper lookups/access control with the -w flag using
55 * the real destination address - the tcp wrapper stuff is done after
56 * the real destination address is retrieved from pf
57 *
58 */
59
60/*
61 * TODO:
62 * Plenty, this is very basic, with the idea to get it in clean first.
63 *
64 * - IPv6 and EPASV support
65 * - Content filter support
66 * - filename filter support
67 * - per-user rules perhaps.
68 */
69
70#include <sys/types.h>
71#include <sys/time.h>
72#include <sys/socket.h>
73
74#include <net/if.h>
75#include <netinet/in.h>
76
77#include <arpa/inet.h>
78
79#include <ctype.h>
80#include <errno.h>
81#include <grp.h>
82#include <netdb.h>
83#include <pwd.h>
84#include <signal.h>
85#include <stdarg.h>
86#include <stdio.h>
87#include <stdlib.h>
88#include <string.h>
89#include <sysexits.h>
90#include <syslog.h>
91#include <unistd.h>
92
93#include "util.h"
94
95#ifdef LIBWRAP
96#include <tcpd.h>
97int allow_severity = LOG_INFO;
98int deny_severity = LOG_NOTICE;
99#endif /* LIBWRAP */
100
101int min_port = IPPORT_HIFIRSTAUTO;
102int max_port = IPPORT_HILASTAUTO;
103
104#define STARTBUFSIZE  1024	/* Must be at least 3 */
105
106/*
107 * Variables used to support PORT mode connections.
108 *
109 * This gets a bit complicated.
110 *
111 * If PORT mode is on then client_listen_sa describes the socket that
112 * the real client is listening on and server_listen_sa describes the
113 * socket that we are listening on (waiting for the real server to connect
114 * with us).
115 *
116 * If PASV mode is on then client_listen_sa describes the socket that
117 * we are listening on (waiting for the real client to connect to us on)
118 * and server_listen_sa describes the socket that the real server is
119 * listening on.
120 *
121 * If the socket we are listening on gets a connection then we connect
122 * to the other side's socket.  Similarly, if a connected socket is
123 * shutdown then we shutdown the other side's socket.
124 */
125
126double xfer_start_time;
127
128struct sockaddr_in real_server_sa;
129struct sockaddr_in client_listen_sa;
130struct sockaddr_in server_listen_sa;
131
132int client_listen_socket = -1;	/* Only used in PASV mode */
133int client_data_socket = -1;	/* Connected socket to real client */
134int server_listen_socket = -1;	/* Only used in PORT mode */
135int server_data_socket = -1;	/* Connected socket to real server */
136int client_data_bytes, server_data_bytes;
137
138int AnonFtpOnly;
139int Verbose;
140int NatMode;
141
142char ClientName[NI_MAXHOST];
143char RealServerName[NI_MAXHOST];
144char OurName[NI_MAXHOST];
145
146char *User = "proxy";
147char *Group;
148
149extern int Debug_Level;
150extern int Use_Rdns;
151extern char *__progname;
152
153typedef enum {
154	UNKNOWN_MODE,
155	PORT_MODE,
156	PASV_MODE,
157	EPRT_MODE,
158	EPSV_MODE
159} connection_mode_t;
160
161connection_mode_t connection_mode;
162
163extern void	debuglog(int debug_level, const char *fmt, ...);
164double		wallclock_time(void);
165void		show_xfer_stats(void);
166void		log_control_command (char *cmd, int client);
167int		new_dataconn(int server);
168void		do_client_cmd(struct csiob *client, struct csiob *server);
169void		do_server_reply(struct csiob *server, struct csiob *client);
170static void
171usage(void)
172{
173	syslog(LOG_NOTICE,
174	    "usage: %s [-AnrVw] [-D debuglevel] [-g group] %s %s",
175	    __progname, "[-m minport] [-M maxport] [-t timeout]",
176	    "[-u user]");
177	exit(EX_USAGE);
178}
179
180static void
181close_client_data(void)
182{
183	if (client_data_socket >= 0) {
184		shutdown(client_data_socket, 2);
185		close(client_data_socket);
186		client_data_socket = -1;
187	}
188}
189
190static void
191close_server_data(void)
192{
193	if (server_data_socket >= 0)  {
194		shutdown(server_data_socket, 2);
195		close(server_data_socket);
196		server_data_socket = -1;
197	}
198}
199
200static void
201drop_privs(void)
202{
203	struct passwd *pw;
204	struct group *gr;
205	uid_t uid = 0;
206	gid_t gid = 0;
207
208	if (User != NULL) {
209		pw = getpwnam(User);
210		if (pw == NULL) {
211			syslog(LOG_ERR, "cannot find user %s", User);
212			exit(EX_USAGE);
213		}
214		uid = pw->pw_uid;
215		gid = pw->pw_gid;
216	}
217
218	if (Group != NULL) {
219		gr = getgrnam(Group);
220		if (gr == NULL) {
221			syslog(LOG_ERR, "cannot find group %s", Group);
222			exit(EX_USAGE);
223		}
224		gid = gr->gr_gid;
225	}
226
227	if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) {
228		syslog(LOG_ERR, "cannot drop group privs (%m)");
229		exit(EX_CONFIG);
230	}
231
232	if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) {
233		syslog(LOG_ERR, "cannot drop root privs (%m)");
234		exit(EX_CONFIG);
235	}
236}
237
238#ifdef LIBWRAP
239/*
240 * Check a connection against the tcpwrapper, log if we're going to
241 * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames
242 * if we are set to do reverse DNS, otherwise no.
243 */
244static int
245check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin)
246{
247	char cname[NI_MAXHOST];
248	char sname[NI_MAXHOST];
249	struct request_info request;
250	int i;
251
252	request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN,
253	    client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR,
254	    inet_ntoa(client_sin->sin_addr), 0);
255
256	if (Use_Rdns)  {
257		/*
258		 * We already looked these up, but we have to do it again
259		 * for tcp wrapper, to ensure that we get the DNS name, since
260		 * the tcp wrapper cares about these things, and we don't
261		 * want to pass in a printed address as a name.
262		 */
263		i = getnameinfo((struct sockaddr *) &client_sin->sin_addr,
264		    sizeof(&client_sin->sin_addr), cname, sizeof(cname),
265		    NULL, 0, NI_NAMEREQD);
266
267		if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
268			strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
269
270		i = getnameinfo((struct sockaddr *)&server_sin->sin_addr,
271		    sizeof(&server_sin->sin_addr), sname, sizeof(sname),
272		    NULL, 0, NI_NAMEREQD);
273
274		if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN)
275			strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
276	} else {
277		/*
278		 * ensure the TCP wrapper doesn't start doing
279		 * reverse DNS lookups if we aren't supposed to.
280		 */
281		strlcpy(cname, STRING_UNKNOWN, sizeof(cname));
282		strlcpy(sname, STRING_UNKNOWN, sizeof(sname));
283	}
284
285	request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr),
286	    0);
287	request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0);
288
289	if (!hosts_access(&request)) {
290		syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s",
291		    ClientName, RealServerName);
292		return(0);
293	}
294	return(1);
295}
296#endif /* LIBWRAP */
297
298double
299wallclock_time(void)
300{
301	struct timeval tv;
302
303	gettimeofday(&tv, NULL);
304	return(tv.tv_sec + tv.tv_usec / 1e6);
305}
306
307/*
308 * Show the stats for this data transfer
309 */
310void
311show_xfer_stats(void)
312{
313	char tbuf[1000];
314	double delta;
315	size_t len;
316	int i;
317
318	if (!Verbose)
319		return;
320
321	delta = wallclock_time() - xfer_start_time;
322
323	if (delta < 0.001)
324		delta = 0.001;
325
326	if (client_data_bytes == 0 && server_data_bytes == 0) {
327		syslog(LOG_INFO,
328		  "data transfer complete (no bytes transferred)");
329		return;
330	}
331
332	len = sizeof(tbuf);
333
334	if (delta >= 60) {
335		int idelta;
336
337		idelta = delta + 0.5;
338		if (idelta >= 60*60) {
339			i = snprintf(tbuf, len,
340			    "data transfer complete (%dh %dm %ds",
341			    idelta / (60*60), (idelta % (60*60)) / 60,
342			    idelta % 60);
343			if (i >= len)
344				goto logit;
345			len -= i;
346		} else {
347			i = snprintf(tbuf, len,
348			    "data transfer complete (%dm %ds", idelta / 60,
349			    idelta % 60);
350			if (i >= len)
351				goto logit;
352			len -= i;
353		}
354	} else {
355		i = snprintf(tbuf, len, "data transfer complete (%.1fs",
356		    delta);
357		if (i >= len)
358			goto logit;
359		len -= i;
360	}
361
362	if (client_data_bytes > 0) {
363		i = snprintf(&tbuf[strlen(tbuf)], len,
364		    ", %d bytes to server) (%.1fKB/s", client_data_bytes,
365		    (client_data_bytes / delta) / (double)1024);
366		if (i >= len)
367			goto logit;
368		len -= i;
369	}
370	if (server_data_bytes > 0) {
371		i = snprintf(&tbuf[strlen(tbuf)], len,
372		    ", %d bytes to client) (%.1fKB/s", server_data_bytes,
373		    (server_data_bytes / delta) / (double)1024);
374		if (i >= len)
375			goto logit;
376		len -= i;
377	}
378	strlcat(tbuf, ")", sizeof(tbuf));
379 logit:
380	syslog(LOG_INFO, "%s", tbuf);
381}
382
383void
384log_control_command (char *cmd, int client)
385{
386	/* log an ftp control command or reply */
387	char *logstring;
388	int level = LOG_DEBUG;
389
390	if (!Verbose)
391		return;
392
393	/* don't log passwords */
394	if (strncasecmp(cmd, "pass ", 5) == 0)
395		logstring = "PASS XXXX";
396	else
397		logstring = cmd;
398	if (client) {
399		/* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */
400		if ((strncasecmp(cmd, "user ", 5) == 0) ||
401		    (strncasecmp(cmd, "retr ", 5) == 0) ||
402		    (strncasecmp(cmd, "cwd ", 4) == 0) ||
403		    (strncasecmp(cmd, "stor " ,5) == 0))
404			level = LOG_INFO;
405	}
406	syslog(level, "%s %s", client ? "client:" : " server:",
407	    logstring);
408}
409
410/*
411 * set ourselves up for a new data connection. Direction is toward client if
412 * "server" is 0, towards server otherwise.
413 */
414int
415new_dataconn(int server)
416{
417	/*
418	 * Close existing data conn.
419	 */
420
421	if (client_listen_socket != -1) {
422		close(client_listen_socket);
423		client_listen_socket = -1;
424	}
425	close_client_data();
426
427	if (server_listen_socket != -1) {
428		close(server_listen_socket);
429		server_listen_socket = -1;
430	}
431	close_server_data();
432
433	if (server) {
434		bzero(&server_listen_sa, sizeof(server_listen_sa));
435		server_listen_socket = get_backchannel_socket(SOCK_STREAM,
436		    min_port, max_port, -1, 1, &server_listen_sa);
437
438		if (server_listen_socket == -1) {
439			syslog(LOG_INFO, "server socket bind() failed (%m)");
440			exit(EX_OSERR);
441		}
442		if (listen(server_listen_socket, 5) != 0) {
443			syslog(LOG_INFO, "server socket listen() failed (%m)");
444			exit(EX_OSERR);
445		}
446	} else {
447		bzero(&client_listen_sa, sizeof(client_listen_sa));
448		client_listen_socket = get_backchannel_socket(SOCK_STREAM,
449		    min_port, max_port, -1, 1, &client_listen_sa);
450
451		if (client_listen_socket == -1) {
452			syslog(LOG_NOTICE,
453			    "cannot get client listen socket (%m)");
454			exit(EX_OSERR);
455		}
456		if (listen(client_listen_socket, 5) != 0) {
457			syslog(LOG_NOTICE,
458			    "cannot listen on client socket (%m)");
459			exit(EX_OSERR);
460		}
461	}
462	return(0);
463}
464
465static void
466connect_pasv_backchannel(void)
467{
468	struct sockaddr_in listen_sa;
469	socklen_t salen;
470
471	/*
472	 * We are about to accept a connection from the client.
473	 * This is a PASV data connection.
474	 */
475	debuglog(2, "client listen socket ready");
476
477	close_server_data();
478	close_client_data();
479
480	salen = sizeof(listen_sa);
481	client_data_socket = accept(client_listen_socket,
482	    (struct sockaddr *)&listen_sa, &salen);
483
484	if (client_data_socket < 0) {
485		syslog(LOG_NOTICE, "accept() failed (%m)");
486		exit(EX_OSERR);
487	}
488	close(client_listen_socket);
489	client_listen_socket = -1;
490	memset(&listen_sa, 0, sizeof(listen_sa));
491
492	server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port,
493	    max_port, -1, 1, &listen_sa);
494	if (server_data_socket < 0) {
495		syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)");
496		exit(EX_OSERR);
497	}
498	if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa,
499	    sizeof(server_listen_sa)) != 0) {
500		syslog(LOG_NOTICE, "connect() failed (%m)");
501		exit(EX_NOHOST);
502	}
503	client_data_bytes = 0;
504	server_data_bytes = 0;
505	xfer_start_time = wallclock_time();
506}
507
508static void
509connect_port_backchannel(void)
510{
511	struct sockaddr_in listen_sa;
512	socklen_t salen;
513
514	/*
515	 * We are about to accept a connection from the server.
516	 * This is a PORT or EPRT data connection.
517	 */
518	debuglog(2, "server listen socket ready");
519
520	close_server_data();
521	close_client_data();
522
523	salen = sizeof(listen_sa);
524	server_data_socket = accept(server_listen_socket,
525	    (struct sockaddr *)&listen_sa, &salen);
526	if (server_data_socket < 0) {
527		syslog(LOG_NOTICE, "accept() failed (%m)");
528		exit(EX_OSERR);
529	}
530	close(server_listen_socket);
531	server_listen_socket = -1;
532
533	if (getuid() != 0)  {
534		/*
535		 * We're not running as root, so we get a backchannel
536		 * socket bound in our designated range, instead of
537		 * getting one bound to port 20 - This is deliberately
538		 * not RFC compliant.
539		 */
540		bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
541		client_data_socket =  get_backchannel_socket(SOCK_STREAM,
542		    min_port, max_port, -1, 1, &listen_sa);
543		if (client_data_socket < 0) {
544			syslog(LOG_NOTICE,  "get_backchannel_socket() failed (%m)");
545			exit(EX_OSERR);
546		}
547
548	} else {
549
550		/*
551		 * We're root, get our backchannel socket bound to port
552		 * 20 here, so we're fully RFC compliant.
553		 */
554		client_data_socket = socket(AF_INET, SOCK_STREAM, 0);
555
556		salen = 1;
557		listen_sa.sin_family = AF_INET;
558		bzero(&listen_sa.sin_addr, sizeof(struct in_addr));
559		listen_sa.sin_port = htons(20);
560
561		if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR,
562		    &salen, sizeof(salen)) == -1) {
563			syslog(LOG_NOTICE, "setsockopt() failed (%m)");
564			exit(EX_OSERR);
565		}
566
567		if (bind(client_data_socket, (struct sockaddr *)&listen_sa,
568		    sizeof(listen_sa)) == - 1) {
569			syslog(LOG_NOTICE, "data channel bind() failed (%m)");
570			exit(EX_OSERR);
571		}
572	}
573
574	if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa,
575	    sizeof(client_listen_sa)) != 0) {
576		syslog(LOG_INFO, "cannot connect data channel (%m)");
577		exit(EX_NOHOST);
578	}
579
580	client_data_bytes = 0;
581	server_data_bytes = 0;
582	xfer_start_time = wallclock_time();
583}
584
585void
586do_client_cmd(struct csiob *client, struct csiob *server)
587{
588	int i, j, rv;
589	char tbuf[100];
590	char *sendbuf = NULL;
591
592	log_control_command((char *)client->line_buffer, 1);
593
594	/* client->line_buffer is an ftp control command.
595	 * There is no reason for these to be very long.
596	 * In the interest of limiting buffer overrun attempts,
597	 * we catch them here.
598	 */
599	if (strlen((char *)client->line_buffer) > 512) {
600		syslog(LOG_NOTICE, "excessively long control command");
601		exit(EX_DATAERR);
602	}
603
604	/*
605	 * Check the client user provided if needed
606	 */
607	if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ",
608	    strlen("user ")) == 0) {
609		char *cp;
610
611		cp = (char *) client->line_buffer + strlen("user ");
612		if ((strcasecmp(cp, "ftp\r\n") != 0) &&
613		    (strcasecmp(cp, "anonymous\r\n") != 0)) {
614			/*
615			 * this isn't anonymous - give the client an
616			 * error before they send a password
617			 */
618			snprintf(tbuf, sizeof(tbuf),
619			    "500 Only anonymous FTP is allowed\r\n");
620			j = 0;
621			i = strlen(tbuf);
622			do {
623				rv = send(client->fd, tbuf + j, i - j, 0);
624				if (rv == -1 && errno != EAGAIN &&
625				    errno != EINTR)
626					break;
627				else if (rv != -1)
628					j += rv;
629			} while (j >= 0 && j < i);
630			sendbuf = NULL;
631		} else
632			sendbuf = (char *)client->line_buffer;
633	} else if ((strncasecmp((char *)client->line_buffer, "eprt ",
634	    strlen("eprt ")) == 0)) {
635
636		/* Watch out for EPRT commands */
637		char *line = NULL,  *q, *p, *result[3], delim;
638		struct addrinfo hints, *res = NULL;
639		unsigned long proto;
640
641		j = 0;
642		line = strdup((char *)client->line_buffer+strlen("eprt "));
643		if (line == NULL) {
644			syslog(LOG_ERR, "insufficient memory");
645			exit(EX_UNAVAILABLE);
646		}
647		p = line;
648		delim = p[0];
649		p++;
650
651		memset(result,0, sizeof(result));
652		for (i = 0; i < 3; i++) {
653			q = strchr(p, delim);
654			if (!q || *q != delim)
655				goto parsefail;
656			*q++ = '\0';
657			result[i] = p;
658			p = q;
659		}
660
661		proto = strtoul(result[0], &p, 10);
662		if (!*result[0] || *p)
663			goto protounsupp;
664
665		memset(&hints, 0, sizeof(hints));
666		if (proto != 1) /* 1 == AF_INET - all we support for now */
667			goto protounsupp;
668		hints.ai_family = AF_INET;
669		hints.ai_socktype = SOCK_STREAM;
670		hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
671		if (getaddrinfo(result[1], result[2], &hints, &res))
672			goto parsefail;
673		if (res->ai_next)
674			goto parsefail;
675		if (sizeof(client_listen_sa) < res->ai_addrlen)
676			goto parsefail;
677		memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen);
678
679		debuglog(1, "client wants us to use %s:%u",
680		    inet_ntoa(client_listen_sa.sin_addr),
681		    htons(client_listen_sa.sin_port));
682
683		/*
684		 * Configure our own listen socket and tell the server about it
685		 */
686		new_dataconn(1);
687		connection_mode = EPRT_MODE;
688
689		debuglog(1, "we want server to use %s:%u",
690		    inet_ntoa(server->sa.sin_addr),
691		    ntohs(server_listen_sa.sin_port));
692
693		snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1,
694		    inet_ntoa(server->sa.sin_addr),
695		    ntohs(server_listen_sa.sin_port));
696		debuglog(1, "to server (modified): %s", tbuf);
697		sendbuf = tbuf;
698		goto out;
699parsefail:
700		snprintf(tbuf, sizeof(tbuf),
701		    "500 Invalid argument; rejected\r\n");
702		sendbuf = NULL;
703		goto out;
704protounsupp:
705		/* we only support AF_INET for now */
706		if (proto == 2)
707			snprintf(tbuf, sizeof(tbuf),
708			    "522 Protocol not supported, use (1)\r\n");
709		else
710			snprintf(tbuf, sizeof(tbuf),
711			    "501 Protocol not supported\r\n");
712		sendbuf = NULL;
713out:
714		if (line)
715			free(line);
716		if (res)
717			freeaddrinfo(res);
718		if (sendbuf == NULL) {
719			debuglog(1, "to client (modified): %s", tbuf);
720			i = strlen(tbuf);
721			do {
722				rv = send(client->fd, tbuf + j, i - j, 0);
723				if (rv == -1 && errno != EAGAIN &&
724				    errno != EINTR)
725					break;
726				else if (rv != -1)
727					j += rv;
728			} while (j >= 0 && j < i);
729		}
730	} else if (!NatMode && (strncasecmp((char *)client->line_buffer,
731	    "epsv", strlen("epsv")) == 0)) {
732
733		/*
734		 * If we aren't in NAT mode, deal with EPSV.
735		 * EPSV is a problem - Unlike PASV, the reply from the
736		 * server contains *only* a port, we can't modify the reply
737		 * to the client and get the client to connect to us without
738		 * resorting to using a dynamic rdr rule we have to add in
739		 * for the reply to this connection, and take away afterwards.
740		 * so this will wait until we have the right solution for rule
741		 * additions/deletions in pf.
742		 *
743		 * in the meantime we just tell the client we don't do it,
744		 * and most clients should fall back to using PASV.
745		 */
746
747		snprintf(tbuf, sizeof(tbuf),
748		    "500 EPSV command not understood\r\n");
749		debuglog(1, "to client (modified): %s", tbuf);
750		j = 0;
751		i = strlen(tbuf);
752		do {
753			rv = send(client->fd, tbuf + j, i - j, 0);
754			if (rv == -1 && errno != EAGAIN && errno != EINTR)
755				break;
756			else if (rv != -1)
757				j += rv;
758		} while (j >= 0 && j < i);
759		sendbuf = NULL;
760	} else if (strncasecmp((char *)client->line_buffer, "port ",
761	    strlen("port ")) == 0) {
762		unsigned int values[6];
763		char *tailptr;
764
765		debuglog(1, "Got a PORT command");
766
767		tailptr = (char *)&client->line_buffer[strlen("port ")];
768		values[0] = 0;
769
770		i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
771		    &values[1], &values[2], &values[3], &values[4],
772		    &values[5]);
773		if (i != 6) {
774			syslog(LOG_INFO, "malformed PORT command (%s)",
775			    client->line_buffer);
776			exit(EX_DATAERR);
777		}
778
779		for (i = 0; i<6; i++) {
780			if (values[i] > 255) {
781				syslog(LOG_INFO,
782				    "malformed PORT command (%s)",
783				    client->line_buffer);
784				exit(EX_DATAERR);
785			}
786		}
787
788		client_listen_sa.sin_family = AF_INET;
789		client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
790		    (values[1] << 16) | (values[2] <<  8) |
791		    (values[3] <<  0));
792
793		client_listen_sa.sin_port = htons((values[4] << 8) |
794		    values[5]);
795		debuglog(1, "client wants us to use %u.%u.%u.%u:%u",
796		    values[0], values[1], values[2], values[3],
797		    (values[4] << 8) | values[5]);
798
799		/*
800		 * Configure our own listen socket and tell the server about it
801		 */
802		new_dataconn(1);
803		connection_mode = PORT_MODE;
804
805		debuglog(1, "we want server to use %s:%u",
806		    inet_ntoa(server->sa.sin_addr),
807		    ntohs(server_listen_sa.sin_port));
808
809		snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n",
810		    ((u_char *)&server->sa.sin_addr.s_addr)[0],
811		    ((u_char *)&server->sa.sin_addr.s_addr)[1],
812		    ((u_char *)&server->sa.sin_addr.s_addr)[2],
813		    ((u_char *)&server->sa.sin_addr.s_addr)[3],
814		    ((u_char *)&server_listen_sa.sin_port)[0],
815		    ((u_char *)&server_listen_sa.sin_port)[1]);
816
817		debuglog(1, "to server (modified): %s", tbuf);
818
819		sendbuf = tbuf;
820	} else
821		sendbuf = (char *)client->line_buffer;
822
823	/*
824	 *send our (possibly modified) control command in sendbuf
825	 * on it's way to the server
826	 */
827	if (sendbuf != NULL) {
828		j = 0;
829		i = strlen(sendbuf);
830		do {
831			rv = send(server->fd, sendbuf + j, i - j, 0);
832			if (rv == -1 && errno != EAGAIN && errno != EINTR)
833				break;
834			else if (rv != -1)
835				j += rv;
836		} while (j >= 0 && j < i);
837	}
838}
839
840void
841do_server_reply(struct csiob *server, struct csiob *client)
842{
843	int code, i, j, rv;
844	struct in_addr *iap;
845	static int continuing = 0;
846	char tbuf[100], *sendbuf, *p;
847
848	log_control_command((char *)server->line_buffer, 0);
849
850	if (strlen((char *)server->line_buffer) > 512) {
851		/*
852		 * someone's playing games. Have a cow in the syslogs and
853		 * exit - we don't pass this on for fear of hurting
854		 * our other end, which might be poorly implemented.
855		 */
856		syslog(LOG_NOTICE, "long FTP control reply");
857		exit(EX_DATAERR);
858	}
859
860	/*
861	 * Watch out for "227 Entering Passive Mode ..." replies
862	 */
863	code = strtol((char *)server->line_buffer, &p, 10);
864	if (isspace(server->line_buffer[0]))
865		code = 0;
866	if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) {
867		if (continuing)
868			goto sendit;
869		syslog(LOG_INFO, "malformed control reply");
870		exit(EX_DATAERR);
871	}
872	if (code <= 0 || code > 999) {
873		if (continuing)
874			goto sendit;
875		syslog(LOG_INFO, "invalid server reply code %d", code);
876		exit(EX_DATAERR);
877	}
878	if (*p == '-')
879		continuing = 1;
880	else
881		continuing = 0;
882	if (code == 227 && !NatMode) {
883		unsigned int values[6];
884		char *tailptr;
885
886		debuglog(1, "Got a PASV reply");
887		debuglog(1, "{%s}", (char *)server->line_buffer);
888
889		tailptr = (char *)strchr((char *)server->line_buffer, '(');
890		if (tailptr == NULL) {
891			tailptr = strrchr((char *)server->line_buffer, ' ');
892			if (tailptr == NULL) {
893				syslog(LOG_NOTICE, "malformed 227 reply");
894				exit(EX_DATAERR);
895			}
896		}
897		tailptr++; /* skip past space or ( */
898
899		values[0] = 0;
900
901		i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0],
902		    &values[1], &values[2], &values[3], &values[4],
903		    &values[5]);
904		if (i != 6) {
905			syslog(LOG_INFO, "malformed PASV reply (%s)",
906			    client->line_buffer);
907			exit(EX_DATAERR);
908		}
909		for (i = 0; i<6; i++)
910			if (values[i] > 255) {
911				syslog(LOG_INFO, "malformed PASV reply(%s)",
912				    client->line_buffer);
913				exit(EX_DATAERR);
914			}
915
916		server_listen_sa.sin_family = AF_INET;
917		server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) |
918		    (values[1] << 16) | (values[2] <<  8) | (values[3] <<  0));
919		server_listen_sa.sin_port = htons((values[4] << 8) |
920		    values[5]);
921
922		debuglog(1, "server wants us to use %s:%u",
923		    inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) |
924		    values[5]);
925
926		new_dataconn(0);
927		connection_mode = PASV_MODE;
928		iap = &(server->sa.sin_addr);
929
930		debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap),
931		    htons(client_listen_sa.sin_port));
932
933		snprintf(tbuf, sizeof(tbuf),
934		    "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n",
935		    ((u_char *)iap)[0], ((u_char *)iap)[1],
936		    ((u_char *)iap)[2], ((u_char *)iap)[3],
937		    ((u_char *)&client_listen_sa.sin_port)[0],
938		    ((u_char *)&client_listen_sa.sin_port)[1]);
939		debuglog(1, "to client (modified): %s", tbuf);
940		sendbuf = tbuf;
941	} else {
942 sendit:
943		sendbuf = (char *)server->line_buffer;
944	}
945
946	/*
947	 * send our (possibly modified) control command in sendbuf
948	 * on it's way to the client
949	 */
950	j = 0;
951	i = strlen(sendbuf);
952	do {
953		rv = send(client->fd, sendbuf + j, i - j, 0);
954		if (rv == -1 && errno != EAGAIN && errno != EINTR)
955			break;
956		else if (rv != -1)
957			j += rv;
958	} while (j >= 0 && j < i);
959
960}
961
962int
963main(int argc, char *argv[])
964{
965	struct csiob client_iob, server_iob;
966	struct sigaction new_sa, old_sa;
967	int sval, ch, flags, i;
968	socklen_t salen;
969	int one = 1;
970	long timeout_seconds = 0;
971	struct timeval tv;
972#ifdef LIBWRAP
973	int use_tcpwrapper = 0;
974#endif /* LIBWRAP */
975
976	while ((ch = getopt(argc, argv, "D:g:m:M:t:u:AnVwr")) != -1) {
977		char *p;
978		switch (ch) {
979		case 'A':
980			AnonFtpOnly = 1; /* restrict to anon usernames only */
981			break;
982		case 'D':
983			Debug_Level = strtol(optarg, &p, 10);
984			if (!*optarg || *p)
985				usage();
986			break;
987		case 'g':
988			Group = optarg;
989			break;
990		case 'm':
991			min_port = strtol(optarg, &p, 10);
992			if (!*optarg || *p)
993				usage();
994			if (min_port < 0 || min_port > USHRT_MAX)
995				usage();
996			break;
997		case 'M':
998			max_port = strtol(optarg, &p, 10);
999			if (!*optarg || *p)
1000				usage();
1001			if (max_port < 0 || max_port > USHRT_MAX)
1002				usage();
1003			break;
1004		case 'n':
1005			NatMode = 1; /* pass all passives, we're using NAT */
1006			break;
1007		case 'r':
1008			Use_Rdns = 1; /* look up hostnames */
1009			break;
1010		case 't':
1011			timeout_seconds = strtol(optarg, &p, 10);
1012			if (!*optarg || *p)
1013				usage();
1014			break;
1015		case 'u':
1016			User = optarg;
1017			break;
1018		case 'V':
1019			Verbose = 1;
1020			break;
1021#ifdef LIBWRAP
1022		case 'w':
1023			use_tcpwrapper = 1; /* do the libwrap thing */
1024			break;
1025#endif /* LIBWRAP */
1026		default:
1027			usage();
1028			/* NOTREACHED */
1029		}
1030	}
1031	argc -= optind;
1032	argv += optind;
1033
1034	if (max_port < min_port)
1035		usage();
1036
1037	openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON);
1038
1039	setlinebuf(stdout);
1040	setlinebuf(stderr);
1041
1042	memset(&client_iob, 0, sizeof(client_iob));
1043	memset(&server_iob, 0, sizeof(server_iob));
1044
1045	if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1)
1046		exit(EX_PROTOCOL);
1047
1048	/*
1049	 * We may now drop root privs, as we have done our ioctl for
1050	 * pf. If we do drop root, we can't make backchannel connections
1051	 * for PORT and EPRT come from port 20, which is not strictly
1052	 * RFC compliant. This shouldn't cause problems for all but
1053	 * the stupidest ftp clients and the stupidest packet filters.
1054	 */
1055	drop_privs();
1056
1057	/*
1058	 * We check_host after get_proxy_env so that checks are done
1059	 * against the original destination endpoint, not the endpoint
1060	 * of our side of the rdr. This allows the use of tcpwrapper
1061	 * rules to restrict destinations as well as sources of connections
1062	 * for ftp.
1063	 */
1064	if (Use_Rdns)
1065		flags = 0;
1066	else
1067		flags = NI_NUMERICHOST | NI_NUMERICSERV;
1068
1069	i = getnameinfo((struct sockaddr *)&client_iob.sa,
1070	    sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0,
1071	    flags);
1072
1073	if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1074		debuglog(2, "name resolution failure (client)");
1075		exit(EX_OSERR);
1076	}
1077
1078	i = getnameinfo((struct sockaddr *)&real_server_sa,
1079	    sizeof(real_server_sa), RealServerName, sizeof(RealServerName),
1080	    NULL, 0, flags);
1081
1082	if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1083		debuglog(2, "name resolution failure (server)");
1084		exit(EX_OSERR);
1085	}
1086
1087#ifdef LIBWRAP
1088	if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa))
1089		exit(EX_NOPERM);
1090#endif
1091
1092	client_iob.fd = 0;
1093
1094	syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName,
1095		ntohs(client_iob.sa.sin_port), RealServerName,
1096		ntohs(real_server_sa.sin_port));
1097
1098	server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port,
1099	    -1,	1, &server_iob.sa);
1100
1101	if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa,
1102	    sizeof(real_server_sa)) != 0) {
1103		syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName,
1104		    ntohs(real_server_sa.sin_port));
1105		exit(EX_NOHOST);
1106	}
1107
1108	/*
1109	 * Now that we are connected to the real server, get the name
1110	 * of our end of the server socket so we know our IP address
1111	 * from the real server's perspective.
1112	 */
1113	salen = sizeof(server_iob.sa);
1114	getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen);
1115
1116	i = getnameinfo((struct sockaddr *)&server_iob.sa,
1117	    sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags);
1118
1119	if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) {
1120		debuglog(2, "name resolution failure (local)");
1121		exit(EX_OSERR);
1122	}
1123
1124	debuglog(1, "local socket is %s:%u", OurName,
1125	    ntohs(server_iob.sa.sin_port));
1126
1127	/* ignore SIGPIPE */
1128	bzero(&new_sa, sizeof(new_sa));
1129	new_sa.sa_handler = SIG_IGN;
1130	(void)sigemptyset(&new_sa.sa_mask);
1131	new_sa.sa_flags = SA_RESTART;
1132	if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) {
1133		syslog(LOG_ERR, "sigaction() failed (%m)");
1134		exit(EX_OSERR);
1135	}
1136
1137	if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one,
1138	    sizeof(one)) == -1) {
1139		syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)");
1140		exit(EX_OSERR);
1141	}
1142
1143	client_iob.line_buffer_size = STARTBUFSIZE;
1144	client_iob.line_buffer = malloc(client_iob.line_buffer_size);
1145	client_iob.io_buffer_size = STARTBUFSIZE;
1146	client_iob.io_buffer = malloc(client_iob.io_buffer_size);
1147	client_iob.next_byte = 0;
1148	client_iob.io_buffer_len = 0;
1149	client_iob.alive = 1;
1150	client_iob.who = "client";
1151	client_iob.send_oob_flags = 0;
1152	client_iob.real_sa = client_iob.sa;
1153
1154	server_iob.line_buffer_size = STARTBUFSIZE;
1155	server_iob.line_buffer = malloc(server_iob.line_buffer_size);
1156	server_iob.io_buffer_size = STARTBUFSIZE;
1157	server_iob.io_buffer = malloc(server_iob.io_buffer_size);
1158	server_iob.next_byte = 0;
1159	server_iob.io_buffer_len = 0;
1160	server_iob.alive = 1;
1161	server_iob.who = "server";
1162	server_iob.send_oob_flags = MSG_OOB;
1163	server_iob.real_sa = real_server_sa;
1164
1165	if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL ||
1166	    server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) {
1167		syslog (LOG_NOTICE, "insufficient memory");
1168		exit(EX_UNAVAILABLE);
1169	}
1170
1171	while (client_iob.alive || server_iob.alive) {
1172		int maxfd = 0;
1173		fd_set *fdsp;
1174
1175		if (client_iob.fd > maxfd)
1176			maxfd = client_iob.fd;
1177		if (client_listen_socket > maxfd)
1178			maxfd = client_listen_socket;
1179		if (client_data_socket > maxfd)
1180			maxfd = client_data_socket;
1181		if (server_iob.fd > maxfd)
1182			maxfd = server_iob.fd;
1183		if (server_listen_socket > maxfd)
1184			maxfd = server_listen_socket;
1185		if (server_data_socket > maxfd)
1186			maxfd = server_data_socket;
1187
1188		debuglog(3, "client is %s; server is %s",
1189		    client_iob.alive ? "alive" : "dead",
1190		    server_iob.alive ? "alive" : "dead");
1191
1192		fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS),
1193		    sizeof(fd_mask));
1194		if (fdsp == NULL) {
1195			syslog(LOG_NOTICE, "insufficient memory");
1196			exit(EX_UNAVAILABLE);
1197		}
1198
1199		if (client_iob.alive && telnet_getline(&client_iob,
1200		    &server_iob)) {
1201			debuglog(3, "client line buffer is \"%s\"",
1202			    (char *)client_iob.line_buffer);
1203			if (client_iob.line_buffer[0] != '\0')
1204				do_client_cmd(&client_iob, &server_iob);
1205		} else if (server_iob.alive && telnet_getline(&server_iob,
1206		    &client_iob)) {
1207			debuglog(3, "server line buffer is \"%s\"",
1208			    (char *)server_iob.line_buffer);
1209			if (server_iob.line_buffer[0] != '\0')
1210				do_server_reply(&server_iob, &client_iob);
1211		} else {
1212			if (client_iob.alive) {
1213				FD_SET(client_iob.fd, fdsp);
1214				if (client_listen_socket >= 0)
1215					FD_SET(client_listen_socket, fdsp);
1216				if (client_data_socket >= 0)
1217					FD_SET(client_data_socket, fdsp);
1218			}
1219			if (server_iob.alive) {
1220				FD_SET(server_iob.fd, fdsp);
1221				if (server_listen_socket >= 0)
1222					FD_SET(server_listen_socket, fdsp);
1223				if (server_data_socket >= 0)
1224					FD_SET(server_data_socket, fdsp);
1225			}
1226			tv.tv_sec = timeout_seconds;
1227			tv.tv_usec = 0;
1228
1229		doselect:
1230			sval = select(maxfd + 1, fdsp, NULL, NULL,
1231			    (tv.tv_sec == 0) ? NULL : &tv);
1232			if (sval == 0) {
1233				/*
1234				 * This proxy has timed out. Expire it
1235				 * quietly with an obituary in the syslogs
1236				 * for any passing mourners.
1237				 */
1238				syslog(LOG_INFO,
1239				    "timeout: no data for %ld seconds",
1240				    timeout_seconds);
1241				exit(EX_OK);
1242			}
1243			if (sval == -1) {
1244				if (errno == EINTR || errno == EAGAIN)
1245					goto doselect;
1246				syslog(LOG_NOTICE,
1247				    "select() failed (%m)");
1248				exit(EX_OSERR);
1249			}
1250			if (client_data_socket >= 0 &&
1251			    FD_ISSET(client_data_socket, fdsp)) {
1252				int rval;
1253
1254				debuglog(3, "transfer: client to server");
1255				rval = xfer_data("client to server",
1256				    client_data_socket,
1257				    server_data_socket,
1258				    client_iob.sa.sin_addr,
1259				    real_server_sa.sin_addr);
1260				if (rval <= 0) {
1261					close_client_data();
1262					close_server_data();
1263					show_xfer_stats();
1264				} else
1265					client_data_bytes += rval;
1266			}
1267			if (server_data_socket >= 0 &&
1268			    FD_ISSET(server_data_socket, fdsp)) {
1269				int rval;
1270
1271				debuglog(3, "transfer: server to client");
1272				rval = xfer_data("server to client",
1273				    server_data_socket,
1274				    client_data_socket,
1275				    real_server_sa.sin_addr,
1276				    client_iob.sa.sin_addr);
1277				if (rval <= 0) {
1278					close_client_data();
1279					close_server_data();
1280					show_xfer_stats();
1281				} else
1282					server_data_bytes += rval;
1283			}
1284			if (server_listen_socket >= 0 &&
1285			    FD_ISSET(server_listen_socket, fdsp)) {
1286				connect_port_backchannel();
1287			}
1288			if (client_listen_socket >= 0 &&
1289			    FD_ISSET(client_listen_socket, fdsp)) {
1290				connect_pasv_backchannel();
1291			}
1292			if (client_iob.alive &&
1293			    FD_ISSET(client_iob.fd, fdsp)) {
1294				client_iob.data_available = 1;
1295			}
1296			if (server_iob.alive &&
1297			    FD_ISSET(server_iob.fd, fdsp)) {
1298				server_iob.data_available = 1;
1299			}
1300		}
1301		free(fdsp);
1302		if (client_iob.got_eof) {
1303			shutdown(server_iob.fd, 1);
1304			shutdown(client_iob.fd, 0);
1305			client_iob.got_eof = 0;
1306			client_iob.alive = 0;
1307		}
1308		if (server_iob.got_eof) {
1309			shutdown(client_iob.fd, 1);
1310			shutdown(server_iob.fd, 0);
1311			server_iob.got_eof = 0;
1312			server_iob.alive = 0;
1313		}
1314	}
1315
1316	if (Verbose)
1317		syslog(LOG_INFO, "session ended");
1318
1319	exit(EX_OK);
1320}
1321