Home | History | Annotate | Line # | Download | only in faithd
ftp.c revision 1.7
      1 /*	$NetBSD: ftp.c,v 1.7 2001/09/05 01:22:24 itojun Exp $	*/
      2 /*	$KAME: ftp.c,v 1.13 2001/09/05 01:10: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 #ifdef FAITH4
     65 enum state { NONE, LPRT, EPRT, PORT, LPSV, EPSV, PASV };
     66 #else
     67 enum state { NONE, LPRT, EPRT, LPSV, EPSV };
     68 #endif
     69 
     70 static int ftp_activeconn __P((void));
     71 static int ftp_passiveconn __P((void));
     72 static int ftp_copy __P((int, int));
     73 static int ftp_copyresult __P((int, int, enum state));
     74 static int ftp_copycommand __P((int, int, enum state *));
     75 
     76 void
     77 ftp_relay(int ctl6, int ctl4)
     78 {
     79 	fd_set readfds;
     80 	int error;
     81 	enum state state = NONE;
     82 	struct timeval tv;
     83 
     84 	syslog(LOG_INFO, "starting ftp control connection");
     85 
     86 	for (;;) {
     87 		int maxfd = 0;
     88 
     89 		FD_ZERO(&readfds);
     90 		FD_SET(ctl4, &readfds);
     91 		FD_SET(ctl6, &readfds);
     92 		if (0 <= port4) {
     93 			FD_SET(port4, &readfds);
     94 			if (port4 > maxfd)
     95 				maxfd = port4;
     96 		}
     97 		if (0 <= port6) {
     98 			FD_SET(port6, &readfds);
     99 			if (port6 > maxfd)
    100 				maxfd = port6;
    101 		}
    102 #if 0
    103 		if (0 <= wport4) {
    104 			FD_SET(wport4, &readfds);
    105 			if (wport4 > maxfd)
    106 				maxfd = wport4;
    107 		}
    108 		if (0 <= wport6) {
    109 			FD_SET(wport6, &readfds);
    110 			if (wport6 > maxfd)
    111 				maxfd = wport6;
    112 		}
    113 #endif
    114 		tv.tv_sec = FAITH_TIMEOUT;
    115 		tv.tv_usec = 0;
    116 
    117 		error = select(maxfd + 1, &readfds, NULL, NULL, &tv);
    118 		if (error == -1)
    119 			exit_failure("select: %s", strerror(errno));
    120 		else if (error == 0)
    121 			exit_failure("connection timeout");
    122 
    123 		/*
    124 		 * The order of the following checks does (slightly) matter.
    125 		 * It is important to visit all checks (do not use "continue"),
    126 		 * otherwise some of the pipe may become full and we cannot
    127 		 * relay correctly.
    128 		 */
    129 		if (FD_ISSET(ctl6, &readfds)) {
    130 			/*
    131 			 * copy control connection from the client.
    132 			 * command translation is necessary.
    133 			 */
    134 			error = ftp_copycommand(ctl6, ctl4, &state);
    135 
    136 			switch (error) {
    137 			case -1:
    138 				goto bad;
    139 			case 0:
    140 				close(ctl4);
    141 				close(ctl6);
    142 				exit_success("terminating ftp control connection");
    143 				/*NOTREACHED*/
    144 			default:
    145 				break;
    146 			}
    147 		}
    148 		if (FD_ISSET(ctl4, &readfds)) {
    149 			/*
    150 			 * copy control connection from the server
    151 			 * translation of result code is necessary.
    152 			 */
    153 			error = ftp_copyresult(ctl4, ctl6, state);
    154 
    155 			switch (error) {
    156 			case -1:
    157 				goto bad;
    158 			case 0:
    159 				close(ctl4);
    160 				close(ctl6);
    161 				exit_success("terminating ftp control connection");
    162 				/*NOTREACHED*/
    163 			default:
    164 				break;
    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 	FD_SET(wport4, &set);
    239 	timeout.tv_sec = 120;
    240 	timeout.tv_usec = -1;
    241 	n = sizeof(data4);
    242 	if (select(wport4 + 1, &set, NULL, NULL, &timeout) == 0
    243 	 || (port4 = accept(wport4, (struct sockaddr *)&data4, &n)) < 0) {
    244 		close(wport4);
    245 		wport4 = -1;
    246 		syslog(LOG_INFO, "active mode data connection failed");
    247 		return -1;
    248 	}
    249 
    250 	/* ask active connection to client */
    251 	sa = (struct sockaddr *)&data6;
    252 	port6 = socket(sa->sa_family, SOCK_STREAM, 0);
    253 	if (port6 == -1) {
    254 		close(port4);
    255 		close(wport4);
    256 		port4 = wport4 = -1;
    257 		syslog(LOG_INFO, "active mode data connection failed");
    258 		return -1;
    259 	}
    260 	error = connect(port6, sa, sa->sa_len);
    261 	if (port6 == -1) {
    262 		close(port6);
    263 		close(port4);
    264 		close(wport4);
    265 		port6 = port4 = wport4 = -1;
    266 		syslog(LOG_INFO, "active mode data connection failed");
    267 		return -1;
    268 	}
    269 
    270 	syslog(LOG_INFO, "active mode data connection established");
    271 	return 0;
    272 }
    273 
    274 static int
    275 ftp_passiveconn()
    276 {
    277 	int n;
    278 	int error;
    279 	fd_set set;
    280 	struct timeval timeout;
    281 	struct sockaddr *sa;
    282 
    283 	/* get passive connection from client */
    284 	FD_ZERO(&set);
    285 	FD_SET(wport6, &set);
    286 	timeout.tv_sec = 120;
    287 	timeout.tv_usec = 0;
    288 	n = sizeof(data6);
    289 	if (select(wport6 + 1, &set, NULL, NULL, &timeout) == 0
    290 	 || (port6 = accept(wport6, (struct sockaddr *)&data6, &n)) < 0) {
    291 		close(wport6);
    292 		wport6 = -1;
    293 		syslog(LOG_INFO, "passive mode data connection failed");
    294 		return -1;
    295 	}
    296 
    297 	/* ask passive connection to server */
    298 	sa = (struct sockaddr *)&data4;
    299 	port4 = socket(sa->sa_family, SOCK_STREAM, 0);
    300 	if (port4 == -1) {
    301 		close(wport6);
    302 		close(port6);
    303 		wport6 = port6 = -1;
    304 		syslog(LOG_INFO, "passive mode data connection failed");
    305 		return -1;
    306 	}
    307 	error = connect(port4, sa, sa->sa_len);
    308 	if (port4 == -1) {
    309 		close(wport6);
    310 		close(port4);
    311 		close(port6);
    312 		wport6 = port4 = port6 = -1;
    313 		syslog(LOG_INFO, "passive mode data connection failed");
    314 		return -1;
    315 	}
    316 
    317 	syslog(LOG_INFO, "passive mode data connection established");
    318 	return 0;
    319 }
    320 
    321 static int
    322 ftp_copy(int src, int dst)
    323 {
    324 	int error, atmark;
    325 	int n;
    326 
    327 	/* OOB data handling */
    328 	error = ioctl(src, SIOCATMARK, &atmark);
    329 	if (error != -1 && atmark == 1) {
    330 		n = read(src, rbuf, 1);
    331 		if (n == -1)
    332 			goto bad;
    333 		send(dst, rbuf, n, MSG_OOB);
    334 #if 0
    335 		n = read(src, rbuf, sizeof(rbuf));
    336 		if (n == -1)
    337 			goto bad;
    338 		write(dst, rbuf, n);
    339 		return n;
    340 #endif
    341 	}
    342 
    343 	n = read(src, rbuf, sizeof(rbuf));
    344 	switch (n) {
    345 	case -1:
    346 	case 0:
    347 		return n;
    348 	default:
    349 		write(dst, rbuf, n);
    350 		return n;
    351 	}
    352 
    353  bad:
    354 	exit_failure("%s", strerror(errno));
    355 	/*NOTREACHED*/
    356 	return 0;	/* to make gcc happy */
    357 }
    358 
    359 static int
    360 ftp_copyresult(int src, int dst, enum state state)
    361 {
    362 	int error, atmark;
    363 	int n;
    364 	char *param;
    365 	int code;
    366 	char *a, *p;
    367 	int i;
    368 
    369 	/* OOB data handling */
    370 	error = ioctl(src, SIOCATMARK, &atmark);
    371 	if (error != -1 && atmark == 1) {
    372 		n = read(src, rbuf, 1);
    373 		if (n == -1)
    374 			goto bad;
    375 		send(dst, rbuf, n, MSG_OOB);
    376 #if 0
    377 		n = read(src, rbuf, sizeof(rbuf));
    378 		if (n == -1)
    379 			goto bad;
    380 		write(dst, rbuf, n);
    381 		return n;
    382 #endif
    383 	}
    384 
    385 	n = read(src, rbuf, sizeof(rbuf));
    386 	if (n <= 0)
    387 		return n;
    388 	rbuf[n] = '\0';
    389 
    390 	/*
    391 	 * parse argument
    392 	 */
    393 	p = rbuf;
    394 	for (i = 0; i < 3; i++) {
    395 		if (!isdigit(*p)) {
    396 			/* invalid reply */
    397 			write(dst, rbuf, n);
    398 			return n;
    399 		}
    400 		p++;
    401 	}
    402 	if (!isspace(*p)) {
    403 		/* invalid reply */
    404 		write(dst, rbuf, n);
    405 		return n;
    406 	}
    407 	code = atoi(rbuf);
    408 	param = p;
    409 	/* param points to first non-command token, if any */
    410 	while (*param && isspace(*param))
    411 		param++;
    412 	if (!*param)
    413 		param = NULL;
    414 
    415 	switch (state) {
    416 	case NONE:
    417 		if (!passivemode && rbuf[0] == '1') {
    418 			if (ftp_activeconn() < 0) {
    419 				n = snprintf(rbuf, sizeof(rbuf),
    420 					"425 Cannot open data connetion\r\n");
    421 				if (n < 0 || n >= sizeof(rbuf))
    422 					n = 0;
    423 			}
    424 		}
    425 		if (n)
    426 			write(dst, rbuf, n);
    427 		return n;
    428 	case LPRT:
    429 	case EPRT:
    430 		/* expecting "200 PORT command successful." */
    431 		if (code == 200) {
    432 			p = strstr(rbuf, "PORT");
    433 			if (p) {
    434 				p[0] = (state == LPRT) ? 'L' : 'E';
    435 				p[1] = 'P';
    436 			}
    437 		} else {
    438 			close(wport4);
    439 			wport4 = -1;
    440 		}
    441 		write(dst, rbuf, n);
    442 		return n;
    443 #ifdef FAITH4
    444 	case PORT:
    445 		/* expecting "200 EPRT command successful." */
    446 		if (code == 200) {
    447 			p = strstr(rbuf, "EPRT");
    448 			if (p) {
    449 				p[0] = 'P';
    450 				p[1] = 'O';
    451 			}
    452 		} else {
    453 			close(wport4);
    454 			wport4 = -1;
    455 		}
    456 		write(dst, rbuf, n);
    457 		return n;
    458 #endif
    459 	case LPSV:
    460 	case EPSV:
    461 		/*
    462 		 * expecting "227 Entering Passive Mode (x,x,x,x,x,x,x)"
    463 		 * (in some cases result comes without paren)
    464 		 */
    465 		if (code != 227) {
    466 passivefail0:
    467 			close(wport6);
    468 			wport6 = -1;
    469 			write(dst, rbuf, n);
    470 			return n;
    471 		}
    472 
    473 	    {
    474 		unsigned int ho[4], po[2];
    475 		struct sockaddr_in *sin;
    476 		struct sockaddr_in6 *sin6;
    477 		u_short port;
    478 
    479 		/*
    480 		 * PASV result -> LPSV/EPSV result
    481 		 */
    482 		p = param;
    483 		while (*p && *p != '(' && !isdigit(*p))	/*)*/
    484 			p++;
    485 		if (!*p)
    486 			goto passivefail0;	/*XXX*/
    487 		if (*p == '(')	/*)*/
    488 			p++;
    489 		n = sscanf(p, "%u,%u,%u,%u,%u,%u",
    490 			&ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
    491 		if (n != 6)
    492 			goto passivefail0;	/*XXX*/
    493 
    494 		/* keep PORT parameter */
    495 		memset(&data4, 0, sizeof(data4));
    496 		sin = (struct sockaddr_in *)&data4;
    497 		sin->sin_len = sizeof(*sin);
    498 		sin->sin_family = AF_INET;
    499 		sin->sin_addr.s_addr = 0;
    500 		for (n = 0; n < 4; n++) {
    501 			sin->sin_addr.s_addr |=
    502 				htonl((ho[n] & 0xff) << ((3 - n) * 8));
    503 		}
    504 		sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
    505 
    506 		/* get ready for passive data connection */
    507 		memset(&data6, 0, sizeof(data6));
    508 		sin6 = (struct sockaddr_in6 *)&data6;
    509 		sin6->sin6_len = sizeof(*sin6);
    510 		sin6->sin6_family = AF_INET6;
    511 		wport6 = socket(sin6->sin6_family, SOCK_STREAM, 0);
    512 		if (wport6 == -1) {
    513 passivefail:
    514 			n = snprintf(sbuf, sizeof(sbuf),
    515 				"500 could not translate from PASV\r\n");
    516 			if (n < 0 || n >= sizeof(sbuf))
    517 			if (n)
    518 				write(src, sbuf, n);
    519 			return n;
    520 		}
    521 #ifdef IPV6_FAITH
    522 	    {
    523 		int on = 1;
    524 		error = setsockopt(wport6, IPPROTO_IPV6, IPV6_FAITH,
    525 			&on, sizeof(on));
    526 		if (error == -1)
    527 			exit_failure("setsockopt(IPV6_FAITH): %s", strerror(errno));
    528 	    }
    529 #endif
    530 		error = bind(wport6, (struct sockaddr *)sin6, sin6->sin6_len);
    531 		if (error == -1) {
    532 			close(wport6);
    533 			wport6 = -1;
    534 			goto passivefail;
    535 		}
    536 		error = listen(wport6, 1);
    537 		if (error == -1) {
    538 			close(wport6);
    539 			wport6 = -1;
    540 			goto passivefail;
    541 		}
    542 
    543 		/* transmit LPSV or EPSV */
    544 		/*
    545 		 * addr from dst, port from wport6
    546 		 */
    547 		n = sizeof(data6);
    548 		error = getsockname(wport6, (struct sockaddr *)&data6, &n);
    549 		if (error == -1) {
    550 			close(wport6);
    551 			wport6 = -1;
    552 			goto passivefail;
    553 		}
    554 		sin6 = (struct sockaddr_in6 *)&data6;
    555 		port = sin6->sin6_port;
    556 
    557 		n = sizeof(data6);
    558 		error = getsockname(dst, (struct sockaddr *)&data6, &n);
    559 		if (error == -1) {
    560 			close(wport6);
    561 			wport6 = -1;
    562 			goto passivefail;
    563 		}
    564 		sin6 = (struct sockaddr_in6 *)&data6;
    565 		sin6->sin6_port = port;
    566 
    567 		if (state == LPSV) {
    568 			a = (char *)&sin6->sin6_addr;
    569 			p = (char *)&sin6->sin6_port;
    570 			n = snprintf(sbuf, sizeof(sbuf),
    571 "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",
    572 				6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
    573 				UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
    574 				UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
    575 				UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
    576 				2, UC(p[0]), UC(p[1]));
    577 			if (n < 0 || n >= sizeof(sbuf))
    578 				n = 0;
    579 			if (n)
    580 				write(dst, sbuf, n);
    581 			passivemode = 1;
    582 			return n;
    583 		} else {
    584 			n = snprintf(sbuf, sizeof(sbuf),
    585 "229 Entering Extended Passive Mode (|||%d|)\r\n",
    586 				ntohs(sin6->sin6_port));
    587 			if (n < 0 || n >= sizeof(sbuf))
    588 				n = 0;
    589 			if (n)
    590 				write(dst, sbuf, n);
    591 			passivemode = 1;
    592 			return n;
    593 		}
    594 	    }
    595 #ifdef FAITH4
    596 	case PASV:
    597 		/* expecting "229 Entering Extended Passive Mode (|||x|)" */
    598 		if (code != 229) {
    599 passivefail1:
    600 			close(wport6);
    601 			wport6 = -1;
    602 			write(dst, rbuf, n);
    603 			return n;
    604 		}
    605 
    606 	    {
    607 		u_short port;
    608 		struct sockaddr_in *sin;
    609 		struct sockaddr_in6 *sin6;
    610 
    611 		/*
    612 		 * EPSV result -> PORT result
    613 		 */
    614 		p = param;
    615 		while (*p && *p != '(')	/*)*/
    616 			p++;
    617 		if (!*p)
    618 			goto passivefail1;	/*XXX*/
    619 		p++;
    620 		n = sscanf(p, "|||%hu|", &port);
    621 		if (n != 1)
    622 			goto passivefail1;	/*XXX*/
    623 
    624 		/* keep EPRT parameter */
    625 		n = sizeof(data4);
    626 		error = getpeername(src, (struct sockaddr *)&data4, &n);
    627 		if (error == -1)
    628 			goto passivefail1;	/*XXX*/
    629 		sin6 = (struct sockaddr_in6 *)&data4;
    630 		sin6->sin6_port = htons(port);
    631 
    632 		/* get ready for passive data connection */
    633 		memset(&data6, 0, sizeof(data6));
    634 		sin = (struct sockaddr_in *)&data6;
    635 		sin->sin_len = sizeof(*sin);
    636 		sin->sin_family = AF_INET;
    637 		wport6 = socket(sin->sin_family, SOCK_STREAM, 0);
    638 		if (wport6 == -1) {
    639 passivefail2:
    640 			n = snprintf(sbuf, sizeof(sbuf),
    641 				"500 could not translate from EPSV\r\n");
    642 			if (n < 0 || n >= sizeof(sbuf))
    643 				n = 0;
    644 			if (n)
    645 				write(src, sbuf, n);
    646 			return n;
    647 		}
    648 #ifdef IP_FAITH
    649 	    {
    650 		int on = 1;
    651 		error = setsockopt(wport6, IPPROTO_IP, IP_FAITH,
    652 			&on, sizeof(on));
    653 		if (error == -1)
    654 			exit_error("setsockopt(IP_FAITH): %s", strerror(errno));
    655 	    }
    656 #endif
    657 		error = bind(wport6, (struct sockaddr *)sin, sin->sin_len);
    658 		if (error == -1) {
    659 			close(wport6);
    660 			wport6 = -1;
    661 			goto passivefail2;
    662 		}
    663 		error = listen(wport6, 1);
    664 		if (error == -1) {
    665 			close(wport6);
    666 			wport6 = -1;
    667 			goto passivefail2;
    668 		}
    669 
    670 		/* transmit PORT */
    671 		/*
    672 		 * addr from dst, port from wport6
    673 		 */
    674 		n = sizeof(data6);
    675 		error = getsockname(wport6, (struct sockaddr *)&data6, &n);
    676 		if (error == -1) {
    677 			close(wport6);
    678 			wport6 = -1;
    679 			goto passivefail2;
    680 		}
    681 		sin = (struct sockaddr_in *)&data6;
    682 		port = sin->sin_port;
    683 
    684 		n = sizeof(data6);
    685 		error = getsockname(dst, (struct sockaddr *)&data6, &n);
    686 		if (error == -1) {
    687 			close(wport6);
    688 			wport6 = -1;
    689 			goto passivefail2;
    690 		}
    691 		sin = (struct sockaddr_in *)&data6;
    692 		sin->sin_port = port;
    693 
    694 		{
    695 			char *a, *p;
    696 
    697 			a = (char *)&sin->sin_addr;
    698 			p = (char *)&sin->sin_port;
    699 			n = snprintf(sbuf, sizeof(sbuf),
    700 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
    701 				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
    702 				UC(p[0]), UC(p[1]));
    703 			if (n < 0 || n >= sizeof(sbuf))
    704 				n = 0;
    705 			if (n)
    706 				write(dst, sbuf, n);
    707 			passivemode = 1;
    708 			return n;
    709 		}
    710 	    }
    711 #endif /* FAITH4 */
    712 	}
    713 
    714  bad:
    715 	exit_failure("%s", strerror(errno));
    716 	/*NOTREACHED*/
    717 	return 0;	/* to make gcc happy */
    718 }
    719 
    720 static int
    721 ftp_copycommand(int src, int dst, enum state *state)
    722 {
    723 	int error, atmark;
    724 	int n;
    725 	unsigned int af, hal, ho[16], pal, po[2];
    726 	char *a, *p, *q;
    727 	char cmd[5], *param;
    728 	struct sockaddr_in *sin;
    729 	struct sockaddr_in6 *sin6;
    730 	enum state nstate;
    731 	char ch;
    732 	int i;
    733 
    734 	/* OOB data handling */
    735 	error = ioctl(src, SIOCATMARK, &atmark);
    736 	if (error != -1 && atmark == 1) {
    737 		n = read(src, rbuf, 1);
    738 		if (n == -1)
    739 			goto bad;
    740 		send(dst, rbuf, n, MSG_OOB);
    741 #if 0
    742 		n = read(src, rbuf, sizeof(rbuf));
    743 		if (n == -1)
    744 			goto bad;
    745 		write(dst, rbuf, n);
    746 		return n;
    747 #endif
    748 	}
    749 
    750 	n = read(src, rbuf, sizeof(rbuf));
    751 	if (n <= 0)
    752 		return n;
    753 	rbuf[n] = '\0';
    754 
    755 	if (n < 4) {
    756 		write(dst, rbuf, n);
    757 		return n;
    758 	}
    759 
    760 	/*
    761 	 * parse argument
    762 	 */
    763 	p = rbuf;
    764 	q = cmd;
    765 	for (i = 0; i < 4; i++) {
    766 		if (!isalpha(*p)) {
    767 			/* invalid command */
    768 			write(dst, rbuf, n);
    769 			return n;
    770 		}
    771 		*q++ = islower(*p) ? toupper(*p) : *p;
    772 		p++;
    773 	}
    774 	if (!isspace(*p)) {
    775 		/* invalid command */
    776 		write(dst, rbuf, n);
    777 		return n;
    778 	}
    779 	*q = '\0';
    780 	param = p;
    781 	/* param points to first non-command token, if any */
    782 	while (*param && isspace(*param))
    783 		param++;
    784 	if (!*param)
    785 		param = NULL;
    786 
    787 	*state = NONE;
    788 
    789 	if (strcmp(cmd, "LPRT") == 0 && param) {
    790 		/*
    791 		 * LPRT -> PORT
    792 		 */
    793 		nstate = LPRT;
    794 
    795 		close(wport4);
    796 		close(wport6);
    797 		close(port4);
    798 		close(port6);
    799 		wport4 = wport6 = port4 = port6 = -1;
    800 
    801 		if (epsvall) {
    802 			n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
    803 				cmd);
    804 			if (n < 0 || n >= sizeof(sbuf))
    805 				n = 0;
    806 			if (n)
    807 				write(src, sbuf, n);
    808 			return n;
    809 		}
    810 
    811 		n = sscanf(param,
    812 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
    813 			      &af, &hal, &ho[0], &ho[1], &ho[2], &ho[3],
    814 			      &ho[4], &ho[5], &ho[6], &ho[7],
    815 			      &ho[8], &ho[9], &ho[10], &ho[11],
    816 			      &ho[12], &ho[13], &ho[14], &ho[15],
    817 			      &pal, &po[0], &po[1]);
    818 		if (n != 21 || af != 6 || hal != 16|| pal != 2) {
    819 			n = snprintf(sbuf, sizeof(sbuf),
    820 				"501 illegal parameter to LPRT\r\n");
    821 			if (n < 0 || n >= sizeof(sbuf))
    822 				n = 0;
    823 			if (n)
    824 				write(src, sbuf, n);
    825 			return n;
    826 		}
    827 
    828 		/* keep LPRT parameter */
    829 		memset(&data6, 0, sizeof(data6));
    830 		sin6 = (struct sockaddr_in6 *)&data6;
    831 		sin6->sin6_len = sizeof(*sin6);
    832 		sin6->sin6_family = AF_INET6;
    833 		for (n = 0; n < 16; n++)
    834 			sin6->sin6_addr.s6_addr[n] = ho[n];
    835 		sin6->sin6_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
    836 
    837 sendport:
    838 		/* get ready for active data connection */
    839 		n = sizeof(data4);
    840 		error = getsockname(dst, (struct sockaddr *)&data4, &n);
    841 		if (error == -1) {
    842 lprtfail:
    843 			n = snprintf(sbuf, sizeof(sbuf),
    844 				"500 could not translate to PORT\r\n");
    845 			if (n < 0 || n >= sizeof(sbuf))
    846 				n = 0;
    847 			if (n)
    848 				write(src, sbuf, n);
    849 			return n;
    850 		}
    851 		if (((struct sockaddr *)&data4)->sa_family != AF_INET)
    852 			goto lprtfail;
    853 		sin = (struct sockaddr_in *)&data4;
    854 		sin->sin_port = 0;
    855 		wport4 = socket(sin->sin_family, SOCK_STREAM, 0);
    856 		if (wport4 == -1)
    857 			goto lprtfail;
    858 		error = bind(wport4, (struct sockaddr *)sin, sin->sin_len);
    859 		if (error == -1) {
    860 			close(wport4);
    861 			wport4 = -1;
    862 			goto lprtfail;
    863 		}
    864 		error = listen(wport4, 1);
    865 		if (error == -1) {
    866 			close(wport4);
    867 			wport4 = -1;
    868 			goto lprtfail;
    869 		}
    870 
    871 		/* transmit PORT */
    872 		n = sizeof(data4);
    873 		error = getsockname(wport4, (struct sockaddr *)&data4, &n);
    874 		if (error == -1) {
    875 			close(wport4);
    876 			wport4 = -1;
    877 			goto lprtfail;
    878 		}
    879 		if (((struct sockaddr *)&data4)->sa_family != AF_INET) {
    880 			close(wport4);
    881 			wport4 = -1;
    882 			goto lprtfail;
    883 		}
    884 		sin = (struct sockaddr_in *)&data4;
    885 		a = (char *)&sin->sin_addr;
    886 		p = (char *)&sin->sin_port;
    887 		n = snprintf(sbuf, sizeof(sbuf), "PORT %d,%d,%d,%d,%d,%d\r\n",
    888 				  UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
    889 				  UC(p[0]), UC(p[1]));
    890 		if (n < 0 || n >= sizeof(sbuf))
    891 			n = 0;
    892 		if (n)
    893 			write(dst, sbuf, n);
    894 		*state = nstate;
    895 		passivemode = 0;
    896 		return n;
    897 	} else if (strcmp(cmd, "EPRT") == 0 && param) {
    898 		/*
    899 		 * EPRT -> PORT
    900 		 */
    901 		char *afp, *hostp, *portp;
    902 		struct addrinfo hints, *res;
    903 
    904 		nstate = EPRT;
    905 
    906 		close(wport4);
    907 		close(wport6);
    908 		close(port4);
    909 		close(port6);
    910 		wport4 = wport6 = port4 = port6 = -1;
    911 
    912 		if (epsvall) {
    913 			n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
    914 				cmd);
    915 			if (n < 0 || n >= sizeof(sbuf))
    916 				n = 0;
    917 			if (n)
    918 				write(src, sbuf, n);
    919 			return n;
    920 		}
    921 
    922 		p = param;
    923 		ch = *p++;	/* boundary character */
    924 		afp = p;
    925 		while (*p && *p != ch)
    926 			p++;
    927 		if (!*p) {
    928 eprtparamfail:
    929 			n = snprintf(sbuf, sizeof(sbuf),
    930 				"501 illegal parameter to EPRT\r\n");
    931 			if (n < 0 || n >= sizeof(sbuf))
    932 				n = 0;
    933 			if (n)
    934 				write(src, sbuf, n);
    935 			return n;
    936 		}
    937 		*p++ = '\0';
    938 		hostp = p;
    939 		while (*p && *p != ch)
    940 			p++;
    941 		if (!*p)
    942 			goto eprtparamfail;
    943 		*p++ = '\0';
    944 		portp = p;
    945 		while (*p && *p != ch)
    946 			p++;
    947 		if (!*p)
    948 			goto eprtparamfail;
    949 		*p++ = '\0';
    950 
    951 		n = sscanf(afp, "%d", &af);
    952 		if (n != 1 || af != 2) {
    953 			n = snprintf(sbuf, sizeof(sbuf),
    954 				"501 unsupported address family to EPRT\r\n");
    955 			if (n < 0 || n >= sizeof(sbuf))
    956 				n = 0;
    957 			if (n)
    958 				write(src, sbuf, n);
    959 			return n;
    960 		}
    961 		memset(&hints, 0, sizeof(hints));
    962 		hints.ai_family = AF_UNSPEC;
    963 		hints.ai_socktype = SOCK_STREAM;
    964 		error = getaddrinfo(hostp, portp, &hints, &res);
    965 		if (error) {
    966 			n = snprintf(sbuf, sizeof(sbuf),
    967 				"501 EPRT: %s\r\n", gai_strerror(error));
    968 			if (n < 0 || n >= sizeof(sbuf))
    969 				n = 0;
    970 			if (n)
    971 				write(src, sbuf, n);
    972 			return n;
    973 		}
    974 		if (res->ai_next) {
    975 			n = snprintf(sbuf, sizeof(sbuf),
    976 				"501 EPRT: %s resolved to multiple addresses\r\n", hostp);
    977 			if (n < 0 || n >= sizeof(sbuf))
    978 				n = 0;
    979 			if (n)
    980 				write(src, sbuf, n);
    981 			return n;
    982 		}
    983 
    984 		memcpy(&data6, res->ai_addr, res->ai_addrlen);
    985 
    986 		goto sendport;
    987 	} else if (strcmp(cmd, "LPSV") == 0 && !param) {
    988 		/*
    989 		 * LPSV -> PASV
    990 		 */
    991 		nstate = LPSV;
    992 
    993 		close(wport4);
    994 		close(wport6);
    995 		close(port4);
    996 		close(port6);
    997 		wport4 = wport6 = port4 = port6 = -1;
    998 
    999 		if (epsvall) {
   1000 			n = snprintf(sbuf, sizeof(sbuf), "501 %s disallowed in EPSV ALL\r\n",
   1001 				cmd);
   1002 			if (n < 0 || n >= sizeof(sbuf))
   1003 				n = 0;
   1004 			if (n)
   1005 				write(src, sbuf, n);
   1006 			return n;
   1007 		}
   1008 
   1009 		/* transmit PASV */
   1010 		n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
   1011 		if (n < 0 || n >= sizeof(sbuf))
   1012 			n = 0;
   1013 		if (n)
   1014 			write(dst, sbuf, n);
   1015 		*state = LPSV;
   1016 		passivemode = 0;	/* to be set to 1 later */
   1017 		return n;
   1018 	} else if (strcmp(cmd, "EPSV") == 0 && !param) {
   1019 		/*
   1020 		 * EPSV -> PASV
   1021 		 */
   1022 		close(wport4);
   1023 		close(wport6);
   1024 		close(port4);
   1025 		close(port6);
   1026 		wport4 = wport6 = port4 = port6 = -1;
   1027 
   1028 		n = snprintf(sbuf, sizeof(sbuf), "PASV\r\n");
   1029 		if (n < 0 || n >= sizeof(sbuf))
   1030 			n = 0;
   1031 		if (n)
   1032 			write(dst, sbuf, n);
   1033 		*state = EPSV;
   1034 		passivemode = 0;	/* to be set to 1 later */
   1035 		return n;
   1036 	} else if (strcmp(cmd, "EPSV") == 0 && param
   1037 	 && strncasecmp(param, "ALL", 3) == 0 && isspace(param[3])) {
   1038 		/*
   1039 		 * EPSV ALL
   1040 		 */
   1041 		epsvall = 1;
   1042 		n = snprintf(sbuf, sizeof(sbuf), "200 EPSV ALL command successful.\r\n");
   1043 		if (n < 0 || n >= sizeof(sbuf))
   1044 			n = 0;
   1045 		if (n)
   1046 			write(src, sbuf, n);
   1047 		return n;
   1048 #ifdef FAITH4
   1049 	} else if (strcmp(cmd, "PORT") == 0 && param) {
   1050 		/*
   1051 		 * PORT -> EPRT
   1052 		 */
   1053 		char host[NI_MAXHOST], serv[NI_MAXSERV];
   1054 
   1055 		nstate = PORT;
   1056 
   1057 		close(wport4);
   1058 		close(wport6);
   1059 		close(port4);
   1060 		close(port6);
   1061 		wport4 = wport6 = port4 = port6 = -1;
   1062 
   1063 		p = param;
   1064 		n = sscanf(p, "%u,%u,%u,%u,%u,%u",
   1065 			&ho[0], &ho[1], &ho[2], &ho[3], &po[0], &po[1]);
   1066 		if (n != 6) {
   1067 			n = snprintf(sbuf, sizeof(sbuf),
   1068 				"501 illegal parameter to PORT\r\n");
   1069 			if (n < 0 || n >= sizeof(sbuf))
   1070 				n = 0;
   1071 			if (n)
   1072 				write(src, sbuf, n);
   1073 			return n;
   1074 		}
   1075 
   1076 		memset(&data6, 0, sizeof(data6));
   1077 		sin = (struct sockaddr_in *)&data6;
   1078 		sin->sin_len = sizeof(*sin);
   1079 		sin->sin_family = AF_INET;
   1080 		sin->sin_addr.s_addr = htonl(
   1081 			((ho[0] & 0xff) << 24) | ((ho[1] & 0xff) << 16) |
   1082 			((ho[2] & 0xff) << 8) | (ho[3] & 0xff));
   1083 		sin->sin_port = htons(((po[0] & 0xff) << 8) | (po[1] & 0xff));
   1084 
   1085 		/* get ready for active data connection */
   1086 		n = sizeof(data4);
   1087 		error = getsockname(dst, (struct sockaddr *)&data4, &n);
   1088 		if (error == -1) {
   1089 portfail:
   1090 			n = snprintf(sbuf, sizeof(sbuf),
   1091 				"500 could not translate to EPRT\r\n");
   1092 			if (n < 0 || n >= sizeof(sbuf))
   1093 				n = 0;
   1094 			if (n)
   1095 				write(src, sbuf, n);
   1096 			return n;
   1097 		}
   1098 		if (((struct sockaddr *)&data4)->sa_family != AF_INET6)
   1099 			goto portfail;
   1100 
   1101 		((struct sockaddr_in6 *)&data4)->sin6_port = 0;
   1102 		sa = (struct sockaddr *)&data4;
   1103 		wport4 = socket(sa->sa_family, SOCK_STREAM, 0);
   1104 		if (wport4 == -1)
   1105 			goto portfail;
   1106 		error = bind(wport4, sa, sa->sa_len);
   1107 		if (error == -1) {
   1108 			close(wport4);
   1109 			wport4 = -1;
   1110 			goto portfail;
   1111 		}
   1112 		error = listen(wport4, 1);
   1113 		if (error == -1) {
   1114 			close(wport4);
   1115 			wport4 = -1;
   1116 			goto portfail;
   1117 		}
   1118 
   1119 		/* transmit EPRT */
   1120 		n = sizeof(data4);
   1121 		error = getsockname(wport4, (struct sockaddr *)&data4, &n);
   1122 		if (error == -1) {
   1123 			close(wport4);
   1124 			wport4 = -1;
   1125 			goto portfail;
   1126 		}
   1127 		af = 2;
   1128 		sa = (struct sockaddr *)&data4;
   1129 		if (getnameinfo(sa, sa->sa_len, host, sizeof(host),
   1130 			serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV)) {
   1131 			close(wport4);
   1132 			wport4 = -1;
   1133 			goto portfail;
   1134 		}
   1135 		n = snprintf(sbuf, sizeof(sbuf), "EPRT |%d|%s|%s|\r\n", af, host, serv);
   1136 		if (n < 0 || n >= sizeof(sbuf))
   1137 			n = 0;
   1138 		if (n)
   1139 			write(dst, sbuf, n);
   1140 		*state = nstate;
   1141 		passivemode = 0;
   1142 		return n;
   1143 	} else if (strcmp(cmd, "PASV") == 0 && !param) {
   1144 		/*
   1145 		 * PASV -> EPSV
   1146 		 */
   1147 
   1148 		nstate = PASV;
   1149 
   1150 		close(wport4);
   1151 		close(wport6);
   1152 		close(port4);
   1153 		close(port6);
   1154 		wport4 = wport6 = port4 = port6 = -1;
   1155 
   1156 		/* transmit EPSV */
   1157 		n = snprintf(sbuf, sizeof(sbuf), "EPSV\r\n");
   1158 		if (n < 0 || n >= sizeof(sbuf))
   1159 			n = 0;
   1160 		if (n)
   1161 			write(dst, sbuf, n);
   1162 		*state = PASV;
   1163 		passivemode = 0;	/* to be set to 1 later */
   1164 		return n;
   1165 #else /* FAITH4 */
   1166 	} else if (strcmp(cmd, "PORT") == 0 || strcmp(cmd, "PASV") == 0) {
   1167 		/*
   1168 		 * reject PORT/PASV
   1169 		 */
   1170 		n = snprintf(sbuf, sizeof(sbuf), "502 %s not implemented.\r\n", cmd);
   1171 		if (n < 0 || n >= sizeof(sbuf))
   1172 			n = 0;
   1173 		if (n)
   1174 			write(src, sbuf, n);
   1175 		return n;
   1176 #endif /* FAITH4 */
   1177 	} else if (passivemode
   1178 		&& (strcmp(cmd, "STOR") == 0
   1179 		 || strcmp(cmd, "STOU") == 0
   1180 		 || strcmp(cmd, "RETR") == 0
   1181 		 || strcmp(cmd, "LIST") == 0
   1182 		 || strcmp(cmd, "NLST") == 0
   1183 		 || strcmp(cmd, "APPE") == 0)) {
   1184 		/*
   1185 		 * commands with data transfer.  need to care about passive
   1186 		 * mode data connection.
   1187 		 */
   1188 
   1189 		if (ftp_passiveconn() < 0) {
   1190 			n = snprintf(sbuf, sizeof(sbuf), "425 Cannot open data connetion\r\n");
   1191 			if (n < 0 || n >= sizeof(sbuf))
   1192 				n = 0;
   1193 			if (n)
   1194 				write(src, sbuf, n);
   1195 		} else {
   1196 			/* simply relay the command */
   1197 			write(dst, rbuf, n);
   1198 		}
   1199 
   1200 		*state = NONE;
   1201 		return n;
   1202 	} else {
   1203 		/* simply relay it */
   1204 		*state = NONE;
   1205 		write(dst, rbuf, n);
   1206 		return n;
   1207 	}
   1208 
   1209  bad:
   1210 	exit_failure("%s", strerror(errno));
   1211 	/*NOTREACHED*/
   1212 	return 0;	/* to make gcc happy */
   1213 }
   1214