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