ftp.c revision 1.8 1 /* $NetBSD: ftp.c,v 1.8 2002/04/24 12:14:42 itojun Exp $ */
2 /* $KAME: ftp.c,v 1.14 2002/04/24 08:17:23 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 <errno.h>
45 #include <ctype.h>
46
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <netdb.h>
50
51 #include "faithd.h"
52
53 static char rbuf[MSS];
54 static char sbuf[MSS];
55 static int passivemode = 0;
56 static int wport4 = -1; /* listen() to active */
57 static int wport6 = -1; /* listen() to passive */
58 static int port4 = -1; /* active: inbound passive: outbound */
59 static int port6 = -1; /* active: outbound passive: inbound */
60 static struct sockaddr_storage data4; /* server data address */
61 static struct sockaddr_storage data6; /* client data address */
62 static int epsvall = 0;
63
64 #ifdef FAITH4
65 enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV };
66 #else
67 enum state { NONE, LPRT, EPRT, LPSV, EPSV };
68 #endif
69
70 static int ftp_activeconn __P((void));
71 static int ftp_passiveconn __P((void));
72 static int ftp_copy __P((int, int));
73 static int ftp_copyresult __P((int, int, enum state));
74 static int ftp_copycommand __P((int, int, enum state *));
75
76 void
77 ftp_relay(int ctl6, int ctl4)
78 {
79 fd_set readfds;
80 int error;
81 enum state state = NONE;
82 struct timeval tv;
83
84 syslog(LOG_INFO, "starting ftp control connection");
85
86 for (;;) {
87 int maxfd = 0;
88
89 FD_ZERO(&readfds);
90 FD_SET(ctl4, &readfds);
91 FD_SET(ctl6, &readfds);
92 if (0 <= port4) {
93 FD_SET(port4, &readfds);
94 if (port4 > maxfd)
95 maxfd = port4;
96 }
97 if (0 <= port6) {
98 FD_SET(port6, &readfds);
99 if (port6 > maxfd)
100 maxfd = port6;
101 }
102 #if 0
103 if (0 <= wport4) {
104 FD_SET(wport4, &readfds);
105 if (wport4 > maxfd)
106 maxfd = wport4;
107 }
108 if (0 <= wport6) {
109 FD_SET(wport6, &readfds);
110 if (wport6 > maxfd)
111 maxfd = wport6;
112 }
113 #endif
114 tv.tv_sec = FAITH_TIMEOUT;
115 tv.tv_usec = 0;
116
117 error = select(maxfd + 1, &readfds, NULL, NULL, &tv);
118 if (error == -1)
119 exit_failure("select: %s", strerror(errno));
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 (FD_ISSET(ctl6, &readfds)) {
130 /*
131 * copy control connection from the client.
132 * command translation is necessary.
133 */
134 error = ftp_copycommand(ctl6, ctl4, &state);
135
136 switch (error) {
137 case -1:
138 goto bad;
139 case 0:
140 close(ctl4);
141 close(ctl6);
142 exit_success("terminating ftp control connection");
143 /*NOTREACHED*/
144 default:
145 break;
146 }
147 }
148 if (FD_ISSET(ctl4, &readfds)) {
149 /*
150 * copy control connection from the server
151 * translation of result code is necessary.
152 */
153 error = ftp_copyresult(ctl4, ctl6, state);
154
155 switch (error) {
156 case -1:
157 goto bad;
158 case 0:
159 close(ctl4);
160 close(ctl6);
161 exit_success("terminating ftp control connection");
162 /*NOTREACHED*/
163 default:
164 break;
165 }
166 }
167 if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) {
168 /*
169 * copy data connection.
170 * no special treatment necessary.
171 */
172 if (FD_ISSET(port4, &readfds))
173 error = ftp_copy(port4, port6);
174 switch (error) {
175 case -1:
176 goto bad;
177 case 0:
178 close(port4);
179 close(port6);
180 port4 = port6 = -1;
181 syslog(LOG_INFO, "terminating data connection");
182 break;
183 default:
184 break;
185 }
186 }
187 if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) {
188 /*
189 * copy data connection.
190 * no special treatment necessary.
191 */
192 if (FD_ISSET(port6, &readfds))
193 error = ftp_copy(port6, port4);
194 switch (error) {
195 case -1:
196 goto bad;
197 case 0:
198 close(port4);
199 close(port6);
200 port4 = port6 = -1;
201 syslog(LOG_INFO, "terminating data connection");
202 break;
203 default:
204 break;
205 }
206 }
207 #if 0
208 if (wport4 && FD_ISSET(wport4, &readfds)) {
209 /*
210 * establish active data connection from the server.
211 */
212 ftp_activeconn();
213 }
214 if (wport6 && FD_ISSET(wport6, &readfds)) {
215 /*
216 * establish passive data connection from the client.
217 */
218 ftp_passiveconn();
219 }
220 #endif
221 }
222
223 bad:
224 exit_failure("%s", strerror(errno));
225 }
226
227 static int
228 ftp_activeconn()
229 {
230 int n;
231 int error;
232 fd_set set;
233 struct timeval timeout;
234 struct sockaddr *sa;
235
236 /* get active connection from server */
237 FD_ZERO(&set);
238 FD_SET(wport4, &set);
239 timeout.tv_sec = 120;
240 timeout.tv_usec = -1;
241 n = sizeof(data4);
242 if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0
243 || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) {
244 close(wport4);
245 wport4 = -1;
246 syslog(LOG_INFO, "active mode data connection failed");
247 return -1;
248 }
249
250 /* ask active connection to client */
251 sa = (struct sockaddr *)&data6;
252 port6 = socket(sa->sa_family, SOCK_STREAM, 0);
253 if (port6 == -1) {
254 close(port4);
255 close(wport4);
256 port4 = wport4 = -1;
257 syslog(LOG_INFO, "active mode data connection failed");
258 return -1;
259 }
260 error = connect(port6, sa, sa->sa_len);
261 if (error < 0) {
262 close(port6);
263 close(port4);
264 close(wport4);
265 port6 = port4 = wport4 = -1;
266 syslog(LOG_INFO, "active mode data connection failed");
267 return -1;
268 }
269
270 syslog(LOG_INFO, "active mode data connection established");
271 return 0;
272 }
273
274 static int
275 ftp_passiveconn()
276 {
277 int n;
278 int error;
279 fd_set set;
280 struct timeval timeout;
281 struct sockaddr *sa;
282
283 /* get passive connection from client */
284 FD_ZERO(&set);
285 FD_SET(wport6, &set);
286 timeout.tv_sec = 120;
287 timeout.tv_usec = 0;
288 n = sizeof(data6);
289 if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0
290 || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) {
291 close(wport6);
292 wport6 = -1;
293 syslog(LOG_INFO, "passive mode data connection failed");
294 return -1;
295 }
296
297 /* ask passive connection to server */
298 sa = (struct sockaddr *)&data4;
299 port4 = socket(sa->sa_family, SOCK_STREAM, 0);
300 if (port4 == -1) {
301 close(wport6);
302 close(port6);
303 wport6 = port6 = -1;
304 syslog(LOG_INFO, "passive mode data connection failed");
305 return -1;
306 }
307 error = connect(port4, sa, sa->sa_len);
308 if (error < 0) {
309 close(wport6);
310 close(port4);
311 close(port6);
312 wport6 = port4 = port6 = -1;
313 syslog(LOG_INFO, "passive mode data connection failed");
314 return -1;
315 }
316
317 syslog(LOG_INFO, "passive mode data connection established");
318 return 0;
319 }
320
321 static int
322 ftp_copy(int src, int dst)
323 {
324 int error, atmark;
325 int n;
326
327 /* OOB data handling */
328 error = ioctl(src, SIOCATMARK, &atmark);
329 if (error != -1 && atmark == 1) {
330 n = read(src, rbuf, 1);
331 if (n == -1)
332 goto bad;
333 send(dst, rbuf, n, MSG_OOB);
334 #if 0
335 n = read(src, rbuf, sizeof(rbuf));
336 if (n == -1)
337 goto bad;
338 write(dst, rbuf, n);
339 return n;
340 #endif
341 }
342
343 n = read(src, rbuf, sizeof(rbuf));
344 switch (n) {
345 case -1:
346 case 0:
347 return n;
348 default:
349 write(dst, rbuf, n);
350 return n;
351 }
352
353 bad:
354 exit_failure("%s", strerror(errno));
355 /*NOTREACHED*/
356 return 0; /* to make gcc happy */
357 }
358
359 static int
360 ftp_copyresult(int src, int dst, enum state state)
361 {
362 int error, atmark;
363 int n;
364 char *param;
365 int code;
366 char *a, *p;
367 int i;
368
369 /* OOB data handling */
370 error = ioctl(src, SIOCATMARK, &atmark);
371 if (error != -1 && atmark == 1) {
372 n = read(src, rbuf, 1);
373 if (n == -1)
374 goto bad;
375 send(dst, rbuf, n, MSG_OOB);
376 #if 0
377 n = read(src, rbuf, sizeof(rbuf));
378 if (n == -1)
379 goto bad;
380 write(dst, rbuf, n);
381 return n;
382 #endif
383 }
384
385 n = read(src, rbuf, sizeof(rbuf));
386 if (n <= 0)
387 return n;
388 rbuf[n] = '\0';
389
390 /*
391 * parse argument
392 */
393 p = rbuf;
394 for (i = 0; i < 3; i++) {
395 if (!isdigit(*p)) {
396 /* invalid reply */
397 write(dst, rbuf, n);
398 return n;
399 }
400 p++;
401 }
402 if (!isspace(*p)) {
403 /* invalid reply */
404 write(dst, rbuf, n);
405 return n;
406 }
407 code = atoi(rbuf);
408 param = p;
409 /* param points to first non-command token, if any */
410 while (*param && isspace(*param))
411 param++;
412 if (!*param)
413 param = NULL;
414
415 switch (state) {
416 case NONE:
417 if (!passivemode && rbuf[0] == '1') {
418 if (ftp_activeconn() < 0) {
419 n = snprintf(rbuf, sizeof(rbuf),
420 "425 Cannot open data connetion\r\n");
421 if (n < 0 || n >= sizeof(rbuf))
422 n = 0;
423 }
424 }
425 if (n)
426 write(dst, rbuf, n);
427 return n;
428 case LPRT:
429 case EPRT:
430 /* expecting "200 PORT command successful." */
431 if (code == 200) {
432 p = strstr(rbuf, "PORT");
433 if (p) {
434 p[0] = (state == LPRT) ? 'L' : 'E';
435 p[1] = 'P';
436 }
437 } else {
438 close(wport4);
439 wport4 = -1;
440 }
441 write(dst, rbuf, n);
442 return n;
443 #ifdef FAITH4
444 case PORT:
445 /* expecting "200 EPRT command successful." */
446 if (code == 200) {
447 p = strstr(rbuf, "EPRT");
448 if (p) {
449 p[0] = 'P';
450 p[1] = 'O';
451 }
452 } else {
453 close(wport4);
454 wport4 = -1;
455 }
456 write(dst, rbuf, n);
457 return n;
458 #endif
459 case LPSV:
460 case EPSV:
461 /*
462 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
463 * (in some cases result comes without paren)
464 */
465 if (code != 227) {
466 passivefail0:
467 close(wport6);
468 wport6 = -1;
469 write(dst, rbuf, n);
470 return n;
471 }
472
473 {
474 unsigned int ho[4], po[2];
475 struct sockaddr_in *sin;
476 struct sockaddr_in6 *sin6;
477 u_short port;
478
479 /*
480 * PASV result -> LPSV/EPSV result
481 */
482 p = param;
483 while (*p && *p != '(' && !isdigit(*p)) /*)*/
484 p++;
485 if (!*p)
486 goto passivefail0; /*XXX*/
487 if (*p == '(') /*)*/
488 p++;
489 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
490 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
491 if (n != 6)
492 goto passivefail0; /*XXX*/
493
494 /* keep PORT parameter */
495 memset(&data4, 0, sizeof(data4));
496 sin = (struct sockaddr_in *)&data4;
497 sin->sin_len = sizeof(*sin);
498 sin->sin_family = AF_INET;
499 sin->sin_addr.s_addr = 0;
500 for (n = 0; n < 4; n++) {
501 sin->sin_addr.s_addr |=
502 htonl((ho[n] & 0xff) << ((3 - n) * 8));
503 }
504 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
505
506 /* get ready for passive data connection */
507 memset(&data6, 0, sizeof(data6));
508 sin6 = (struct sockaddr_in6 *)&data6;
509 sin6->sin6_len = sizeof(*sin6);
510 sin6->sin6_family = AF_INET6;
511 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
512 if (wport6 == -1) {
513 passivefail:
514 n = snprintf(sbuf, sizeof(sbuf),
515 "500 could not translate from PASV\r\n");
516 if (n < 0 || n >= sizeof(sbuf))
517 if (n)
518 write(src, sbuf, n);
519 return n;
520 }
521 #ifdef IPV6_FAITH
522 {
523 int on = 1;
524 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
525 &on, sizeof(on));
526 if (error == -1)
527 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
528 }
529 #endif
530 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
531 if (error == -1) {
532 close(wport6);
533 wport6 = -1;
534 goto passivefail;
535 }
536 error = listen(wport6, 1);
537 if (error == -1) {
538 close(wport6);
539 wport6 = -1;
540 goto passivefail;
541 }
542
543 /* transmit LPSV or EPSV */
544 /*
545 * addr from dst, port from wport6
546 */
547 n = sizeof(data6);
548 error = getsockname(wport6, (struct sockaddr *)&data6, &n);
549 if (error == -1) {
550 close(wport6);
551 wport6 = -1;
552 goto passivefail;
553 }
554 sin6 = (struct sockaddr_in6 *)&data6;
555 port = sin6->sin6_port;
556
557 n = sizeof(data6);
558 error = getsockname(dst, (struct sockaddr *)&data6, &n);
559 if (error == -1) {
560 close(wport6);
561 wport6 = -1;
562 goto passivefail;
563 }
564 sin6 = (struct sockaddr_in6 *)&data6;
565 sin6->sin6_port = port;
566
567 if (state == LPSV) {
568 a = (char *)&sin6->sin6_addr;
569 p = (char *)&sin6->sin6_port;
570 n = snprintf(sbuf, sizeof(sbuf),
571 "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",
572 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
573 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
574 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
575 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
576 2, UC(p[0]), UC(p[1]));
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 } else {
584 n = snprintf(sbuf, sizeof(sbuf),
585 "229 Entering Extended Passive Mode (|||%d|)\r\n",
586 ntohs(sin6->sin6_port));
587 if (n < 0 || n >= sizeof(sbuf))
588 n = 0;
589 if (n)
590 write(dst, sbuf, n);
591 passivemode = 1;
592 return n;
593 }
594 }
595 #ifdef FAITH4
596 case PASV:
597 /* expecting "229 Entering Extended Passive Mode (|||x|)" */
598 if (code != 229) {
599 passivefail1:
600 close(wport6);
601 wport6 = -1;
602 write(dst, rbuf, n);
603 return n;
604 }
605
606 {
607 u_short port;
608 struct sockaddr_in *sin;
609 struct sockaddr_in6 *sin6;
610
611 /*
612 * EPSV result -> PORT result
613 */
614 p = param;
615 while (*p && *p != '(') /*)*/
616 p++;
617 if (!*p)
618 goto passivefail1; /*XXX*/
619 p++;
620 n = sscanf(p, "|||%hu|", &port);
621 if (n != 1)
622 goto passivefail1; /*XXX*/
623
624 /* keep EPRT parameter */
625 n = sizeof(data4);
626 error = getpeername(src, (struct sockaddr *)&data4, &n);
627 if (error == -1)
628 goto passivefail1; /*XXX*/
629 sin6 = (struct sockaddr_in6 *)&data4;
630 sin6->sin6_port = htons(port);
631
632 /* get ready for passive data connection */
633 memset(&data6, 0, sizeof(data6));
634 sin = (struct sockaddr_in *)&data6;
635 sin->sin_len = sizeof(*sin);
636 sin->sin_family = AF_INET;
637 wport6 = socket(sin->sin_family, SOCK_STREAM, 0);
638 if (wport6 == -1) {
639 passivefail2:
640 n = snprintf(sbuf, sizeof(sbuf),
641 "500 could not translate from EPSV\r\n");
642 if (n < 0 || n >= sizeof(sbuf))
643 n = 0;
644 if (n)
645 write(src, sbuf, n);
646 return n;
647 }
648 #ifdef IP_FAITH
649 {
650 int on = 1;
651 error = setsockopt(wport6, IPPROTO_IP, IP_FAITH,
652 &on, sizeof(on));
653 if (error == -1)
654 exit_error("setsockopt(IP_FAITH): %s", strerror(errno));
655 }
656 #endif
657 error = bind(wport6, (struct sockaddr *)sin, sin->sin_len);
658 if (error == -1) {
659 close(wport6);
660 wport6 = -1;
661 goto passivefail2;
662 }
663 error = listen(wport6, 1);
664 if (error == -1) {
665 close(wport6);
666 wport6 = -1;
667 goto passivefail2;
668 }
669
670 /* transmit PORT */
671 /*
672 * addr from dst, port from wport6
673 */
674 n = sizeof(data6);
675 error = getsockname(wport6, (struct sockaddr *)&data6, &n);
676 if (error == -1) {
677 close(wport6);
678 wport6 = -1;
679 goto passivefail2;
680 }
681 sin = (struct sockaddr_in *)&data6;
682 port = sin->sin_port;
683
684 n = sizeof(data6);
685 error = getsockname(dst, (struct sockaddr *)&data6, &n);
686 if (error == -1) {
687 close(wport6);
688 wport6 = -1;
689 goto passivefail2;
690 }
691 sin = (struct sockaddr_in *)&data6;
692 sin->sin_port = port;
693
694 {
695 char *a, *p;
696
697 a = (char *)&sin->sin_addr;
698 p = (char *)&sin->sin_port;
699 n = snprintf(sbuf, sizeof(sbuf),
700 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
701 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
702 UC(p[0]), UC(p[1]));
703 if (n < 0 || n >= sizeof(sbuf))
704 n = 0;
705 if (n)
706 write(dst, sbuf, n);
707 passivemode = 1;
708 return n;
709 }
710 }
711 #endif /* FAITH4 */
712 }
713
714 bad:
715 exit_failure("%s", strerror(errno));
716 /*NOTREACHED*/
717 return 0; /* to make gcc happy */
718 }
719
720 static int
721 ftp_copycommand(int src, int dst, enum state *state)
722 {
723 int error, atmark;
724 int n;
725 unsigned int af, hal, ho[16], pal, po[2];
726 char *a, *p, *q;
727 char cmd[5], *param;
728 struct sockaddr_in *sin;
729 struct sockaddr_in6 *sin6;
730 enum state nstate;
731 char ch;
732 int i;
733
734 /* OOB data handling */
735 error = ioctl(src, SIOCATMARK, &atmark);
736 if (error != -1 && atmark == 1) {
737 n = read(src, rbuf, 1);
738 if (n == -1)
739 goto bad;
740 send(dst, rbuf, n, MSG_OOB);
741 #if 0
742 n = read(src, rbuf, sizeof(rbuf));
743 if (n == -1)
744 goto bad;
745 write(dst, rbuf, n);
746 return n;
747 #endif
748 }
749
750 n = read(src, rbuf, sizeof(rbuf));
751 if (n <= 0)
752 return n;
753 rbuf[n] = '\0';
754
755 if (n < 4) {
756 write(dst, rbuf, n);
757 return n;
758 }
759
760 /*
761 * parse argument
762 */
763 p = rbuf;
764 q = cmd;
765 for (i = 0; i < 4; i++) {
766 if (!isalpha(*p)) {
767 /* invalid command */
768 write(dst, rbuf, n);
769 return n;
770 }
771 *q++ = islower(*p) ? toupper(*p) : *p;
772 p++;
773 }
774 if (!isspace(*p)) {
775 /* invalid command */
776 write(dst, rbuf, n);
777 return n;
778 }
779 *q = '\0';
780 param = p;
781 /* param points to first non-command token, if any */
782 while (*param && isspace(*param))
783 param++;
784 if (!*param)
785 param = NULL;
786
787 *state = NONE;
788
789 if (strcmp(cmd, "LPRT") == 0 && param) {
790 /*
791 * LPRT -> PORT
792 */
793 nstate = LPRT;
794
795 close(wport4);
796 close(wport6);
797 close(port4);
798 close(port6);
799 wport4 = wport6 = port4 = port6 = -1;
800
801 if (epsvall) {
802 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
803 cmd);
804 if (n < 0 || n >= sizeof(sbuf))
805 n = 0;
806 if (n)
807 write(src, sbuf, n);
808 return n;
809 }
810
811 n = sscanf(param,
812 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
813 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
814 &ho[4], &ho[5], &ho[6], &ho[7],
815 &ho[8], &ho[9], &ho[10], &ho[11],
816 &ho[12], &ho[13], &ho[14], &ho[15],
817 &pal, &po[0], &po[1]);
818 if (n != 21 || af != 6 || hal != 16|| pal != 2) {
819 n = snprintf(sbuf, sizeof(sbuf),
820 "501 illegal parameter to LPRT\r\n");
821 if (n < 0 || n >= sizeof(sbuf))
822 n = 0;
823 if (n)
824 write(src, sbuf, n);
825 return n;
826 }
827
828 /* keep LPRT parameter */
829 memset(&data6, 0, sizeof(data6));
830 sin6 = (struct sockaddr_in6 *)&data6;
831 sin6->sin6_len = sizeof(*sin6);
832 sin6->sin6_family = AF_INET6;
833 for (n = 0; n < 16; n++)
834 sin6->sin6_addr.s6_addr[n] = ho[n];
835 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
836
837 sendport:
838 /* get ready for active data connection */
839 n = sizeof(data4);
840 error = getsockname(dst, (struct sockaddr *)&data4, &n);
841 if (error == -1) {
842 lprtfail:
843 n = snprintf(sbuf, sizeof(sbuf),
844 "500 could not translate to PORT\r\n");
845 if (n < 0 || n >= sizeof(sbuf))
846 n = 0;
847 if (n)
848 write(src, sbuf, n);
849 return n;
850 }
851 if (((struct sockaddr *)&data4)->sa_family != AF_INET)
852 goto lprtfail;
853 sin = (struct sockaddr_in *)&data4;
854 sin->sin_port = 0;
855 wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
856 if (wport4 == -1)
857 goto lprtfail;
858 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
859 if (error == -1) {
860 close(wport4);
861 wport4 = -1;
862 goto lprtfail;
863 }
864 error = listen(wport4, 1);
865 if (error == -1) {
866 close(wport4);
867 wport4 = -1;
868 goto lprtfail;
869 }
870
871 /* transmit PORT */
872 n = sizeof(data4);
873 error = getsockname(wport4, (struct sockaddr *)&data4, &n);
874 if (error == -1) {
875 close(wport4);
876 wport4 = -1;
877 goto lprtfail;
878 }
879 if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
880 close(wport4);
881 wport4 = -1;
882 goto lprtfail;
883 }
884 sin = (struct sockaddr_in *)&data4;
885 a = (char *)&sin->sin_addr;
886 p = (char *)&sin->sin_port;
887 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
888 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
889 UC(p[0]), UC(p[1]));
890 if (n < 0 || n >= sizeof(sbuf))
891 n = 0;
892 if (n)
893 write(dst, sbuf, n);
894 *state = nstate;
895 passivemode = 0;
896 return n;
897 } else if (strcmp(cmd, "EPRT") == 0 && param) {
898 /*
899 * EPRT -> PORT
900 */
901 char *afp, *hostp, *portp;
902 struct addrinfo hints, *res;
903
904 nstate = EPRT;
905
906 close(wport4);
907 close(wport6);
908 close(port4);
909 close(port6);
910 wport4 = wport6 = port4 = port6 = -1;
911
912 if (epsvall) {
913 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
914 cmd);
915 if (n < 0 || n >= sizeof(sbuf))
916 n = 0;
917 if (n)
918 write(src, sbuf, n);
919 return n;
920 }
921
922 p = param;
923 ch = *p++; /* boundary character */
924 afp = p;
925 while (*p && *p != ch)
926 p++;
927 if (!*p) {
928 eprtparamfail:
929 n = snprintf(sbuf, sizeof(sbuf),
930 "501 illegal parameter to EPRT\r\n");
931 if (n < 0 || n >= sizeof(sbuf))
932 n = 0;
933 if (n)
934 write(src, sbuf, n);
935 return n;
936 }
937 *p++ = '\0';
938 hostp = p;
939 while (*p && *p != ch)
940 p++;
941 if (!*p)
942 goto eprtparamfail;
943 *p++ = '\0';
944 portp = p;
945 while (*p && *p != ch)
946 p++;
947 if (!*p)
948 goto eprtparamfail;
949 *p++ = '\0';
950
951 n = sscanf(afp, "%d", &af);
952 if (n != 1 || af != 2) {
953 n = snprintf(sbuf, sizeof(sbuf),
954 "501 unsupported address family to EPRT\r\n");
955 if (n < 0 || n >= sizeof(sbuf))
956 n = 0;
957 if (n)
958 write(src, sbuf, n);
959 return n;
960 }
961 memset(&hints, 0, sizeof(hints));
962 hints.ai_family = AF_UNSPEC;
963 hints.ai_socktype = SOCK_STREAM;
964 error = getaddrinfo(hostp, portp, &hints, &res);
965 if (error) {
966 n = snprintf(sbuf, sizeof(sbuf),
967 "501 EPRT: %s\r\n", gai_strerror(error));
968 if (n < 0 || n >= sizeof(sbuf))
969 n = 0;
970 if (n)
971 write(src, sbuf, n);
972 return n;
973 }
974 if (res->ai_next) {
975 n = snprintf(sbuf, sizeof(sbuf),
976 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
977 if (n < 0 || n >= sizeof(sbuf))
978 n = 0;
979 if (n)
980 write(src, sbuf, n);
981 return n;
982 }
983
984 memcpy(&data6, res->ai_addr, res->ai_addrlen);
985
986 goto sendport;
987 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
988 /*
989 * LPSV -> PASV
990 */
991 nstate = LPSV;
992
993 close(wport4);
994 close(wport6);
995 close(port4);
996 close(port6);
997 wport4 = wport6 = port4 = port6 = -1;
998
999 if (epsvall) {
1000 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
1001 cmd);
1002 if (n < 0 || n >= sizeof(sbuf))
1003 n = 0;
1004 if (n)
1005 write(src, sbuf, n);
1006 return n;
1007 }
1008
1009 /* transmit PASV */
1010 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
1011 if (n < 0 || n >= sizeof(sbuf))
1012 n = 0;
1013 if (n)
1014 write(dst, sbuf, n);
1015 *state = LPSV;
1016 passivemode = 0; /* to be set to 1 later */
1017 return n;
1018 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
1019 /*
1020 * EPSV -> PASV
1021 */
1022 close(wport4);
1023 close(wport6);
1024 close(port4);
1025 close(port6);
1026 wport4 = wport6 = port4 = port6 = -1;
1027
1028 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
1029 if (n < 0 || n >= sizeof(sbuf))
1030 n = 0;
1031 if (n)
1032 write(dst, sbuf, n);
1033 *state = EPSV;
1034 passivemode = 0; /* to be set to 1 later */
1035 return n;
1036 } else if (strcmp(cmd, "EPSV") == 0 && param
1037 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
1038 /*
1039 * EPSV ALL
1040 */
1041 epsvall = 1;
1042 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
1043 if (n < 0 || n >= sizeof(sbuf))
1044 n = 0;
1045 if (n)
1046 write(src, sbuf, n);
1047 return n;
1048 #ifdef FAITH4
1049 } else if (strcmp(cmd, "PORT") == 0 && param) {
1050 /*
1051 * PORT -> EPRT
1052 */
1053 char host[NI_MAXHOST], serv[NI_MAXSERV];
1054
1055 nstate = PORT;
1056
1057 close(wport4);
1058 close(wport6);
1059 close(port4);
1060 close(port6);
1061 wport4 = wport6 = port4 = port6 = -1;
1062
1063 p = param;
1064 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
1065 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
1066 if (n != 6) {
1067 n = snprintf(sbuf, sizeof(sbuf),
1068 "501 illegal parameter to PORT\r\n");
1069 if (n < 0 || n >= sizeof(sbuf))
1070 n = 0;
1071 if (n)
1072 write(src, sbuf, n);
1073 return n;
1074 }
1075
1076 memset(&data6, 0, sizeof(data6));
1077 sin = (struct sockaddr_in *)&data6;
1078 sin->sin_len = sizeof(*sin);
1079 sin->sin_family = AF_INET;
1080 sin->sin_addr.s_addr = htonl(
1081 ((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) |
1082 ((ho[2] & 0xff) << 8) | (ho[3] & 0xff));
1083 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
1084
1085 /* get ready for active data connection */
1086 n = sizeof(data4);
1087 error = getsockname(dst, (struct sockaddr *)&data4, &n);
1088 if (error == -1) {
1089 portfail:
1090 n = snprintf(sbuf, sizeof(sbuf),
1091 "500 could not translate to EPRT\r\n");
1092 if (n < 0 || n >= sizeof(sbuf))
1093 n = 0;
1094 if (n)
1095 write(src, sbuf, n);
1096 return n;
1097 }
1098 if (((struct sockaddr *)&data4)->sa_family != AF_INET6)
1099 goto portfail;
1100
1101 ((struct sockaddr_in6 *)&data4)->sin6_port = 0;
1102 sa = (struct sockaddr *)&data4;
1103 wport4 = socket(sa->sa_family, SOCK_STREAM, 0);
1104 if (wport4 == -1)
1105 goto portfail;
1106 error = bind(wport4, sa, sa->sa_len);
1107 if (error == -1) {
1108 close(wport4);
1109 wport4 = -1;
1110 goto portfail;
1111 }
1112 error = listen(wport4, 1);
1113 if (error == -1) {
1114 close(wport4);
1115 wport4 = -1;
1116 goto portfail;
1117 }
1118
1119 /* transmit EPRT */
1120 n = sizeof(data4);
1121 error = getsockname(wport4, (struct sockaddr *)&data4, &n);
1122 if (error == -1) {
1123 close(wport4);
1124 wport4 = -1;
1125 goto portfail;
1126 }
1127 af = 2;
1128 sa = (struct sockaddr *)&data4;
1129 if (getnameinfo(sa, sa->sa_len, host, sizeof(host),
1130 serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) {
1131 close(wport4);
1132 wport4 = -1;
1133 goto portfail;
1134 }
1135 n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv);
1136 if (n < 0 || n >= sizeof(sbuf))
1137 n = 0;
1138 if (n)
1139 write(dst, sbuf, n);
1140 *state = nstate;
1141 passivemode = 0;
1142 return n;
1143 } else if (strcmp(cmd, "PASV") == 0 && !param) {
1144 /*
1145 * PASV -> EPSV
1146 */
1147
1148 nstate = PASV;
1149
1150 close(wport4);
1151 close(wport6);
1152 close(port4);
1153 close(port6);
1154 wport4 = wport6 = port4 = port6 = -1;
1155
1156 /* transmit EPSV */
1157 n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n");
1158 if (n < 0 || n >= sizeof(sbuf))
1159 n = 0;
1160 if (n)
1161 write(dst, sbuf, n);
1162 *state = PASV;
1163 passivemode = 0; /* to be set to 1 later */
1164 return n;
1165 #else /* FAITH4 */
1166 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
1167 /*
1168 * reject PORT/PASV
1169 */
1170 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
1171 if (n < 0 || n >= sizeof(sbuf))
1172 n = 0;
1173 if (n)
1174 write(src, sbuf, n);
1175 return n;
1176 #endif /* FAITH4 */
1177 } else if (passivemode
1178 && (strcmp(cmd, "STOR") == 0
1179 || strcmp(cmd, "STOU") == 0
1180 || strcmp(cmd, "RETR") == 0
1181 || strcmp(cmd, "LIST") == 0
1182 || strcmp(cmd, "NLST") == 0
1183 || strcmp(cmd, "APPE") == 0)) {
1184 /*
1185 * commands with data transfer. need to care about passive
1186 * mode data connection.
1187 */
1188
1189 if (ftp_passiveconn() < 0) {
1190 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
1191 if (n < 0 || n >= sizeof(sbuf))
1192 n = 0;
1193 if (n)
1194 write(src, sbuf, n);
1195 } else {
1196 /* simply relay the command */
1197 write(dst, rbuf, n);
1198 }
1199
1200 *state = NONE;
1201 return n;
1202 } else {
1203 /* simply relay it */
1204 *state = NONE;
1205 write(dst, rbuf, n);
1206 return n;
1207 }
1208
1209 bad:
1210 exit_failure("%s", strerror(errno));
1211 /*NOTREACHED*/
1212 return 0; /* to make gcc happy */
1213 }
1214