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