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