Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / usr.sbin / faithd / ftp.c
blobc54371a2c20e6496f4d198b58a87d0ffaf16ed6e
1 /* $KAME: ftp.c,v 1.24 2005/03/16 05:05:48 itojun Exp $ */
3 /*
4 * Copyright (C) 1997 and 1998 WIDE Project.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * $FreeBSD$
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45 #ifdef HAVE_POLL_H
46 #include <poll.h>
47 #endif
48 #include <errno.h>
49 #include <ctype.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
55 #include "faithd.h"
57 static char rbuf[MSS];
58 static char sbuf[MSS];
59 static int passivemode = 0;
60 static int wport4 = -1; /* listen() to active */
61 static int wport6 = -1; /* listen() to passive */
62 static int port4 = -1; /* active: inbound passive: outbound */
63 static int port6 = -1; /* active: outbound passive: inbound */
64 static struct sockaddr_storage data4; /* server data address */
65 static struct sockaddr_storage data6; /* client data address */
66 static int epsvall = 0;
68 enum state { NONE, LPRT, EPRT, LPSV, EPSV };
70 static int ftp_activeconn(void);
71 static int ftp_passiveconn(void);
72 static int ftp_copy(int, int);
73 static int ftp_copyresult(int, int, enum state);
74 static int ftp_copycommand(int, int, enum state *);
76 void
77 ftp_relay(int ctl6, int ctl4)
79 #ifdef HAVE_POLL_H
80 struct pollfd pfd[6];
81 #else
82 fd_set readfds;
83 #endif
84 int error;
85 enum state state = NONE;
86 struct timeval tv;
88 syslog(LOG_INFO, "starting ftp control connection");
90 for (;;) {
91 #ifdef HAVE_POLL_H
92 pfd[0].fd = ctl4;
93 pfd[0].events = POLLIN;
94 pfd[1].fd = ctl6;
95 pfd[1].events = POLLIN;
96 if (0 <= port4) {
97 pfd[2].fd = port4;
98 pfd[2].events = POLLIN;
99 } else
100 pfd[2].fd = -1;
101 if (0 <= port6) {
102 pfd[3].fd = port6;
103 pfd[3].events = POLLIN;
104 } else
105 pfd[3].fd = -1;
106 #if 0
107 if (0 <= wport4) {
108 pfd[4].fd = wport4;
109 pfd[4].events = POLLIN;
110 } else
111 pfd[4].fd = -1;
112 if (0 <= wport6) {
113 pfd[5].fd = wport4;
114 pfd[5].events = POLLIN;
115 } else
116 pfd[5].fd = -1;
117 #else
118 pfd[4].fd = pfd[5].fd = -1;
119 pfd[4].events = pfd[5].events = 0;
120 #endif
121 #else
122 int maxfd = 0;
124 FD_ZERO(&readfds);
125 if (ctl4 >= FD_SETSIZE)
126 exit_failure("descriptor too big");
127 FD_SET(ctl4, &readfds);
128 maxfd = ctl4;
129 if (ctl6 >= FD_SETSIZE)
130 exit_failure("descriptor too big");
131 FD_SET(ctl6, &readfds);
132 maxfd = (ctl6 > maxfd) ? ctl6 : maxfd;
133 if (0 <= port4) {
134 if (port4 >= FD_SETSIZE)
135 exit_failure("descriptor too big");
136 FD_SET(port4, &readfds);
137 maxfd = (port4 > maxfd) ? port4 : maxfd;
139 if (0 <= port6) {
140 if (port6 >= FD_SETSIZE)
141 exit_failure("descriptor too big");
142 FD_SET(port6, &readfds);
143 maxfd = (port6 > maxfd) ? port6 : maxfd;
145 #if 0
146 if (0 <= wport4) {
147 if (wport4 >= FD_SETSIZE)
148 exit_failure("descriptor too big");
149 FD_SET(wport4, &readfds);
150 maxfd = (wport4 > maxfd) ? wport4 : maxfd;
152 if (0 <= wport6) {
153 if (wport6 >= FD_SETSIZE)
154 exit_failure("descriptor too big");
155 FD_SET(wport6, &readfds);
156 maxfd = (wport6 > maxfd) ? wport6 : maxfd;
158 #endif
159 #endif
160 tv.tv_sec = FAITH_TIMEOUT;
161 tv.tv_usec = 0;
163 #ifdef HAVE_POLL_H
164 error = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), tv.tv_sec * 1000);
165 #else
166 error = select(maxfd + 1, &readfds, NULL, NULL, &tv);
167 #endif
168 if (error == -1) {
169 #ifdef HAVE_POLL_H
170 exit_failure("poll: %s", strerror(errno));
171 #else
172 exit_failure("select: %s", strerror(errno));
173 #endif
175 else if (error == 0)
176 exit_failure("connection timeout");
179 * The order of the following checks does (slightly) matter.
180 * It is important to visit all checks (do not use "continue"),
181 * otherwise some of the pipe may become full and we cannot
182 * relay correctly.
184 #ifdef HAVE_POLL_H
185 if (pfd[1].revents & POLLIN)
186 #else
187 if (FD_ISSET(ctl6, &readfds))
188 #endif
191 * copy control connection from the client.
192 * command translation is necessary.
194 error = ftp_copycommand(ctl6, ctl4, &state);
196 if (error < 0)
197 goto bad;
198 else if (error == 0) {
199 close(ctl4);
200 close(ctl6);
201 exit_success("terminating ftp control connection");
202 /*NOTREACHED*/
205 #ifdef HAVE_POLL_H
206 if (pfd[0].revents & POLLIN)
207 #else
208 if (FD_ISSET(ctl4, &readfds))
209 #endif
212 * copy control connection from the server
213 * translation of result code is necessary.
215 error = ftp_copyresult(ctl4, ctl6, state);
217 if (error < 0)
218 goto bad;
219 else if (error == 0) {
220 close(ctl4);
221 close(ctl6);
222 exit_success("terminating ftp control connection");
223 /*NOTREACHED*/
226 #ifdef HAVE_POLL_H
227 if (0 <= port4 && 0 <= port6 && (pfd[2].revents & POLLIN))
228 #else
229 if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds))
230 #endif
233 * copy data connection.
234 * no special treatment necessary.
236 #ifdef HAVE_POLL_H
237 if (pfd[2].revents & POLLIN)
238 #else
239 if (FD_ISSET(port4, &readfds))
240 #endif
241 error = ftp_copy(port4, port6);
242 switch (error) {
243 case -1:
244 goto bad;
245 case 0:
246 close(port4);
247 close(port6);
248 port4 = port6 = -1;
249 syslog(LOG_INFO, "terminating data connection");
250 break;
251 default:
252 break;
255 #ifdef HAVE_POLL_H
256 if (0 <= port4 && 0 <= port6 && (pfd[3].revents & POLLIN))
257 #else
258 if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds))
259 #endif
262 * copy data connection.
263 * no special treatment necessary.
265 #ifdef HAVE_POLL_H
266 if (pfd[3].revents & POLLIN)
267 #else
268 if (FD_ISSET(port6, &readfds))
269 #endif
270 error = ftp_copy(port6, port4);
271 switch (error) {
272 case -1:
273 goto bad;
274 case 0:
275 close(port4);
276 close(port6);
277 port4 = port6 = -1;
278 syslog(LOG_INFO, "terminating data connection");
279 break;
280 default:
281 break;
284 #if 0
285 #ifdef HAVE_POLL_H
286 if (wport4 && (pfd[4].revents & POLLIN))
287 #else
288 if (wport4 && FD_ISSET(wport4, &readfds))
289 #endif
292 * establish active data connection from the server.
294 ftp_activeconn();
296 #ifdef HAVE_POLL_H
297 if (wport4 && (pfd[5].revents & POLLIN))
298 #else
299 if (wport6 && FD_ISSET(wport6, &readfds))
300 #endif
303 * establish passive data connection from the client.
305 ftp_passiveconn();
307 #endif
310 bad:
311 exit_failure("%s", strerror(errno));
314 static int
315 ftp_activeconn()
317 socklen_t n;
318 int error;
319 #ifdef HAVE_POLL_H
320 struct pollfd pfd[1];
321 #else
322 fd_set set;
323 #endif
324 struct timeval timeout;
325 struct sockaddr *sa;
327 /* get active connection from server */
328 #ifdef HAVE_POLL_H
329 pfd[0].fd = wport4;
330 pfd[0].events = POLLIN;
331 #else
332 FD_ZERO(&set);
333 if (wport4 >= FD_SETSIZE)
334 exit_failure("descriptor too big");
335 FD_SET(wport4, &set);
336 #endif
337 timeout.tv_sec = 120;
338 timeout.tv_usec = 0;
339 n = sizeof(data4);
340 #ifdef HAVE_POLL_H
341 if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
342 (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0)
343 #else
344 if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0 ||
345 (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0)
346 #endif
348 close(wport4);
349 wport4 = -1;
350 syslog(LOG_INFO, "active mode data connection failed");
351 return -1;
354 /* ask active connection to client */
355 sa = (struct sockaddr *)&data6;
356 port6 = socket(sa->sa_family, SOCK_STREAM, 0);
357 if (port6 == -1) {
358 close(port4);
359 close(wport4);
360 port4 = wport4 = -1;
361 syslog(LOG_INFO, "active mode data connection failed");
362 return -1;
364 error = connect(port6, sa, sa->sa_len);
365 if (error < 0) {
366 close(port6);
367 close(port4);
368 close(wport4);
369 port6 = port4 = wport4 = -1;
370 syslog(LOG_INFO, "active mode data connection failed");
371 return -1;
374 syslog(LOG_INFO, "active mode data connection established");
375 return 0;
378 static int
379 ftp_passiveconn()
381 socklen_t len;
382 int error;
383 #ifdef HAVE_POLL_H
384 struct pollfd pfd[1];
385 #else
386 fd_set set;
387 #endif
388 struct timeval timeout;
389 struct sockaddr *sa;
391 /* get passive connection from client */
392 #ifdef HAVE_POLL_H
393 pfd[0].fd = wport6;
394 pfd[0].events = POLLIN;
395 #else
396 FD_ZERO(&set);
397 if (wport6 >= FD_SETSIZE)
398 exit_failure("descriptor too big");
399 FD_SET(wport6, &set);
400 #endif
401 timeout.tv_sec = 120;
402 timeout.tv_usec = 0;
403 len = sizeof(data6);
404 #ifdef HAVE_POLL_H
405 if (poll(pfd, sizeof(pfd)/sizeof(pfd[0]), timeout.tv_sec * 1000) == 0 ||
406 (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0)
407 #else
408 if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0 ||
409 (port6 = accept(wport6, (struct sockaddr *)&data6, &len)) < 0)
410 #endif
412 close(wport6);
413 wport6 = -1;
414 syslog(LOG_INFO, "passive mode data connection failed");
415 return -1;
418 /* ask passive connection to server */
419 sa = (struct sockaddr *)&data4;
420 port4 = socket(sa->sa_family, SOCK_STREAM, 0);
421 if (port4 == -1) {
422 close(wport6);
423 close(port6);
424 wport6 = port6 = -1;
425 syslog(LOG_INFO, "passive mode data connection failed");
426 return -1;
428 error = connect(port4, sa, sa->sa_len);
429 if (error < 0) {
430 close(wport6);
431 close(port4);
432 close(port6);
433 wport6 = port4 = port6 = -1;
434 syslog(LOG_INFO, "passive mode data connection failed");
435 return -1;
438 syslog(LOG_INFO, "passive mode data connection established");
439 return 0;
442 static int
443 ftp_copy(int src, int dst)
445 int error, atmark, n;
447 /* OOB data handling */
448 error = ioctl(src, SIOCATMARK, &atmark);
449 if (error != -1 && atmark == 1) {
450 n = read(src, rbuf, 1);
451 if (n == -1)
452 goto bad;
453 send(dst, rbuf, n, MSG_OOB);
454 #if 0
455 n = read(src, rbuf, sizeof(rbuf));
456 if (n == -1)
457 goto bad;
458 write(dst, rbuf, n);
459 return n;
460 #endif
463 n = read(src, rbuf, sizeof(rbuf));
464 switch (n) {
465 case -1:
466 case 0:
467 return n;
468 default:
469 write(dst, rbuf, n);
470 return n;
473 bad:
474 exit_failure("%s", strerror(errno));
475 /*NOTREACHED*/
476 return 0; /* to make gcc happy */
479 static int
480 ftp_copyresult(int src, int dst, enum state state)
482 int error, atmark, n;
483 socklen_t len;
484 char *param;
485 int code;
486 char *a, *p;
487 int i;
489 /* OOB data handling */
490 error = ioctl(src, SIOCATMARK, &atmark);
491 if (error != -1 && atmark == 1) {
492 n = read(src, rbuf, 1);
493 if (n == -1)
494 goto bad;
495 send(dst, rbuf, n, MSG_OOB);
496 #if 0
497 n = read(src, rbuf, sizeof(rbuf));
498 if (n == -1)
499 goto bad;
500 write(dst, rbuf, n);
501 return n;
502 #endif
505 n = read(src, rbuf, sizeof(rbuf));
506 if (n <= 0)
507 return n;
508 rbuf[n] = '\0';
511 * parse argument
513 p = rbuf;
514 for (i = 0; i < 3; i++) {
515 if (!isdigit(*p)) {
516 /* invalid reply */
517 write(dst, rbuf, n);
518 return n;
520 p++;
522 if (!isspace(*p)) {
523 /* invalid reply */
524 write(dst, rbuf, n);
525 return n;
527 code = atoi(rbuf);
528 param = p;
529 /* param points to first non-command token, if any */
530 while (*param && isspace(*param))
531 param++;
532 if (!*param)
533 param = NULL;
535 switch (state) {
536 case NONE:
537 if (!passivemode && rbuf[0] == '1') {
538 if (ftp_activeconn() < 0) {
539 n = snprintf(rbuf, sizeof(rbuf),
540 "425 Cannot open data connetion\r\n");
541 if (n < 0 || n >= sizeof(rbuf))
542 n = 0;
545 if (n)
546 write(dst, rbuf, n);
547 return n;
548 case LPRT:
549 case EPRT:
550 /* expecting "200 PORT command successful." */
551 if (code == 200) {
552 p = strstr(rbuf, "PORT");
553 if (p) {
554 p[0] = (state == LPRT) ? 'L' : 'E';
555 p[1] = 'P';
557 } else {
558 close(wport4);
559 wport4 = -1;
561 write(dst, rbuf, n);
562 return n;
563 case LPSV:
564 case EPSV:
566 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
567 * (in some cases result comes without paren)
569 if (code != 227) {
570 passivefail0:
571 close(wport6);
572 wport6 = -1;
573 write(dst, rbuf, n);
574 return n;
578 unsigned int ho[4], po[2];
579 struct sockaddr_in *sin;
580 struct sockaddr_in6 *sin6;
581 u_short port;
584 * PASV result -> LPSV/EPSV result
586 p = param;
587 while (*p && *p != '(' && !isdigit(*p)) /*)*/
588 p++;
589 if (!*p)
590 goto passivefail0; /*XXX*/
591 if (*p == '(') /*)*/
592 p++;
593 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
594 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
595 if (n != 6)
596 goto passivefail0; /*XXX*/
598 /* keep PORT parameter */
599 memset(&data4, 0, sizeof(data4));
600 sin = (struct sockaddr_in *)&data4;
601 sin->sin_len = sizeof(*sin);
602 sin->sin_family = AF_INET;
603 sin->sin_addr.s_addr = 0;
604 for (n = 0; n < 4; n++) {
605 sin->sin_addr.s_addr |=
606 htonl((ho[n] & 0xff) << ((3 - n) * 8));
608 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
610 /* get ready for passive data connection */
611 memset(&data6, 0, sizeof(data6));
612 sin6 = (struct sockaddr_in6 *)&data6;
613 sin6->sin6_len = sizeof(*sin6);
614 sin6->sin6_family = AF_INET6;
615 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
616 if (wport6 == -1) {
617 passivefail:
618 n = snprintf(sbuf, sizeof(sbuf),
619 "500 could not translate from PASV\r\n");
620 if (n < 0 || n >= sizeof(sbuf))
621 n = 0;
622 if (n)
623 write(src, sbuf, n);
624 return n;
626 #ifdef IPV6_FAITH
628 int on = 1;
629 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
630 &on, sizeof(on));
631 if (error == -1)
632 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
634 #endif
635 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
636 if (error == -1) {
637 close(wport6);
638 wport6 = -1;
639 goto passivefail;
641 error = listen(wport6, 1);
642 if (error == -1) {
643 close(wport6);
644 wport6 = -1;
645 goto passivefail;
648 /* transmit LPSV or EPSV */
650 * addr from dst, port from wport6
652 len = sizeof(data6);
653 error = getsockname(wport6, (struct sockaddr *)&data6, &len);
654 if (error == -1) {
655 close(wport6);
656 wport6 = -1;
657 goto passivefail;
659 sin6 = (struct sockaddr_in6 *)&data6;
660 port = sin6->sin6_port;
662 len = sizeof(data6);
663 error = getsockname(dst, (struct sockaddr *)&data6, &len);
664 if (error == -1) {
665 close(wport6);
666 wport6 = -1;
667 goto passivefail;
669 sin6 = (struct sockaddr_in6 *)&data6;
670 sin6->sin6_port = port;
672 if (state == LPSV) {
673 a = (char *)&sin6->sin6_addr;
674 p = (char *)&sin6->sin6_port;
675 n = snprintf(sbuf, sizeof(sbuf),
676 "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",
677 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
678 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
679 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
680 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
681 2, UC(p[0]), UC(p[1]));
682 if (n < 0 || n >= sizeof(sbuf))
683 n = 0;
684 if (n)
685 write(dst, sbuf, n);
686 passivemode = 1;
687 return n;
688 } else {
689 n = snprintf(sbuf, sizeof(sbuf),
690 "229 Entering Extended Passive Mode (|||%d|)\r\n",
691 ntohs(sin6->sin6_port));
692 if (n < 0 || n >= sizeof(sbuf))
693 n = 0;
694 if (n)
695 write(dst, sbuf, n);
696 passivemode = 1;
697 return n;
702 bad:
703 exit_failure("%s", strerror(errno));
704 /*NOTREACHED*/
705 return 0; /* to make gcc happy */
708 static int
709 ftp_copycommand(int src, int dst, enum state *state)
711 int error, atmark, n;
712 socklen_t len;
713 unsigned int af, hal, ho[16], pal, po[2];
714 char *a, *p, *q;
715 char cmd[5], *param;
716 struct sockaddr_in *sin;
717 struct sockaddr_in6 *sin6;
718 enum state nstate;
719 char ch;
720 int i;
722 /* OOB data handling */
723 error = ioctl(src, SIOCATMARK, &atmark);
724 if (error != -1 && atmark == 1) {
725 n = read(src, rbuf, 1);
726 if (n == -1)
727 goto bad;
728 send(dst, rbuf, n, MSG_OOB);
729 #if 0
730 n = read(src, rbuf, sizeof(rbuf));
731 if (n == -1)
732 goto bad;
733 write(dst, rbuf, n);
734 return n;
735 #endif
738 n = read(src, rbuf, sizeof(rbuf));
739 if (n <= 0)
740 return n;
741 rbuf[n] = '\0';
743 if (n < 4) {
744 write(dst, rbuf, n);
745 return n;
749 * parse argument
751 p = rbuf;
752 q = cmd;
753 for (i = 0; i < 4; i++) {
754 if (!isalpha(*p)) {
755 /* invalid command */
756 write(dst, rbuf, n);
757 return n;
759 *q++ = islower(*p) ? toupper(*p) : *p;
760 p++;
762 if (!isspace(*p)) {
763 /* invalid command */
764 write(dst, rbuf, n);
765 return n;
767 *q = '\0';
768 param = p;
769 /* param points to first non-command token, if any */
770 while (*param && isspace(*param))
771 param++;
772 if (!*param)
773 param = NULL;
775 *state = NONE;
777 if (strcmp(cmd, "LPRT") == 0 && param) {
779 * LPRT -> PORT
781 nstate = LPRT;
783 close(wport4);
784 close(wport6);
785 close(port4);
786 close(port6);
787 wport4 = wport6 = port4 = port6 = -1;
789 if (epsvall) {
790 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
791 cmd);
792 if (n < 0 || n >= sizeof(sbuf))
793 n = 0;
794 if (n)
795 write(src, sbuf, n);
796 return n;
799 n = sscanf(param,
800 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
801 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
802 &ho[4], &ho[5], &ho[6], &ho[7],
803 &ho[8], &ho[9], &ho[10], &ho[11],
804 &ho[12], &ho[13], &ho[14], &ho[15],
805 &pal, &po[0], &po[1]);
806 if (n != 21 || af != 6 || hal != 16|| pal != 2) {
807 n = snprintf(sbuf, sizeof(sbuf),
808 "501 illegal parameter to LPRT\r\n");
809 if (n < 0 || n >= sizeof(sbuf))
810 n = 0;
811 if (n)
812 write(src, sbuf, n);
813 return n;
816 /* keep LPRT parameter */
817 memset(&data6, 0, sizeof(data6));
818 sin6 = (struct sockaddr_in6 *)&data6;
819 sin6->sin6_len = sizeof(*sin6);
820 sin6->sin6_family = AF_INET6;
821 for (n = 0; n < 16; n++)
822 sin6->sin6_addr.s6_addr[n] = ho[n];
823 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
825 sendport:
826 /* get ready for active data connection */
827 len = sizeof(data4);
828 error = getsockname(dst, (struct sockaddr *)&data4, &len);
829 if (error == -1) {
830 lprtfail:
831 n = snprintf(sbuf, sizeof(sbuf),
832 "500 could not translate to PORT\r\n");
833 if (n < 0 || n >= sizeof(sbuf))
834 n = 0;
835 if (n)
836 write(src, sbuf, n);
837 return n;
839 if (((struct sockaddr *)&data4)->sa_family != AF_INET)
840 goto lprtfail;
841 sin = (struct sockaddr_in *)&data4;
842 sin->sin_port = 0;
843 wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
844 if (wport4 == -1)
845 goto lprtfail;
846 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
847 if (error == -1) {
848 close(wport4);
849 wport4 = -1;
850 goto lprtfail;
852 error = listen(wport4, 1);
853 if (error == -1) {
854 close(wport4);
855 wport4 = -1;
856 goto lprtfail;
859 /* transmit PORT */
860 len = sizeof(data4);
861 error = getsockname(wport4, (struct sockaddr *)&data4, &len);
862 if (error == -1) {
863 close(wport4);
864 wport4 = -1;
865 goto lprtfail;
867 if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
868 close(wport4);
869 wport4 = -1;
870 goto lprtfail;
872 sin = (struct sockaddr_in *)&data4;
873 a = (char *)&sin->sin_addr;
874 p = (char *)&sin->sin_port;
875 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
876 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
877 UC(p[0]), UC(p[1]));
878 if (n < 0 || n >= sizeof(sbuf))
879 n = 0;
880 if (n)
881 write(dst, sbuf, n);
882 *state = nstate;
883 passivemode = 0;
884 return n;
885 } else if (strcmp(cmd, "EPRT") == 0 && param) {
887 * EPRT -> PORT
889 char *afp, *hostp, *portp;
890 struct addrinfo hints, *res;
892 nstate = EPRT;
894 close(wport4);
895 close(wport6);
896 close(port4);
897 close(port6);
898 wport4 = wport6 = port4 = port6 = -1;
900 if (epsvall) {
901 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
902 cmd);
903 if (n < 0 || n >= sizeof(sbuf))
904 n = 0;
905 if (n)
906 write(src, sbuf, n);
907 return n;
910 p = param;
911 ch = *p++; /* boundary character */
912 afp = p;
913 while (*p && *p != ch)
914 p++;
915 if (!*p) {
916 eprtparamfail:
917 n = snprintf(sbuf, sizeof(sbuf),
918 "501 illegal parameter to EPRT\r\n");
919 if (n < 0 || n >= sizeof(sbuf))
920 n = 0;
921 if (n)
922 write(src, sbuf, n);
923 return n;
925 *p++ = '\0';
926 hostp = p;
927 while (*p && *p != ch)
928 p++;
929 if (!*p)
930 goto eprtparamfail;
931 *p++ = '\0';
932 portp = p;
933 while (*p && *p != ch)
934 p++;
935 if (!*p)
936 goto eprtparamfail;
937 *p++ = '\0';
939 n = sscanf(afp, "%d", &af);
940 if (n != 1 || af != 2) {
941 n = snprintf(sbuf, sizeof(sbuf),
942 "501 unsupported address family to EPRT\r\n");
943 if (n < 0 || n >= sizeof(sbuf))
944 n = 0;
945 if (n)
946 write(src, sbuf, n);
947 return n;
949 memset(&hints, 0, sizeof(hints));
950 hints.ai_family = AF_UNSPEC;
951 hints.ai_socktype = SOCK_STREAM;
952 hints.ai_protocol = IPPROTO_TCP;
953 error = getaddrinfo(hostp, portp, &hints, &res);
954 if (error) {
955 n = snprintf(sbuf, sizeof(sbuf),
956 "501 EPRT: %s\r\n", gai_strerror(error));
957 if (n < 0 || n >= sizeof(sbuf))
958 n = 0;
959 if (n)
960 write(src, sbuf, n);
961 return n;
963 if (res->ai_next) {
964 n = snprintf(sbuf, sizeof(sbuf),
965 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
966 if (n < 0 || n >= sizeof(sbuf))
967 n = 0;
968 if (n)
969 write(src, sbuf, n);
970 freeaddrinfo(res);
971 return n;
974 memcpy(&data6, res->ai_addr, res->ai_addrlen);
976 freeaddrinfo(res);
977 goto sendport;
978 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
980 * LPSV -> PASV
982 nstate = LPSV;
984 close(wport4);
985 close(wport6);
986 close(port4);
987 close(port6);
988 wport4 = wport6 = port4 = port6 = -1;
990 if (epsvall) {
991 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
992 cmd);
993 if (n < 0 || n >= sizeof(sbuf))
994 n = 0;
995 if (n)
996 write(src, sbuf, n);
997 return n;
1000 /* transmit PASV */
1001 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
1002 if (n < 0 || n >= sizeof(sbuf))
1003 n = 0;
1004 if (n)
1005 write(dst, sbuf, n);
1006 *state = LPSV;
1007 passivemode = 0; /* to be set to 1 later */
1008 return n;
1009 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
1011 * EPSV -> PASV
1013 close(wport4);
1014 close(wport6);
1015 close(port4);
1016 close(port6);
1017 wport4 = wport6 = port4 = port6 = -1;
1019 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
1020 if (n < 0 || n >= sizeof(sbuf))
1021 n = 0;
1022 if (n)
1023 write(dst, sbuf, n);
1024 *state = EPSV;
1025 passivemode = 0; /* to be set to 1 later */
1026 return n;
1027 } else if (strcmp(cmd, "EPSV") == 0 && param
1028 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
1030 * EPSV ALL
1032 epsvall = 1;
1033 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
1034 if (n < 0 || n >= sizeof(sbuf))
1035 n = 0;
1036 if (n)
1037 write(src, sbuf, n);
1038 return n;
1039 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
1041 * reject PORT/PASV
1043 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
1044 if (n < 0 || n >= sizeof(sbuf))
1045 n = 0;
1046 if (n)
1047 write(src, sbuf, n);
1048 return n;
1049 } else if (passivemode
1050 && (strcmp(cmd, "STOR") == 0
1051 || strcmp(cmd, "STOU") == 0
1052 || strcmp(cmd, "RETR") == 0
1053 || strcmp(cmd, "LIST") == 0
1054 || strcmp(cmd, "NLST") == 0
1055 || strcmp(cmd, "APPE") == 0)) {
1057 * commands with data transfer. need to care about passive
1058 * mode data connection.
1061 if (ftp_passiveconn() < 0) {
1062 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
1063 if (n < 0 || n >= sizeof(sbuf))
1064 n = 0;
1065 if (n)
1066 write(src, sbuf, n);
1067 } else {
1068 /* simply relay the command */
1069 write(dst, rbuf, n);
1072 *state = NONE;
1073 return n;
1074 } else {
1075 /* simply relay it */
1076 *state = NONE;
1077 write(dst, rbuf, n);
1078 return n;
1081 bad:
1082 exit_failure("%s", strerror(errno));
1083 /*NOTREACHED*/
1084 return 0; /* to make gcc happy */