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