1 /* $OpenBSD: ftp.c,v 1.14 2005/03/16 05:07:48 itojun Exp $ */
2 /* $KAME: ftp.c,v 1.20 2002/09/08 01:12:30 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(void);
68 static int ftp_passiveconn(void);
69 static int ftp_copy(int, int);
70 static int ftp_copyresult(int, int, enum state);
71 static int ftp_copycommand(int, int, enum state *);
72
73 void
ftp_relay(int ctl6,int ctl4)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 int maxfd = 0;
85
86 pfd[0].fd = ctl4;
87 pfd[0].events = POLLIN;
88 pfd[1].fd = ctl6;
89 pfd[1].events = POLLIN;
90
91 maxfd = (ctl6 > maxfd) ? ctl6 : maxfd;
92 if (0 <= port4) {
93 pfd[2].fd = port4;
94 pfd[2].events = POLLIN;
95 } else
96 pfd[2].fd = -1;
97
98 if (0 <= port6) {
99 pfd[3].fd = port6;
100 pfd[3].events = POLLIN;
101 } else
102 pfd[3].fd = -1;
103 #if 0
104 if (0 <= wport4) {
105 pfd[4].fd = wport4;
106 pfd[4].events = POLLIN;
107 } else
108 pfd[4].fd = -1;
109 if (0 <= wport6) {
110 pfd[5].fd = wport6;
111 pfd[5].events = POLLIN;
112 } else
113 pfd[5].fd = -1;
114 #endif
115 tv.tv_sec = FAITH_TIMEOUT;
116 tv.tv_usec = 0;
117
118 error = poll(pfd, 6, FAITH_TIMEOUT * 1000);
119 if (error == -1)
120 exit_failure("poll: %s", strerror(errno));
121 else if (error == 0)
122 exit_failure("connection timeout");
123
124 /*
125 * The order of the following checks does (slightly) matter.
126 * It is important to visit all checks (do not use "continue"),
127 * otherwise some of the pipe may become full and we cannot
128 * relay correctly.
129 */
130 if (pfd[1].revents & POLLIN) {
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[1].revents & POLLIN) {
147 /*
148 * copy control connection from the server
149 * translation of result code is necessary.
150 */
151 error = ftp_copyresult(ctl4, ctl6, state);
152
153 if (error < 0)
154 goto bad;
155 else if (error == 0) {
156 close(ctl4);
157 close(ctl6);
158 exit_success("terminating ftp control connection");
159 /*NOTREACHED*/
160 }
161 }
162 if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN)) {
163 /*
164 * copy data connection.
165 * no special treatment necessary.
166 */
167 if (pfd[2].revents & POLLIN)
168 error = ftp_copy(port4, port6);
169 switch (error) {
170 case -1:
171 goto bad;
172 case 0:
173 close(port4);
174 close(port6);
175 port4 = port6 = -1;
176 syslog(LOG_INFO, "terminating data connection");
177 break;
178 default:
179 break;
180 }
181 }
182 if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN)) {
183 /*
184 * copy data connection.
185 * no special treatment necessary.
186 */
187 if (pfd[3].revents & POLLIN)
188 error = ftp_copy(port6, port4);
189 switch (error) {
190 case -1:
191 goto bad;
192 case 0:
193 close(port4);
194 close(port6);
195 port4 = port6 = -1;
196 syslog(LOG_INFO, "terminating data connection");
197 break;
198 default:
199 break;
200 }
201 }
202 #if 0
203 if (wport4 && (pfd[4].revents & POLLIN)) {
204 /*
205 * establish active data connection from the server.
206 */
207 ftp_activeconn();
208 }
209 if (wport6 && (pfd[5].revents & POLLIN)) {
210 /*
211 * establish passive data connection from the client.
212 */
213 ftp_passiveconn();
214 }
215 #endif
216 }
217
218 bad:
219 exit_failure("%s", strerror(errno));
220 }
221
222 static int
ftp_activeconn()223 ftp_activeconn()
224 {
225 socklen_t n;
226 int error;
227 struct pollfd pfd[1];
228 struct sockaddr *sa;
229
230 /* get active connection from server */
231 pfd[0].fd = wport4;
232 pfd[0].events = POLLIN;
233 n = sizeof(data4);
234 if (poll(pfd, 1, 120 * 1000) == 0
235 || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) {
236 close(wport4);
237 wport4 = -1;
238 syslog(LOG_INFO, "active mode data connection failed");
239 return -1;
240 }
241
242 /* ask active connection to client */
243 sa = (struct sockaddr *)&data6;
244 port6 = socket(sa->sa_family, SOCK_STREAM, 0);
245 if (port6 == -1) {
246 close(port4);
247 close(wport4);
248 port4 = wport4 = -1;
249 syslog(LOG_INFO, "active mode data connection failed");
250 return -1;
251 }
252 error = connect(port6, sa, sa->sa_len);
253 if (error < 0) {
254 close(port6);
255 close(port4);
256 close(wport4);
257 port6 = port4 = wport4 = -1;
258 syslog(LOG_INFO, "active mode data connection failed");
259 return -1;
260 }
261
262 syslog(LOG_INFO, "active mode data connection established");
263 return 0;
264 }
265
266 static int
ftp_passiveconn()267 ftp_passiveconn()
268 {
269 socklen_t len;
270 int error;
271 struct pollfd pfd[1];
272 struct sockaddr *sa;
273
274 /* get passive connection from client */
275 pfd[0].fd = wport6;
276 pfd[0].events = POLLIN;
277 len = sizeof(data6);
278 if (poll(pfd, 1, 120 * 1000) == 0
279 || (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0) {
280 close(wport6);
281 wport6 = -1;
282 syslog(LOG_INFO, "passive mode data connection failed");
283 return -1;
284 }
285
286 /* ask passive connection to server */
287 sa = (struct sockaddr *)&data4;
288 port4 = socket(sa->sa_family, SOCK_STREAM, 0);
289 if (port4 == -1) {
290 close(wport6);
291 close(port6);
292 wport6 = port6 = -1;
293 syslog(LOG_INFO, "passive mode data connection failed");
294 return -1;
295 }
296 error = connect(port4, sa, sa->sa_len);
297 if (error < 0) {
298 close(wport6);
299 close(port4);
300 close(port6);
301 wport6 = port4 = port6 = -1;
302 syslog(LOG_INFO, "passive mode data connection failed");
303 return -1;
304 }
305
306 syslog(LOG_INFO, "passive mode data connection established");
307 return 0;
308 }
309
310 static int
ftp_copy(int src,int dst)311 ftp_copy(int src, int dst)
312 {
313 int error, atmark, 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
ftp_copyresult(int src,int dst,enum state state)348 ftp_copyresult(int src, int dst, enum state state)
349 {
350 int error, atmark, n;
351 socklen_t len;
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 len = sizeof(data6);
521 error = getsockname(wport6, (struct sockaddr *)&data6, &len);
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 len = sizeof(data6);
531 error = getsockname(dst, (struct sockaddr *)&data6, &len);
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
ftp_copycommand(int src,int dst,enum state * state)577 ftp_copycommand(int src, int dst, enum state *state)
578 {
579 int error, atmark, n;
580 socklen_t len;
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 len = sizeof(data4);
696 error = getsockname(dst, (struct sockaddr *)&data4, &len);
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 len = sizeof(data4);
729 error = getsockname(wport4, (struct sockaddr *)&data4, &len);
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 hints.ai_protocol = IPPROTO_TCP;
821 error = getaddrinfo(hostp, portp, &hints, &res);
822 if (error) {
823 n = snprintf(sbuf, sizeof(sbuf),
824 "501 EPRT: %s\r\n", gai_strerror(error));
825 if (n < 0 || n >= sizeof(sbuf))
826 n = 0;
827 if (n)
828 write(src, sbuf, n);
829 return n;
830 }
831 if (res->ai_next) {
832 n = snprintf(sbuf, sizeof(sbuf),
833 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
834 if (n < 0 || n >= sizeof(sbuf))
835 n = 0;
836 if (n)
837 write(src, sbuf, n);
838 freeaddrinfo(res);
839 return n;
840 }
841
842 memcpy(&data6, res->ai_addr, res->ai_addrlen);
843
844 freeaddrinfo(res);
845 goto sendport;
846 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
847 /*
848 * LPSV -> PASV
849 */
850 nstate = LPSV;
851
852 close(wport4);
853 close(wport6);
854 close(port4);
855 close(port6);
856 wport4 = wport6 = port4 = port6 = -1;
857
858 if (epsvall) {
859 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
860 cmd);
861 if (n < 0 || n >= sizeof(sbuf))
862 n = 0;
863 if (n)
864 write(src, sbuf, n);
865 return n;
866 }
867
868 /* transmit PASV */
869 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
870 if (n < 0 || n >= sizeof(sbuf))
871 n = 0;
872 if (n)
873 write(dst, sbuf, n);
874 *state = LPSV;
875 passivemode = 0; /* to be set to 1 later */
876 return n;
877 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
878 /*
879 * EPSV -> PASV
880 */
881 close(wport4);
882 close(wport6);
883 close(port4);
884 close(port6);
885 wport4 = wport6 = port4 = port6 = -1;
886
887 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
888 if (n < 0 || n >= sizeof(sbuf))
889 n = 0;
890 if (n)
891 write(dst, sbuf, n);
892 *state = EPSV;
893 passivemode = 0; /* to be set to 1 later */
894 return n;
895 } else if (strcmp(cmd, "EPSV") == 0 && param
896 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
897 /*
898 * EPSV ALL
899 */
900 epsvall = 1;
901 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
902 if (n < 0 || n >= sizeof(sbuf))
903 n = 0;
904 if (n)
905 write(src, sbuf, n);
906 return n;
907 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
908 /*
909 * reject PORT/PASV
910 */
911 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
912 if (n < 0 || n >= sizeof(sbuf))
913 n = 0;
914 if (n)
915 write(src, sbuf, n);
916 return n;
917 } else if (passivemode
918 && (strcmp(cmd, "STOR") == 0
919 || strcmp(cmd, "STOU") == 0
920 || strcmp(cmd, "RETR") == 0
921 || strcmp(cmd, "LIST") == 0
922 || strcmp(cmd, "NLST") == 0
923 || strcmp(cmd, "APPE") == 0)) {
924 /*
925 * commands with data transfer. need to care about passive
926 * mode data connection.
927 */
928
929 if (ftp_passiveconn() < 0) {
930 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
931 if (n < 0 || n >= sizeof(sbuf))
932 n = 0;
933 if (n)
934 write(src, sbuf, n);
935 } else {
936 /* simply relay the command */
937 write(dst, rbuf, n);
938 }
939
940 *state = NONE;
941 return n;
942 } else {
943 /* simply relay it */
944 *state = NONE;
945 write(dst, rbuf, n);
946 return n;
947 }
948
949 bad:
950 exit_failure("%s", strerror(errno));
951 /*NOTREACHED*/
952 return 0; /* to make gcc happy */
953 }
954