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