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