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