ftp.c revision 1.16 1 /* $NetBSD: ftp.c,v 1.16 2006/05/23 01:36:36 christos Exp $ */
2 /* $KAME: ftp.c,v 1.23 2003/08/19 21:20:33 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * 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 project 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 THE PROJECT 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 THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 #include <poll.h>
45 #include <errno.h>
46 #include <ctype.h>
47
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <netdb.h>
51
52 #include "faithd.h"
53
54 static char rbuf[MSS];
55 static char sbuf[MSS];
56 static int passivemode = 0;
57 static int wport4 = -1; /* listen() to active */
58 static int wport6 = -1; /* listen() to passive */
59 static int port4 = -1; /* active: inbound passive: outbound */
60 static int port6 = -1; /* active: outbound passive: inbound */
61 static struct sockaddr_storage data4; /* server data address */
62 static struct sockaddr_storage data6; /* client data address */
63 static int epsvall = 0;
64
65 enum state { NONE, LPRT, EPRT, LPSV, EPSV };
66
67 static int ftp_activeconn __P((void));
68 static int ftp_passiveconn __P((void));
69 static int ftp_copy __P((int, int));
70 static int ftp_copyresult __P((int, int, enum state));
71 static int ftp_copycommand __P((int, int, enum state *));
72
73 void
74 ftp_relay(int ctl6, int ctl4)
75 {
76 struct pollfd pfd[6];
77 int error;
78 enum state state = NONE;
79 struct timeval tv;
80
81 syslog(LOG_INFO, "starting ftp control connection");
82
83 for (;;) {
84 pfd[0].fd = ctl4;
85 pfd[0].events = POLLIN;
86 pfd[1].fd = ctl6;
87 pfd[1].events = POLLIN;
88 if (0 <= port4) {
89 pfd[2].fd = port4;
90 pfd[2].events = POLLIN;
91 } else
92 pfd[2].fd = -1;
93 if (0 <= port6) {
94 pfd[3].fd = port6;
95 pfd[3].events = POLLIN;
96 } else
97 pfd[3].fd = -1;
98 #if 0
99 if (0 <= wport4) {
100 pfd[4].fd = wport4;
101 pfd[4].events = POLLIN;
102 } else
103 pfd[4].fd = -1;
104 if (0 <= wport6) {
105 pfd[5].fd = wport4;
106 pfd[5].events = POLLIN;
107 } else
108 pfd[5].fd = -1;
109 #else
110 pfd[4].fd = pfd[5].fd = -1;
111 pfd[4].events = pfd[5].events = 0;
112 #endif
113 tv.tv_sec = FAITH_TIMEOUT;
114 tv.tv_usec = 0;
115
116 error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), tv.tv_sec * 1000);
117 if (error == -1) {
118 exit_failure("poll: %s", strerror(errno));
119 }
120 else if (error == 0)
121 exit_failure("connection timeout");
122
123 /*
124 * The order of the following checks does (slightly) matter.
125 * It is important to visit all checks (do not use "continue"),
126 * otherwise some of the pipe may become full and we cannot
127 * relay correctly.
128 */
129 if (pfd[1].revents & POLLIN)
130 {
131 /*
132 * copy control connection from the client.
133 * command translation is necessary.
134 */
135 error = ftp_copycommand(ctl6, ctl4, &state);
136
137 if (error < 0)
138 goto bad;
139 else if (error == 0) {
140 (void)close(ctl4);
141 (void)close(ctl6);
142 exit_success("terminating ftp control connection");
143 /*NOTREACHED*/
144 }
145 }
146 if (pfd[0].revents & POLLIN)
147 {
148 /*
149 * copy control connection from the server
150 * translation of result code is necessary.
151 */
152 error = ftp_copyresult(ctl4, ctl6, state);
153
154 if (error < 0)
155 goto bad;
156 else if (error == 0) {
157 (void)close(ctl4);
158 (void)close(ctl6);
159 exit_success("terminating ftp control connection");
160 /*NOTREACHED*/
161 }
162 }
163 if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN))
164 {
165 /*
166 * copy data connection.
167 * no special treatment necessary.
168 */
169 if (pfd[2].revents & POLLIN)
170 error = ftp_copy(port4, port6);
171 switch (error) {
172 case -1:
173 goto bad;
174 case 0:
175 if (port4 >= 0)
176 (void)close(port4);
177 if (port6)
178 (void)close(port6);
179 port4 = port6 = -1;
180 syslog(LOG_INFO, "terminating data connection");
181 break;
182 default:
183 break;
184 }
185 }
186 if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN))
187 {
188 /*
189 * copy data connection.
190 * no special treatment necessary.
191 */
192 if (pfd[3].revents & POLLIN)
193 error = ftp_copy(port6, port4);
194 switch (error) {
195 case -1:
196 goto bad;
197 case 0:
198 if (port4 >= 0)
199 (void)close(port4);
200 if (port6 >= 0)
201 (void)close(port6);
202 port4 = port6 = -1;
203 syslog(LOG_INFO, "terminating data connection");
204 break;
205 default:
206 break;
207 }
208 }
209 #if 0
210 if (wport4 && (pfd[4].revents & POLLIN))
211 {
212 /*
213 * establish active data connection from the server.
214 */
215 ftp_activeconn();
216 }
217 if (wport4 && (pfd[5].revents & POLLIN))
218 {
219 /*
220 * establish passive data connection from the client.
221 */
222 ftp_passiveconn();
223 }
224 #endif
225 }
226
227 bad:
228 exit_failure("%s", strerror(errno));
229 }
230
231 static int
232 ftp_activeconn()
233 {
234 socklen_t n;
235 int error;
236 struct pollfd pfd[1];
237 struct timeval timeout;
238 struct sockaddr *sa;
239
240 /* get active connection from server */
241 pfd[0].fd = wport4;
242 pfd[0].events = POLLIN;
243 timeout.tv_sec = 120;
244 timeout.tv_usec = 0;
245 n = sizeof(data4);
246 if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
247 (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0)
248 {
249 (void)close(wport4);
250 wport4 = -1;
251 syslog(LOG_INFO, "active mode data connection failed");
252 return -1;
253 }
254
255 /* ask active connection to client */
256 sa = (struct sockaddr *)&data6;
257 port6 = socket(sa->sa_family, SOCK_STREAM, 0);
258 if (port6 == -1) {
259 (void)close(port4);
260 (void)close(wport4);
261 port4 = wport4 = -1;
262 syslog(LOG_INFO, "active mode data connection failed");
263 return -1;
264 }
265 error = connect(port6, sa, sa->sa_len);
266 if (error < 0) {
267 (void)close(port6);
268 (void)close(port4);
269 (void)close(wport4);
270 port6 = port4 = wport4 = -1;
271 syslog(LOG_INFO, "active mode data connection failed");
272 return -1;
273 }
274
275 syslog(LOG_INFO, "active mode data connection established");
276 return 0;
277 }
278
279 static int
280 ftp_passiveconn()
281 {
282 socklen_t len;
283 int error;
284 struct pollfd pfd[1];
285 struct timeval timeout;
286 struct sockaddr *sa;
287
288 /* get passive connection from client */
289 pfd[0].fd = wport6;
290 pfd[0].events = POLLIN;
291 timeout.tv_sec = 120;
292 timeout.tv_usec = 0;
293 len = sizeof(data6);
294 if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
295 (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0)
296 {
297 (void)close(wport6);
298 wport6 = -1;
299 syslog(LOG_INFO, "passive mode data connection failed");
300 return -1;
301 }
302
303 /* ask passive connection to server */
304 sa = (struct sockaddr *)&data4;
305 port4 = socket(sa->sa_family, SOCK_STREAM, 0);
306 if (port4 == -1) {
307 (void)close(wport6);
308 (void)close(port6);
309 wport6 = port6 = -1;
310 syslog(LOG_INFO, "passive mode data connection failed");
311 return -1;
312 }
313 error = connect(port4, sa, sa->sa_len);
314 if (error < 0) {
315 (void)close(wport6);
316 (void)close(port4);
317 (void)close(port6);
318 wport6 = port4 = port6 = -1;
319 syslog(LOG_INFO, "passive mode data connection failed");
320 return -1;
321 }
322
323 syslog(LOG_INFO, "passive mode data connection established");
324 return 0;
325 }
326
327 static int
328 ftp_copy(int src, int dst)
329 {
330 int error, atmark, n;
331
332 /* OOB data handling */
333 error = ioctl(src, SIOCATMARK, &atmark);
334 if (error != -1 && atmark == 1) {
335 n = read(src, rbuf, 1);
336 if (n == -1)
337 goto bad;
338 send(dst, rbuf, n, MSG_OOB);
339 #if 0
340 n = read(src, rbuf, sizeof(rbuf));
341 if (n == -1)
342 goto bad;
343 write(dst, rbuf, n);
344 return n;
345 #endif
346 }
347
348 n = read(src, rbuf, sizeof(rbuf));
349 switch (n) {
350 case -1:
351 case 0:
352 return n;
353 default:
354 write(dst, rbuf, n);
355 return n;
356 }
357
358 bad:
359 exit_failure("%s", strerror(errno));
360 /*NOTREACHED*/
361 return 0; /* to make gcc happy */
362 }
363
364 static int
365 ftp_copyresult(int src, int dst, enum state state)
366 {
367 int error, atmark, n;
368 socklen_t len;
369 char *param;
370 int code;
371 char *a, *p;
372 int i;
373
374 /* OOB data handling */
375 error = ioctl(src, SIOCATMARK, &atmark);
376 if (error != -1 && atmark == 1) {
377 n = read(src, rbuf, 1);
378 if (n == -1)
379 goto bad;
380 send(dst, rbuf, n, MSG_OOB);
381 #if 0
382 n = read(src, rbuf, sizeof(rbuf));
383 if (n == -1)
384 goto bad;
385 write(dst, rbuf, n);
386 return n;
387 #endif
388 }
389
390 n = read(src, rbuf, sizeof(rbuf));
391 if (n <= 0)
392 return n;
393 rbuf[n] = '\0';
394
395 /*
396 * parse argument
397 */
398 p = rbuf;
399 for (i = 0; i < 3; i++) {
400 if (!isdigit((unsigned char)*p)) {
401 /* invalid reply */
402 write(dst, rbuf, n);
403 return n;
404 }
405 p++;
406 }
407 if (!isspace((unsigned char)*p)) {
408 /* invalid reply */
409 write(dst, rbuf, n);
410 return n;
411 }
412 code = atoi(rbuf);
413 param = p;
414 /* param points to first non-command token, if any */
415 while (*param && isspace((unsigned char)*param))
416 param++;
417 if (!*param)
418 param = NULL;
419
420 switch (state) {
421 case NONE:
422 if (!passivemode && rbuf[0] == '1') {
423 if (ftp_activeconn() < 0) {
424 n = snprintf(rbuf, sizeof(rbuf),
425 "425 Cannot open data connetion\r\n");
426 if (n < 0 || n >= sizeof(rbuf))
427 n = 0;
428 }
429 }
430 if (n)
431 write(dst, rbuf, n);
432 return n;
433 case LPRT:
434 case EPRT:
435 /* expecting "200 PORT command successful." */
436 if (code == 200) {
437 p = strstr(rbuf, "PORT");
438 if (p) {
439 p[0] = (state == LPRT) ? 'L' : 'E';
440 p[1] = 'P';
441 }
442 } else {
443 (void)close(wport4);
444 wport4 = -1;
445 }
446 write(dst, rbuf, n);
447 return n;
448 case LPSV:
449 case EPSV:
450 /*
451 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
452 * (in some cases result comes without paren)
453 */
454 if (code != 227) {
455 passivefail0:
456 (void)close(wport6);
457 wport6 = -1;
458 write(dst, rbuf, n);
459 return n;
460 }
461
462 {
463 unsigned int ho[4], po[2];
464 struct sockaddr_in *sin;
465 struct sockaddr_in6 *sin6;
466 u_short port;
467
468 /*
469 * PASV result -> LPSV/EPSV result
470 */
471 p = param;
472 while (*p && *p != '(' && !isdigit((unsigned char)*p)) /*)*/
473 p++;
474 if (!*p)
475 goto passivefail0; /*XXX*/
476 if (*p == '(') /*)*/
477 p++;
478 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
479 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
480 if (n != 6)
481 goto passivefail0; /*XXX*/
482
483 /* keep PORT parameter */
484 memset(&data4, 0, sizeof(data4));
485 sin = (struct sockaddr_in *)&data4;
486 sin->sin_len = sizeof(*sin);
487 sin->sin_family = AF_INET;
488 sin->sin_addr.s_addr = 0;
489 for (n = 0; n < 4; n++) {
490 sin->sin_addr.s_addr |=
491 htonl((ho[n] & 0xff) << ((3 - n) * 8));
492 }
493 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
494
495 /* get ready for passive data connection */
496 memset(&data6, 0, sizeof(data6));
497 sin6 = (struct sockaddr_in6 *)&data6;
498 sin6->sin6_len = sizeof(*sin6);
499 sin6->sin6_family = AF_INET6;
500 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
501 if (wport6 == -1) {
502 passivefail:
503 n = snprintf(sbuf, sizeof(sbuf),
504 "500 could not translate from PASV\r\n");
505 if (n < 0 || n >= sizeof(sbuf))
506 n = 0;
507 if (n)
508 write(src, sbuf, n);
509 return n;
510 }
511 #ifdef IPV6_FAITH
512 {
513 int on = 1;
514 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
515 &on, sizeof(on));
516 if (error == -1)
517 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
518 }
519 #endif
520 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
521 if (error == -1) {
522 (void)close(wport6);
523 wport6 = -1;
524 goto passivefail;
525 }
526 error = listen(wport6, 1);
527 if (error == -1) {
528 (void)close(wport6);
529 wport6 = -1;
530 goto passivefail;
531 }
532
533 /* transmit LPSV or EPSV */
534 /*
535 * addr from dst, port from wport6
536 */
537 len = sizeof(data6);
538 error = getsockname(wport6, (struct sockaddr *)&data6, &len);
539 if (error == -1) {
540 (void)close(wport6);
541 wport6 = -1;
542 goto passivefail;
543 }
544 sin6 = (struct sockaddr_in6 *)&data6;
545 port = sin6->sin6_port;
546
547 len = sizeof(data6);
548 error = getsockname(dst, (struct sockaddr *)&data6, &len);
549 if (error == -1) {
550 (void)close(wport6);
551 wport6 = -1;
552 goto passivefail;
553 }
554 sin6 = (struct sockaddr_in6 *)&data6;
555 sin6->sin6_port = port;
556
557 if (state == LPSV) {
558 a = (char *)&sin6->sin6_addr;
559 p = (char *)&sin6->sin6_port;
560 n = snprintf(sbuf, sizeof(sbuf),
561 "228 Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\r\n",
562 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
563 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
564 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
565 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
566 2, UC(p[0]), UC(p[1]));
567 if (n < 0 || n >= sizeof(sbuf))
568 n = 0;
569 if (n)
570 write(dst, sbuf, n);
571 passivemode = 1;
572 return n;
573 } else {
574 n = snprintf(sbuf, sizeof(sbuf),
575 "229 Entering Extended Passive Mode (|||%d|)\r\n",
576 ntohs(sin6->sin6_port));
577 if (n < 0 || n >= sizeof(sbuf))
578 n = 0;
579 if (n)
580 write(dst, sbuf, n);
581 passivemode = 1;
582 return n;
583 }
584 }
585 }
586
587 bad:
588 exit_failure("%s", strerror(errno));
589 /*NOTREACHED*/
590 return 0; /* to make gcc happy */
591 }
592
593 static int
594 ftp_copycommand(int src, int dst, enum state *state)
595 {
596 int error, atmark, n;
597 socklen_t len;
598 unsigned int af, hal, ho[16], pal, po[2];
599 char *a, *p, *q;
600 char cmd[5], *param;
601 struct sockaddr_in *sin;
602 struct sockaddr_in6 *sin6;
603 enum state nstate;
604 char ch;
605 int i;
606
607 /* OOB data handling */
608 error = ioctl(src, SIOCATMARK, &atmark);
609 if (error != -1 && atmark == 1) {
610 n = read(src, rbuf, 1);
611 if (n == -1)
612 goto bad;
613 send(dst, rbuf, n, MSG_OOB);
614 #if 0
615 n = read(src, rbuf, sizeof(rbuf));
616 if (n == -1)
617 goto bad;
618 write(dst, rbuf, n);
619 return n;
620 #endif
621 }
622
623 n = read(src, rbuf, sizeof(rbuf));
624 if (n <= 0)
625 return n;
626 rbuf[n] = '\0';
627
628 if (n < 4) {
629 write(dst, rbuf, n);
630 return n;
631 }
632
633 /*
634 * parse argument
635 */
636 p = rbuf;
637 q = cmd;
638 for (i = 0; i < 4; i++) {
639 if (!isalpha((unsigned char)*p)) {
640 /* invalid command */
641 write(dst, rbuf, n);
642 return n;
643 }
644 *q++ = islower((unsigned char)*p) ? toupper((unsigned char)*p) : *p;
645 p++;
646 }
647 if (!isspace((unsigned char)*p)) {
648 /* invalid command */
649 write(dst, rbuf, n);
650 return n;
651 }
652 *q = '\0';
653 param = p;
654 /* param points to first non-command token, if any */
655 while (*param && isspace((unsigned char)*param))
656 param++;
657 if (!*param)
658 param = NULL;
659
660 *state = NONE;
661
662 if (strcmp(cmd, "LPRT") == 0 && param) {
663 /*
664 * LPRT -> PORT
665 */
666 nstate = LPRT;
667
668 (void)close(wport4);
669 (void)close(wport6);
670 (void)close(port4);
671 (void)close(port6);
672 wport4 = wport6 = port4 = port6 = -1;
673
674 if (epsvall) {
675 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
676 cmd);
677 if (n < 0 || n >= sizeof(sbuf))
678 n = 0;
679 if (n)
680 write(src, sbuf, n);
681 return n;
682 }
683
684 n = sscanf(param,
685 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
686 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
687 &ho[4], &ho[5], &ho[6], &ho[7],
688 &ho[8], &ho[9], &ho[10], &ho[11],
689 &ho[12], &ho[13], &ho[14], &ho[15],
690 &pal, &po[0], &po[1]);
691 if (n != 21 || af != 6 || hal != 16|| pal != 2) {
692 n = snprintf(sbuf, sizeof(sbuf),
693 "501 illegal parameter to LPRT\r\n");
694 if (n < 0 || n >= sizeof(sbuf))
695 n = 0;
696 if (n)
697 write(src, sbuf, n);
698 return n;
699 }
700
701 /* keep LPRT parameter */
702 memset(&data6, 0, sizeof(data6));
703 sin6 = (struct sockaddr_in6 *)&data6;
704 sin6->sin6_len = sizeof(*sin6);
705 sin6->sin6_family = AF_INET6;
706 for (n = 0; n < 16; n++)
707 sin6->sin6_addr.s6_addr[n] = ho[n];
708 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
709
710 sendport:
711 /* get ready for active data connection */
712 len = sizeof(data4);
713 error = getsockname(dst, (struct sockaddr *)&data4, &len);
714 if (error == -1) {
715 lprtfail:
716 n = snprintf(sbuf, sizeof(sbuf),
717 "500 could not translate to PORT\r\n");
718 if (n < 0 || n >= sizeof(sbuf))
719 n = 0;
720 if (n)
721 write(src, sbuf, n);
722 return n;
723 }
724 if (((struct sockaddr *)&data4)->sa_family != AF_INET)
725 goto lprtfail;
726 sin = (struct sockaddr_in *)&data4;
727 sin->sin_port = 0;
728 wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
729 if (wport4 == -1)
730 goto lprtfail;
731 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
732 if (error == -1) {
733 (void)close(wport4);
734 wport4 = -1;
735 goto lprtfail;
736 }
737 error = listen(wport4, 1);
738 if (error == -1) {
739 (void)close(wport4);
740 wport4 = -1;
741 goto lprtfail;
742 }
743
744 /* transmit PORT */
745 len = sizeof(data4);
746 error = getsockname(wport4, (struct sockaddr *)&data4, &len);
747 if (error == -1) {
748 (void)close(wport4);
749 wport4 = -1;
750 goto lprtfail;
751 }
752 if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
753 (void)close(wport4);
754 wport4 = -1;
755 goto lprtfail;
756 }
757 sin = (struct sockaddr_in *)&data4;
758 a = (char *)&sin->sin_addr;
759 p = (char *)&sin->sin_port;
760 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
761 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
762 UC(p[0]), UC(p[1]));
763 if (n < 0 || n >= sizeof(sbuf))
764 n = 0;
765 if (n)
766 write(dst, sbuf, n);
767 *state = nstate;
768 passivemode = 0;
769 return n;
770 } else if (strcmp(cmd, "EPRT") == 0 && param) {
771 /*
772 * EPRT -> PORT
773 */
774 char *afp, *hostp, *portp;
775 struct addrinfo hints, *res;
776
777 nstate = EPRT;
778
779 (void)close(wport4);
780 (void)close(wport6);
781 (void)close(port4);
782 (void)close(port6);
783 wport4 = wport6 = port4 = port6 = -1;
784
785 if (epsvall) {
786 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
787 cmd);
788 if (n < 0 || n >= sizeof(sbuf))
789 n = 0;
790 if (n)
791 write(src, sbuf, n);
792 return n;
793 }
794
795 p = param;
796 ch = *p++; /* boundary character */
797 afp = p;
798 while (*p && *p != ch)
799 p++;
800 if (!*p) {
801 eprtparamfail:
802 n = snprintf(sbuf, sizeof(sbuf),
803 "501 illegal parameter to EPRT\r\n");
804 if (n < 0 || n >= sizeof(sbuf))
805 n = 0;
806 if (n)
807 write(src, sbuf, n);
808 return n;
809 }
810 *p++ = '\0';
811 hostp = p;
812 while (*p && *p != ch)
813 p++;
814 if (!*p)
815 goto eprtparamfail;
816 *p++ = '\0';
817 portp = p;
818 while (*p && *p != ch)
819 p++;
820 if (!*p)
821 goto eprtparamfail;
822 *p++ = '\0';
823
824 n = sscanf(afp, "%d", &af);
825 if (n != 1 || af != 2) {
826 n = snprintf(sbuf, sizeof(sbuf),
827 "501 unsupported address family to EPRT\r\n");
828 if (n < 0 || n >= sizeof(sbuf))
829 n = 0;
830 if (n)
831 write(src, sbuf, n);
832 return n;
833 }
834 memset(&hints, 0, sizeof(hints));
835 hints.ai_family = AF_UNSPEC;
836 hints.ai_socktype = SOCK_STREAM;
837 hints.ai_protocol = IPPROTO_TCP;
838 error = getaddrinfo(hostp, portp, &hints, &res);
839 if (error) {
840 n = snprintf(sbuf, sizeof(sbuf),
841 "501 EPRT: %s\r\n", gai_strerror(error));
842 if (n < 0 || n >= sizeof(sbuf))
843 n = 0;
844 if (n)
845 write(src, sbuf, n);
846 return n;
847 }
848 if (res->ai_next) {
849 n = snprintf(sbuf, sizeof(sbuf),
850 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
851 if (n < 0 || n >= sizeof(sbuf))
852 n = 0;
853 if (n)
854 write(src, sbuf, n);
855 freeaddrinfo(res);
856 return n;
857 }
858
859 memcpy(&data6, res->ai_addr, res->ai_addrlen);
860
861 freeaddrinfo(res);
862 goto sendport;
863 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
864 /*
865 * LPSV -> PASV
866 */
867 nstate = LPSV;
868
869 (void)close(wport4);
870 (void)close(wport6);
871 (void)close(port4);
872 (void)close(port6);
873 wport4 = wport6 = port4 = port6 = -1;
874
875 if (epsvall) {
876 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
877 cmd);
878 if (n < 0 || n >= sizeof(sbuf))
879 n = 0;
880 if (n)
881 write(src, sbuf, n);
882 return n;
883 }
884
885 /* transmit PASV */
886 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
887 if (n < 0 || n >= sizeof(sbuf))
888 n = 0;
889 if (n)
890 write(dst, sbuf, n);
891 *state = LPSV;
892 passivemode = 0; /* to be set to 1 later */
893 return n;
894 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
895 /*
896 * EPSV -> PASV
897 */
898 (void)close(wport4);
899 (void)close(wport6);
900 (void)close(port4);
901 (void)close(port6);
902 wport4 = wport6 = port4 = port6 = -1;
903
904 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
905 if (n < 0 || n >= sizeof(sbuf))
906 n = 0;
907 if (n)
908 write(dst, sbuf, n);
909 *state = EPSV;
910 passivemode = 0; /* to be set to 1 later */
911 return n;
912 } else if (strcmp(cmd, "EPSV") == 0 && param
913 && strncasecmp(param, "ALL", 3) == 0 && isspace((unsigned char)param[3])) {
914 /*
915 * EPSV ALL
916 */
917 epsvall = 1;
918 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
919 if (n < 0 || n >= sizeof(sbuf))
920 n = 0;
921 if (n)
922 write(src, sbuf, n);
923 return n;
924 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
925 /*
926 * reject PORT/PASV
927 */
928 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
929 if (n < 0 || n >= sizeof(sbuf))
930 n = 0;
931 if (n)
932 write(src, sbuf, n);
933 return n;
934 } else if (passivemode
935 && (strcmp(cmd, "STOR") == 0
936 || strcmp(cmd, "STOU") == 0
937 || strcmp(cmd, "RETR") == 0
938 || strcmp(cmd, "LIST") == 0
939 || strcmp(cmd, "NLST") == 0
940 || strcmp(cmd, "APPE") == 0)) {
941 /*
942 * commands with data transfer. need to care about passive
943 * mode data connection.
944 */
945
946 if (ftp_passiveconn() < 0) {
947 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
948 if (n < 0 || n >= sizeof(sbuf))
949 n = 0;
950 if (n)
951 write(src, sbuf, n);
952 } else {
953 /* simply relay the command */
954 write(dst, rbuf, n);
955 }
956
957 *state = NONE;
958 return n;
959 } else {
960 /* simply relay it */
961 *state = NONE;
962 write(dst, rbuf, n);
963 return n;
964 }
965
966 bad:
967 exit_failure("%s", strerror(errno));
968 /*NOTREACHED*/
969 return 0; /* to make gcc happy */
970 }
971