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