1 /* $KAME: ftp.c,v 1.11 2001/07/02 14:36:49 itojun Exp $ */
4 * Copyright (C) 1997 and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
31 * $FreeBSD: src/usr.sbin/faithd/ftp.c,v 1.2.2.5 2002/04/28 05:40:29 suz Exp $
32 * $DragonFly: src/usr.sbin/faithd/ftp.c,v 1.4 2003/11/16 14:10:45 eirikn Exp $
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
55 static char rbuf[MSS];
56 static char sbuf[MSS];
57 static int passivemode = 0;
58 static int wport4 = -1; /* listen() to active */
59 static int wport6 = -1; /* listen() to passive */
60 static int port4 = -1; /* active: inbound passive: outbound */
61 static int port6 = -1; /* active: outbound passive: inbound */
62 static struct sockaddr_storage data4; /* server data address */
63 static struct sockaddr_storage data6; /* client data address */
64 static int epsvall = 0;
67 enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV };
69 enum state { NONE, LPRT, EPRT, LPSV, EPSV };
72 static int ftp_activeconn(void);
73 static int ftp_passiveconn(void);
74 static int ftp_copy(int, int);
75 static int ftp_copyresult(int, int, enum state);
76 static int ftp_copycommand(int, int, enum state *);
79 ftp_relay(int ctl6, int ctl4)
83 enum state state = NONE;
86 syslog(LOG_INFO, "starting ftp control connection");
90 FD_SET(ctl4, &readfds);
91 FD_SET(ctl6, &readfds);
93 FD_SET(port4, &readfds);
95 FD_SET(port6, &readfds);
98 FD_SET(wport4, &readfds);
100 FD_SET(wport6, &readfds);
102 tv.tv_sec = FAITH_TIMEOUT;
105 error = select(256, &readfds, NULL, NULL, &tv);
107 exit_failure("select: %s", strerror(errno));
109 exit_failure("connection timeout");
112 * The order of the following checks does (slightly) matter.
113 * It is important to visit all checks (do not use "continue"),
114 * otherwise some of the pipe may become full and we cannot
117 if (FD_ISSET(ctl6, &readfds)) {
119 * copy control connection from the client.
120 * command translation is necessary.
122 error = ftp_copycommand(ctl6, ctl4, &state);
130 exit_success("terminating ftp control connection");
136 if (FD_ISSET(ctl4, &readfds)) {
138 * copy control connection from the server
139 * translation of result code is necessary.
141 error = ftp_copyresult(ctl4, ctl6, state);
149 exit_success("terminating ftp control connection");
155 if (0 <= port4 && 0 <= port6 && FD_ISSET(port4, &readfds)) {
157 * copy data connection.
158 * no special treatment necessary.
160 if (FD_ISSET(port4, &readfds))
161 error = ftp_copy(port4, port6);
169 syslog(LOG_INFO, "terminating data connection");
175 if (0 <= port4 && 0 <= port6 && FD_ISSET(port6, &readfds)) {
177 * copy data connection.
178 * no special treatment necessary.
180 if (FD_ISSET(port6, &readfds))
181 error = ftp_copy(port6, port4);
189 syslog(LOG_INFO, "terminating data connection");
196 if (wport4 && FD_ISSET(wport4, &readfds)) {
198 * establish active data connection from the server.
202 if (wport6 && FD_ISSET(wport6, &readfds)) {
204 * establish passive data connection from the client.
212 exit_failure("%s", strerror(errno));
221 struct timeval timeout;
224 /* get active connection from server */
226 FD_SET(wport4, &set);
227 timeout.tv_sec = 120;
228 timeout.tv_usec = -1;
230 if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0
231 || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) {
234 syslog(LOG_INFO, "active mode data connection failed");
238 /* ask active connection to client */
239 sa = (struct sockaddr *)&data6;
240 port6 = socket(sa->sa_family, SOCK_STREAM, 0);
245 syslog(LOG_INFO, "active mode data connection failed");
248 error = connect(port6, sa, sa->sa_len);
253 port6 = port4 = wport4 = -1;
254 syslog(LOG_INFO, "active mode data connection failed");
258 syslog(LOG_INFO, "active mode data connection established");
263 ftp_passiveconn(void)
268 struct timeval timeout;
271 /* get passive connection from client */
273 FD_SET(wport6, &set);
274 timeout.tv_sec = 120;
277 if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0
278 || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) {
281 syslog(LOG_INFO, "passive mode data connection failed");
285 /* ask passive connection to server */
286 sa = (struct sockaddr *)&data4;
287 port4 = socket(sa->sa_family, SOCK_STREAM, 0);
292 syslog(LOG_INFO, "passive mode data connection failed");
295 error = connect(port4, sa, sa->sa_len);
300 wport6 = port4 = port6 = -1;
301 syslog(LOG_INFO, "passive mode data connection failed");
305 syslog(LOG_INFO, "passive mode data connection established");
310 ftp_copy(int src, int dst)
315 /* OOB data handling */
316 error = ioctl(src, SIOCATMARK, &atmark);
317 if (error != -1 && atmark == 1) {
318 n = read(src, rbuf, 1);
321 send(dst, rbuf, n, MSG_OOB);
323 n = read(src, rbuf, sizeof(rbuf));
331 n = read(src, rbuf, sizeof(rbuf));
342 exit_failure("%s", strerror(errno));
344 return 0; /* to make gcc happy */
348 ftp_copyresult(int src, int dst, enum state state)
355 /* OOB data handling */
356 error = ioctl(src, SIOCATMARK, &atmark);
357 if (error != -1 && atmark == 1) {
358 n = read(src, rbuf, 1);
361 send(dst, rbuf, n, MSG_OOB);
363 n = read(src, rbuf, sizeof(rbuf));
371 n = read(src, rbuf, sizeof(rbuf));
384 for (i = 0; i < 3; i++) {
399 /* param points to first non-command token, if any */
400 while (*param && isspace(*param))
408 if (!passivemode && rbuf[0] == '1') {
409 if (ftp_activeconn() < 0) {
410 n = snprintf(rbuf, sizeof(rbuf),
411 "425 Cannot open data connetion\r\n");
418 /* expecting "200 PORT command successful." */
422 p = strstr(rbuf, "PORT");
424 p[0] = (state == LPRT) ? 'L' : 'E';
435 /* expecting "200 EPRT command successful." */
439 p = strstr(rbuf, "EPRT");
454 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
455 * (in some cases result comes without paren)
466 unsigned int ho[4], po[2];
467 struct sockaddr_in *sin;
468 struct sockaddr_in6 *sin6;
473 * PASV result -> LPSV/EPSV result
476 while (*p && *p != '(' && !isdigit(*p)) /*)*/
479 goto passivefail0; /*XXX*/
482 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
483 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
485 goto passivefail0; /*XXX*/
487 /* keep PORT parameter */
488 memset(&data4, 0, sizeof(data4));
489 sin = (struct sockaddr_in *)&data4;
490 sin->sin_len = sizeof(*sin);
491 sin->sin_family = AF_INET;
492 sin->sin_addr.s_addr = 0;
493 for (n = 0; n < 4; n++) {
494 sin->sin_addr.s_addr |=
495 htonl((ho[n] & 0xff) << ((3 - n) * 8));
497 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
499 /* get ready for passive data connection */
500 memset(&data6, 0, sizeof(data6));
501 sin6 = (struct sockaddr_in6 *)&data6;
502 sin6->sin6_len = sizeof(*sin6);
503 sin6->sin6_family = AF_INET6;
504 wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
507 n = snprintf(sbuf, sizeof(sbuf),
508 "500 could not translate from PASV\r\n");
515 error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
518 exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
521 error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
527 error = listen(wport6, 1);
534 /* transmit LPSV or EPSV */
536 * addr from dst, port from wport6
539 error = getsockname(wport6, (struct sockaddr *)&data6, &n);
545 sin6 = (struct sockaddr_in6 *)&data6;
546 port = sin6->sin6_port;
549 error = getsockname(dst, (struct sockaddr *)&data6, &n);
555 sin6 = (struct sockaddr_in6 *)&data6;
556 sin6->sin6_port = port;
561 a = (char *)&sin6->sin6_addr;
562 p = (char *)&sin6->sin6_port;
563 n = snprintf(sbuf, sizeof(sbuf),
564 "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",
565 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
566 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
567 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
568 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
569 2, UC(p[0]), UC(p[1]));
574 n = snprintf(sbuf, sizeof(sbuf),
575 "229 Entering Extended Passive Mode (|||%d|)\r\n",
576 ntohs(sin6->sin6_port));
584 /* expecting "229 Entering Extended Passive Mode (|||x|)" */
596 struct sockaddr_in *sin;
597 struct sockaddr_in6 *sin6;
600 * EPSV result -> PORT result
603 while (*p && *p != '(') /*)*/
606 goto passivefail1; /*XXX*/
608 n = sscanf(p, "|||%hu|", &port);
610 goto passivefail1; /*XXX*/
612 /* keep EPRT parameter */
614 error = getpeername(src, (struct sockaddr *)&data4, &n);
616 goto passivefail1; /*XXX*/
617 sin6 = (struct sockaddr_in6 *)&data4;
618 sin6->sin6_port = htons(port);
620 /* get ready for passive data connection */
621 memset(&data6, 0, sizeof(data6));
622 sin = (struct sockaddr_in *)&data6;
623 sin->sin_len = sizeof(*sin);
624 sin->sin_family = AF_INET;
625 wport6 = socket(sin->sin_family, SOCK_STREAM, 0);
628 n = snprintf(sbuf, sizeof(sbuf),
629 "500 could not translate from EPSV\r\n");
636 error = setsockopt(wport6, IPPROTO_IP, IP_FAITH,
639 exit_error("setsockopt(IP_FAITH): %s", strerror(errno));
642 error = bind(wport6, (struct sockaddr *)sin, sin->sin_len);
648 error = listen(wport6, 1);
657 * addr from dst, port from wport6
660 error = getsockname(wport6, (struct sockaddr *)&data6, &n);
666 sin = (struct sockaddr_in *)&data6;
667 port = sin->sin_port;
670 error = getsockname(dst, (struct sockaddr *)&data6, &n);
676 sin = (struct sockaddr_in *)&data6;
677 sin->sin_port = port;
682 a = (char *)&sin->sin_addr;
683 p = (char *)&sin->sin_port;
684 n = snprintf(sbuf, sizeof(sbuf),
685 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
686 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
697 exit_failure("%s", strerror(errno));
699 return 0; /* to make gcc happy */
703 ftp_copycommand(int src, int dst, enum state *state)
707 unsigned int af, hal, ho[16], pal, po[2];
710 struct sockaddr_in *sin;
711 struct sockaddr_in6 *sin6;
715 /* OOB data handling */
716 error = ioctl(src, SIOCATMARK, &atmark);
717 if (error != -1 && atmark == 1) {
718 n = read(src, rbuf, 1);
721 send(dst, rbuf, n, MSG_OOB);
723 n = read(src, rbuf, sizeof(rbuf));
731 n = read(src, rbuf, sizeof(rbuf));
750 for (i = 0; i < 4; i++) {
752 /* invalid command */
756 *q++ = islower(*p) ? toupper(*p) : *p;
760 /* invalid command */
766 /* param points to first non-command token, if any */
767 while (*param && isspace(*param))
775 if (strcmp(cmd, "LPRT") == 0 && param) {
785 wport4 = wport6 = port4 = port6 = -1;
788 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
795 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
796 &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
797 &ho[4], &ho[5], &ho[6], &ho[7],
798 &ho[8], &ho[9], &ho[10], &ho[11],
799 &ho[12], &ho[13], &ho[14], &ho[15],
800 &pal, &po[0], &po[1]);
801 if (n != 21 || af != 6 || hal != 16|| pal != 2) {
802 n = snprintf(sbuf, sizeof(sbuf),
803 "501 illegal parameter to LPRT\r\n");
808 /* keep LPRT parameter */
809 memset(&data6, 0, sizeof(data6));
810 sin6 = (struct sockaddr_in6 *)&data6;
811 sin6->sin6_len = sizeof(*sin6);
812 sin6->sin6_family = AF_INET6;
813 for (n = 0; n < 16; n++)
814 sin6->sin6_addr.s6_addr[n] = ho[n];
815 sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
818 /* get ready for active data connection */
820 error = getsockname(dst, (struct sockaddr *)&data4, &n);
823 n = snprintf(sbuf, sizeof(sbuf),
824 "500 could not translate to PORT\r\n");
828 if (((struct sockaddr *)&data4)->sa_family != AF_INET)
830 sin = (struct sockaddr_in *)&data4;
832 wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
835 error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
841 error = listen(wport4, 1);
850 error = getsockname(wport4, (struct sockaddr *)&data4, &n);
856 if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
861 sin = (struct sockaddr_in *)&data4;
862 a = (char *)&sin->sin_addr;
863 p = (char *)&sin->sin_port;
864 n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
865 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
871 } else if (strcmp(cmd, "EPRT") == 0 && param) {
875 char *afp, *hostp, *portp;
876 struct addrinfo hints, *res;
884 wport4 = wport6 = port4 = port6 = -1;
887 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
894 ch = *p++; /* boundary character */
896 while (*p && *p != ch)
900 n = snprintf(sbuf, sizeof(sbuf),
901 "501 illegal parameter to EPRT\r\n");
907 while (*p && *p != ch)
913 while (*p && *p != ch)
919 n = sscanf(afp, "%d", &af);
920 if (n != 1 || af != 2) {
921 n = snprintf(sbuf, sizeof(sbuf),
922 "501 unsupported address family to EPRT\r\n");
926 memset(&hints, 0, sizeof(hints));
927 hints.ai_family = AF_UNSPEC;
928 hints.ai_socktype = SOCK_STREAM;
929 error = getaddrinfo(hostp, portp, &hints, &res);
931 n = snprintf(sbuf, sizeof(sbuf),
932 "501 EPRT: %s\r\n", gai_strerror(error));
937 n = snprintf(sbuf, sizeof(sbuf),
938 "501 EPRT: %s resolved to multiple addresses\r\n", hostp);
943 memcpy(&data6, res->ai_addr, res->ai_addrlen);
946 } else if (strcmp(cmd, "LPSV") == 0 && !param) {
956 wport4 = wport6 = port4 = port6 = -1;
959 n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
966 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
969 passivemode = 0; /* to be set to 1 later */
971 } else if (strcmp(cmd, "EPSV") == 0 && !param) {
979 wport4 = wport6 = port4 = port6 = -1;
981 n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
984 passivemode = 0; /* to be set to 1 later */
986 } else if (strcmp(cmd, "EPSV") == 0 && param
987 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
992 n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
996 } else if (strcmp(cmd, "PORT") == 0 && param) {
1000 char host[NI_MAXHOST], serv[NI_MAXSERV];
1008 wport4 = wport6 = port4 = port6 = -1;
1011 n = sscanf(p, "%u,%u,%u,%u,%u,%u",
1012 &ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
1014 n = snprintf(sbuf, sizeof(sbuf),
1015 "501 illegal parameter to PORT\r\n");
1016 write(src, sbuf, n);
1020 memset(&data6, 0, sizeof(data6));
1021 sin = (struct sockaddr_in *)&data6;
1022 sin->sin_len = sizeof(*sin);
1023 sin->sin_family = AF_INET;
1024 sin->sin_addr.s_addr = htonl(
1025 ((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) |
1026 ((ho[2] & 0xff) << 8) | (ho[3] & 0xff));
1027 sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
1029 /* get ready for active data connection */
1031 error = getsockname(dst, (struct sockaddr *)&data4, &n);
1034 n = snprintf(sbuf, sizeof(sbuf),
1035 "500 could not translate to EPRT\r\n");
1036 write(src, sbuf, n);
1039 if (((struct sockaddr *)&data4)->sa_family != AF_INET6)
1042 ((struct sockaddr_in6 *)&data4)->sin6_port = 0;
1043 sa = (struct sockaddr *)&data4;
1044 wport4 = socket(sa->sa_family, SOCK_STREAM, 0);
1047 error = bind(wport4, sa, sa->sa_len);
1053 error = listen(wport4, 1);
1062 error = getsockname(wport4, (struct sockaddr *)&data4, &n);
1069 sa = (struct sockaddr *)&data4;
1070 if (getnameinfo(sa, sa->sa_len, host, sizeof(host),
1071 serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) {
1076 n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv);
1077 write(dst, sbuf, n);
1081 } else if (strcmp(cmd, "PASV") == 0 && !param) {
1092 wport4 = wport6 = port4 = port6 = -1;
1095 n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n");
1096 write(dst, sbuf, n);
1098 passivemode = 0; /* to be set to 1 later */
1101 } else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
1105 n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
1106 write(src, sbuf, n);
1109 } else if (passivemode
1110 && (strcmp(cmd, "STOR") == 0
1111 || strcmp(cmd, "STOU") == 0
1112 || strcmp(cmd, "RETR") == 0
1113 || strcmp(cmd, "LIST") == 0
1114 || strcmp(cmd, "NLST") == 0
1115 || strcmp(cmd, "APPE") == 0)) {
1117 * commands with data transfer. need to care about passive
1118 * mode data connection.
1121 if (ftp_passiveconn() < 0) {
1122 n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
1123 write(src, sbuf, n);
1125 /* simply relay the command */
1126 write(dst, rbuf, n);
1132 /* simply relay it */
1134 write(dst, rbuf, n);
1139 exit_failure("%s", strerror(errno));
1141 return 0; /* to make gcc happy */