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