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