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