ftp.c revision 1.12 1 /* $NetBSD: ftp.c,v 1.12 2002/09/08 01:41:12 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 <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 socklen_t 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 socklen_t len;
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 len = sizeof(data6);
293 if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0
294 || (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 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, n;
329
330 /* OOB data handling */
331 error = ioctl(src, SIOCATMARK, &atmark);
332 if (error != -1 && atmark == 1) {
333 n = read(src, rbuf, 1);
334 if (n == -1)
335 goto bad;
336 send(dst, rbuf, n, MSG_OOB);
337 #if 0
338 n = read(src, rbuf, sizeof(rbuf));
339 if (n == -1)
340 goto bad;
341 write(dst, rbuf, n);
342 return n;
343 #endif
344 }
345
346 n = read(src, rbuf, sizeof(rbuf));
347 switch (n) {
348 case -1:
349 case 0:
350 return n;
351 default:
352 write(dst, rbuf, n);
353 return n;
354 }
355
356 bad:
357 exit_failure("%s", strerror(errno));
358 /*NOTREACHED*/
359 return 0; /* to make gcc happy */
360 }
361
362 static int
363 ftp_copyresult(int src, int dst, enum state state)
364 {
365 int error, atmark, n;
366 socklen_t len;
367 char *param;
368 int code;
369 char *a, *p;
370 int i;
371
372 /* OOB data handling */
373 error = ioctl(src, SIOCATMARK, &atmark);
374 if (error != -1 && atmark == 1) {
375 n = read(src, rbuf, 1);
376 if (n == -1)
377 goto bad;
378 send(dst, rbuf, n, MSG_OOB);
379 #if 0
380 n = read(src, rbuf, sizeof(rbuf));
381 if (n == -1)
382 goto bad;
383 write(dst, rbuf, n);
384 return n;
385 #endif
386 }
387
388 n = read(src, rbuf, sizeof(rbuf));
389 if (n <= 0)
390 return n;
391 rbuf[n] = '\0';
392
393 /*
394 * parse argument
395 */
396 p = rbuf;
397 for (i = 0; i < 3; i++) {
398 if (!isdigit(*p)) {
399 /* invalid reply */
400 write(dst, rbuf, n);
401 return n;
402 }
403 p++;
404 }
405 if (!isspace(*p)) {
406 /* invalid reply */
407 write(dst, rbuf, n);
408 return n;
409 }
410 code = atoi(rbuf);
411 param = p;
412 /* param points to first non-command token, if any */
413 while (*param && isspace(*param))
414 param++;
415 if (!*param)
416 param = NULL;
417
418 switch (state) {
419 case NONE:
420 if (!passivemode && rbuf[0] == '1') {
421 if (ftp_activeconn() < 0) {
422 n = snprintf(rbuf, sizeof(rbuf),
423 "425 Cannot open data connetion\r\n");
424 if (n < 0 || n >= sizeof(rbuf))
425 n = 0;
426 }
427 }
428 if (n)
429 write(dst, rbuf, n);
430 return n;
431 case LPRT:
432 case EPRT:
433 /* expecting "200 PORT command successful." */
434 if (code == 200) {
435 p = strstr(rbuf, "PORT");
436 if (p) {
437 p[0] = (state == LPRT) ? 'L' : 'E';
438 p[1] = 'P';
439 }
440 } else {
441 close(wport4);
442 wport4 = -1;
443 }
444 write(dst, rbuf, n);
445 return n;
446 case LPSV:
447 case EPSV:
448 /*
449 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
450 * (in some cases result comes without paren)
451 */
452 if (code != 227) {
453 passivefail0:
454 close(wport6);
455 wport6 = -1;
456 write(dst, rbuf, n);
457 return n;
458 }
459
460 {
461 unsigned int ho[4], po[2];
462 struct sockaddr_in *sin;
463 struct sockaddr_in6 *sin6;
464 u_short port;
465
466 /*
467 * PASV result -> LPSV/EPSV result
468 */
469 p = param;
470 while (*p && *p != '(' && !isdigit(*p)) /*)*/
471 p++;
472 if (!*p)
473 goto passivefail0; /*XXX*/
474 if (*p == '(') /*)*/
475 p++;
476 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
477 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
478 if (n != 6)
479 goto passivefail0; /*XXX*/
480
481 /* keep PORT parameter */
482 memset(&data4, 0, sizeof(data4));
483 sin = (struct sockaddr_in *)&data4;
484 sin->sin_len = sizeof(*sin);
485 sin->sin_family = AF_INET;
486 sin->sin_addr.s_addr = 0;
487 for (n = 0; n < 4; n++) {
488 sin->sin_addr.s_addr |=
489 htonl((ho[n] & 0xff) << ((3 - n) * 8));
490 }
491 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
492
493 /* get ready for passive data connection */
494 memset(&data6, 0, sizeof(data6));
495 sin6 = (struct sockaddr_in6 *)&data6;
496 sin6->sin6_len = sizeof(*sin6);
497 sin6->sin6_family = AF_INET6;
498 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
499 if (wport6 == -1) {
500 passivefail:
501 n = snprintf(sbuf, sizeof(sbuf),
502 "500 could not translate from PASV\r\n");
503 if (n < 0 || n >= sizeof(sbuf))
504 n = 0;
505 if (n)
506 write(src, sbuf, n);
507 return n;
508 }
509 #ifdef IPV6_FAITH
510 {
511 int on = 1;
512 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
513 &on, sizeof(on));
514 if (error == -1)
515 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
516 }
517 #endif
518 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
519 if (error == -1) {
520 close(wport6);
521 wport6 = -1;
522 goto passivefail;
523 }
524 error = listen(wport6, 1);
525 if (error == -1) {
526 close(wport6);
527 wport6 = -1;
528 goto passivefail;
529 }
530
531 /* transmit LPSV or EPSV */
532 /*
533 * addr from dst, port from wport6
534 */
535 len = sizeof(data6);
536 error = getsockname(wport6, (struct sockaddr *)&data6, &len);
537 if (error == -1) {
538 close(wport6);
539 wport6 = -1;
540 goto passivefail;
541 }
542 sin6 = (struct sockaddr_in6 *)&data6;
543 port = sin6->sin6_port;
544
545 len = sizeof(data6);
546 error = getsockname(dst, (struct sockaddr *)&data6, &len);
547 if (error == -1) {
548 close(wport6);
549 wport6 = -1;
550 goto passivefail;
551 }
552 sin6 = (struct sockaddr_in6 *)&data6;
553 sin6->sin6_port = port;
554
555 if (state == LPSV) {
556 a = (char *)&sin6->sin6_addr;
557 p = (char *)&sin6->sin6_port;
558 n = snprintf(sbuf, sizeof(sbuf),
559 "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",
560 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
561 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
562 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
563 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
564 2, UC(p[0]), UC(p[1]));
565 if (n < 0 || n >= sizeof(sbuf))
566 n = 0;
567 if (n)
568 write(dst, sbuf, n);
569 passivemode = 1;
570 return n;
571 } else {
572 n = snprintf(sbuf, sizeof(sbuf),
573 "229 Entering Extended Passive Mode (|||%d|)\r\n",
574 ntohs(sin6->sin6_port));
575 if (n < 0 || n >= sizeof(sbuf))
576 n = 0;
577 if (n)
578 write(dst, sbuf, n);
579 passivemode = 1;
580 return n;
581 }
582 }
583 }
584
585 bad:
586 exit_failure("%s", strerror(errno));
587 /*NOTREACHED*/
588 return 0; /* to make gcc happy */
589 }
590
591 static int
592 ftp_copycommand(int src, int dst, enum state *state)
593 {
594 int error, atmark, n;
595 socklen_t len;
596 unsigned int af, hal, ho[16], pal, po[2];
597 char *a, *p, *q;
598 char cmd[5], *param;
599 struct sockaddr_in *sin;
600 struct sockaddr_in6 *sin6;
601 enum state nstate;
602 char ch;
603 int i;
604
605 /* OOB data handling */
606 error = ioctl(src, SIOCATMARK, &atmark);
607 if (error != -1 && atmark == 1) {
608 n = read(src, rbuf, 1);
609 if (n == -1)
610 goto bad;
611 send(dst, rbuf, n, MSG_OOB);
612 #if 0
613 n = read(src, rbuf, sizeof(rbuf));
614 if (n == -1)
615 goto bad;
616 write(dst, rbuf, n);
617 return n;
618 #endif
619 }
620
621 n = read(src, rbuf, sizeof(rbuf));
622 if (n <= 0)
623 return n;
624 rbuf[n] = '\0';
625
626 if (n < 4) {
627 write(dst, rbuf, n);
628 return n;
629 }
630
631 /*
632 * parse argument
633 */
634 p = rbuf;
635 q = cmd;
636 for (i = 0; i < 4; i++) {
637 if (!isalpha(*p)) {
638 /* invalid command */
639 write(dst, rbuf, n);
640 return n;
641 }
642 *q++ = islower(*p) ? toupper(*p) : *p;
643 p++;
644 }
645 if (!isspace(*p)) {
646 /* invalid command */
647 write(dst, rbuf, n);
648 return n;
649 }
650 *q = '\0';
651 param = p;
652 /* param points to first non-command token, if any */
653 while (*param && isspace(*param))
654 param++;
655 if (!*param)
656 param = NULL;
657
658 *state = NONE;
659
660 if (strcmp(cmd, "LPRT") == 0 && param) {
661 /*
662 * LPRT -> PORT
663 */
664 nstate = LPRT;
665
666 close(wport4);
667 close(wport6);
668 close(port4);
669 close(port6);
670 wport4 = wport6 = port4 = port6 = -1;
671
672 if (epsvall) {
673 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
674 cmd);
675 if (n < 0 || n >= sizeof(sbuf))
676 n = 0;
677 if (n)
678 write(src, sbuf, n);
679 return n;
680 }
681
682 n = sscanf(param,
683 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
684 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
685 &ho[4], &ho[5], &ho[6], &ho[7],
686 &ho[8], &ho[9], &ho[10], &ho[11],
687 &ho[12], &ho[13], &ho[14], &ho[15],
688 &pal, &po[0], &po[1]);
689 if (n != 21 || af != 6 || hal != 16|| pal != 2) {
690 n = snprintf(sbuf, sizeof(sbuf),
691 "501 illegal parameter to LPRT\r\n");
692 if (n < 0 || n >= sizeof(sbuf))
693 n = 0;
694 if (n)
695 write(src, sbuf, n);
696 return n;
697 }
698
699 /* keep LPRT parameter */
700 memset(&data6, 0, sizeof(data6));
701 sin6 = (struct sockaddr_in6 *)&data6;
702 sin6->sin6_len = sizeof(*sin6);
703 sin6->sin6_family = AF_INET6;
704 for (n = 0; n < 16; n++)
705 sin6->sin6_addr.s6_addr[n] = ho[n];
706 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
707
708 sendport:
709 /* get ready for active data connection */
710 len = sizeof(data4);
711 error = getsockname(dst, (struct sockaddr *)&data4, &len);
712 if (error == -1) {
713 lprtfail:
714 n = snprintf(sbuf, sizeof(sbuf),
715 "500 could not translate to PORT\r\n");
716 if (n < 0 || n >= sizeof(sbuf))
717 n = 0;
718 if (n)
719 write(src, sbuf, n);
720 return n;
721 }
722 if (((struct sockaddr *)&data4)->sa_family != AF_INET)
723 goto lprtfail;
724 sin = (struct sockaddr_in *)&data4;
725 sin->sin_port = 0;
726 wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
727 if (wport4 == -1)
728 goto lprtfail;
729 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
730 if (error == -1) {
731 close(wport4);
732 wport4 = -1;
733 goto lprtfail;
734 }
735 error = listen(wport4, 1);
736 if (error == -1) {
737 close(wport4);
738 wport4 = -1;
739 goto lprtfail;
740 }
741
742 /* transmit PORT */
743 len = sizeof(data4);
744 error = getsockname(wport4, (struct sockaddr *)&data4, &len);
745 if (error == -1) {
746 close(wport4);
747 wport4 = -1;
748 goto lprtfail;
749 }
750 if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
751 close(wport4);
752 wport4 = -1;
753 goto lprtfail;
754 }
755 sin = (struct sockaddr_in *)&data4;
756 a = (char *)&sin->sin_addr;
757 p = (char *)&sin->sin_port;
758 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
759 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
760 UC(p[0]), UC(p[1]));
761 if (n < 0 || n >= sizeof(sbuf))
762 n = 0;
763 if (n)
764 write(dst, sbuf, n);
765 *state = nstate;
766 passivemode = 0;
767 return n;
768 } else if (strcmp(cmd, "EPRT") == 0 && param) {
769 /*
770 * EPRT -> PORT
771 */
772 char *afp, *hostp, *portp;
773 struct addrinfo hints, *res;
774
775 nstate = EPRT;
776
777 close(wport4);
778 close(wport6);
779 close(port4);
780 close(port6);
781 wport4 = wport6 = port4 = port6 = -1;
782
783 if (epsvall) {
784 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
785 cmd);
786 if (n < 0 || n >= sizeof(sbuf))
787 n = 0;
788 if (n)
789 write(src, sbuf, n);
790 return n;
791 }
792
793 p = param;
794 ch = *p++; /* boundary character */
795 afp = p;
796 while (*p && *p != ch)
797 p++;
798 if (!*p) {
799 eprtparamfail:
800 n = snprintf(sbuf, sizeof(sbuf),
801 "501 illegal parameter to EPRT\r\n");
802 if (n < 0 || n >= sizeof(sbuf))
803 n = 0;
804 if (n)
805 write(src, sbuf, n);
806 return n;
807 }
808 *p++ = '\0';
809 hostp = p;
810 while (*p && *p != ch)
811 p++;
812 if (!*p)
813 goto eprtparamfail;
814 *p++ = '\0';
815 portp = p;
816 while (*p && *p != ch)
817 p++;
818 if (!*p)
819 goto eprtparamfail;
820 *p++ = '\0';
821
822 n = sscanf(afp, "%d", &af);
823 if (n != 1 || af != 2) {
824 n = snprintf(sbuf, sizeof(sbuf),
825 "501 unsupported address family to EPRT\r\n");
826 if (n < 0 || n >= sizeof(sbuf))
827 n = 0;
828 if (n)
829 write(src, sbuf, n);
830 return n;
831 }
832 memset(&hints, 0, sizeof(hints));
833 hints.ai_family = AF_UNSPEC;
834 hints.ai_socktype = SOCK_STREAM;
835 error = getaddrinfo(hostp, portp, &hints, &res);
836 if (error) {
837 n = snprintf(sbuf, sizeof(sbuf),
838 "501 EPRT: %s\r\n", gai_strerror(error));
839 if (n < 0 || n >= sizeof(sbuf))
840 n = 0;
841 if (n)
842 write(src, sbuf, n);
843 return n;
844 }
845 if (res->ai_next) {
846 n = snprintf(sbuf, sizeof(sbuf),
847 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
848 if (n < 0 || n >= sizeof(sbuf))
849 n = 0;
850 if (n)
851 write(src, sbuf, n);
852 return n;
853 }
854
855 memcpy(&data6, res->ai_addr, res->ai_addrlen);
856
857 goto sendport;
858 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
859 /*
860 * LPSV -> PASV
861 */
862 nstate = LPSV;
863
864 close(wport4);
865 close(wport6);
866 close(port4);
867 close(port6);
868 wport4 = wport6 = port4 = port6 = -1;
869
870 if (epsvall) {
871 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
872 cmd);
873 if (n < 0 || n >= sizeof(sbuf))
874 n = 0;
875 if (n)
876 write(src, sbuf, n);
877 return n;
878 }
879
880 /* transmit PASV */
881 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
882 if (n < 0 || n >= sizeof(sbuf))
883 n = 0;
884 if (n)
885 write(dst, sbuf, n);
886 *state = LPSV;
887 passivemode = 0; /* to be set to 1 later */
888 return n;
889 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
890 /*
891 * EPSV -> PASV
892 */
893 close(wport4);
894 close(wport6);
895 close(port4);
896 close(port6);
897 wport4 = wport6 = port4 = port6 = -1;
898
899 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
900 if (n < 0 || n >= sizeof(sbuf))
901 n = 0;
902 if (n)
903 write(dst, sbuf, n);
904 *state = EPSV;
905 passivemode = 0; /* to be set to 1 later */
906 return n;
907 } else if (strcmp(cmd, "EPSV") == 0 && param
908 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
909 /*
910 * EPSV ALL
911 */
912 epsvall = 1;
913 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
914 if (n < 0 || n >= sizeof(sbuf))
915 n = 0;
916 if (n)
917 write(src, sbuf, n);
918 return n;
919 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
920 /*
921 * reject PORT/PASV
922 */
923 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
924 if (n < 0 || n >= sizeof(sbuf))
925 n = 0;
926 if (n)
927 write(src, sbuf, n);
928 return n;
929 } else if (passivemode
930 && (strcmp(cmd, "STOR") == 0
931 || strcmp(cmd, "STOU") == 0
932 || strcmp(cmd, "RETR") == 0
933 || strcmp(cmd, "LIST") == 0
934 || strcmp(cmd, "NLST") == 0
935 || strcmp(cmd, "APPE") == 0)) {
936 /*
937 * commands with data transfer. need to care about passive
938 * mode data connection.
939 */
940
941 if (ftp_passiveconn() < 0) {
942 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
943 if (n < 0 || n >= sizeof(sbuf))
944 n = 0;
945 if (n)
946 write(src, sbuf, n);
947 } else {
948 /* simply relay the command */
949 write(dst, rbuf, n);
950 }
951
952 *state = NONE;
953 return n;
954 } else {
955 /* simply relay it */
956 *state = NONE;
957 write(dst, rbuf, n);
958 return n;
959 }
960
961 bad:
962 exit_failure("%s", strerror(errno));
963 /*NOTREACHED*/
964 return 0; /* to make gcc happy */
965 }
966