1/*	$NetBSD: ftp.c,v 1.18 2009/05/20 12:53:47 lukem Exp $	*/
2/*	from	NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp	*/
3
4/*-
5 * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Luke Mewburn.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1989, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62/*
63 * Copyright (C) 1997 and 1998 WIDE Project.
64 * All rights reserved.
65 *
66 * Redistribution and use in source and binary forms, with or without
67 * modification, are permitted provided that the following conditions
68 * are met:
69 * 1. Redistributions of source code must retain the above copyright
70 *    notice, this list of conditions and the following disclaimer.
71 * 2. Redistributions in binary form must reproduce the above copyright
72 *    notice, this list of conditions and the following disclaimer in the
73 *    documentation and/or other materials provided with the distribution.
74 * 3. Neither the name of the project nor the names of its contributors
75 *    may be used to endorse or promote products derived from this software
76 *    without specific prior written permission.
77 *
78 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * SUCH DAMAGE.
89 */
90
91#include "tnftp.h"
92#include <arpa/telnet.h>
93
94#if 0	/* tnftp */
95
96#include <sys/cdefs.h>
97#ifndef lint
98#if 0
99static char sccsid[] = "@(#)ftp.c	8.6 (Berkeley) 10/27/94";
100#else
101__RCSID(" NetBSD: ftp.c,v 1.159 2009/04/15 03:42:33 jld Exp  ");
102#endif
103#endif /* not lint */
104
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <sys/socket.h>
108#include <sys/time.h>
109
110#include <netinet/in.h>
111#include <netinet/in_systm.h>
112#include <netinet/ip.h>
113#include <arpa/inet.h>
114#include <arpa/ftp.h>
115#include <arpa/telnet.h>
116
117#include <ctype.h>
118#include <err.h>
119#include <errno.h>
120#include <fcntl.h>
121#include <netdb.h>
122#include <stdio.h>
123#include <stdlib.h>
124#include <string.h>
125#include <time.h>
126#include <unistd.h>
127#include <stdarg.h>
128
129#endif	/* tnftp */
130
131#include "ftp_var.h"
132
133volatile sig_atomic_t	abrtflag;
134volatile sig_atomic_t	timeoutflag;
135
136sigjmp_buf	ptabort;
137int	ptabflg;
138int	ptflag = 0;
139char	pasv[BUFSIZ];	/* passive port for proxy data connection */
140
141static int empty(FILE *, FILE *, int);
142
143struct sockinet {
144	union sockunion {
145		struct sockaddr_in  su_sin;
146#ifdef INET6
147		struct sockaddr_in6 su_sin6;
148#endif
149	} si_su;
150#if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
151	int	si_len;
152#endif
153};
154
155#if !defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
156# define su_len		si_len
157#else
158# define su_len		si_su.su_sin.sin_len
159#endif
160#define su_family	si_su.su_sin.sin_family
161#define su_port		si_su.su_sin.sin_port
162
163struct sockinet myctladdr, hisctladdr, data_addr;
164
165char *
166hookup(const char *host, const char *port)
167{
168	int s = -1, error;
169	struct addrinfo hints, *res, *res0;
170	static char hostnamebuf[MAXHOSTNAMELEN];
171	socklen_t len;
172	int on = 1;
173
174	memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
175	memset((char *)&myctladdr, 0, sizeof (myctladdr));
176	memset(&hints, 0, sizeof(hints));
177	hints.ai_flags = AI_CANONNAME;
178	hints.ai_family = family;
179	hints.ai_socktype = SOCK_STREAM;
180	hints.ai_protocol = 0;
181	error = getaddrinfo(host, port, &hints, &res0);
182	if (error) {
183		warnx("Can't lookup `%s:%s': %s", host, port,
184		    (error == EAI_SYSTEM) ? strerror(errno)
185					  : gai_strerror(error));
186		code = -1;
187		return (0);
188	}
189
190	if (res0->ai_canonname)
191		(void)strlcpy(hostnamebuf, res0->ai_canonname,
192		    sizeof(hostnamebuf));
193	else
194		(void)strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
195	hostname = hostnamebuf;
196
197	for (res = res0; res; res = res->ai_next) {
198		char hname[NI_MAXHOST], sname[NI_MAXSERV];
199
200		ai_unmapped(res);
201		if (getnameinfo(res->ai_addr, res->ai_addrlen,
202		    hname, sizeof(hname), sname, sizeof(sname),
203		    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
204			strlcpy(hname, "?", sizeof(hname));
205			strlcpy(sname, "?", sizeof(sname));
206		}
207		if (verbose && res0->ai_next) {
208				/* if we have multiple possibilities */
209			fprintf(ttyout, "Trying %s:%s ...\n", hname, sname);
210		}
211		s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
212		if (s < 0) {
213			warn("Can't create socket for connection to `%s:%s'",
214			    hname, sname);
215			continue;
216		}
217		if (ftp_connect(s, res->ai_addr, res->ai_addrlen) < 0) {
218			close(s);
219			s = -1;
220			continue;
221		}
222
223		/* finally we got one */
224		break;
225	}
226	if (s < 0) {
227		warnx("Can't connect to `%s:%s'", host, port);
228		code = -1;
229		freeaddrinfo(res0);
230		return 0;
231	}
232	memcpy(&hisctladdr.si_su, res->ai_addr, res->ai_addrlen);
233	hisctladdr.su_len = res->ai_addrlen;
234	freeaddrinfo(res0);
235	res0 = res = NULL;
236
237	len = hisctladdr.su_len;
238	if (getsockname(s, (struct sockaddr *)&myctladdr.si_su, &len) == -1) {
239		warn("Can't determine my address of connection to `%s:%s'",
240		    host, port);
241		code = -1;
242		goto bad;
243	}
244	myctladdr.su_len = len;
245
246#ifdef IPTOS_LOWDELAY
247	if (hisctladdr.su_family == AF_INET) {
248		int tos = IPTOS_LOWDELAY;
249		if (setsockopt(s, IPPROTO_IP, IP_TOS,
250				(void *)&tos, sizeof(tos)) == -1) {
251				DWARN("setsockopt %s (ignored)",
252				    "IPTOS_LOWDELAY");
253		}
254	}
255#endif
256	cin = fdopen(s, "r");
257	cout = fdopen(s, "w");
258	if (cin == NULL || cout == NULL) {
259		warnx("Can't fdopen socket");
260		if (cin)
261			(void)fclose(cin);
262		if (cout)
263			(void)fclose(cout);
264		code = -1;
265		goto bad;
266	}
267	if (verbose)
268		fprintf(ttyout, "Connected to %s.\n", hostname);
269	if (getreply(0) > 2) {	/* read startup message from server */
270		if (cin)
271			(void)fclose(cin);
272		if (cout)
273			(void)fclose(cout);
274		code = -1;
275		goto bad;
276	}
277
278	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE,
279			(void *)&on, sizeof(on)) == -1) {
280		DWARN("setsockopt %s (ignored)", "SO_OOBINLINE");
281	}
282
283	return (hostname);
284 bad:
285	(void)close(s);
286	return (NULL);
287}
288
289void
290cmdabort(int notused)
291{
292	int oerrno = errno;
293
294	sigint_raised = 1;
295	alarmtimer(0);
296	if (fromatty)
297		write(fileno(ttyout), "\n", 1);
298	abrtflag++;
299	if (ptflag)
300		siglongjmp(ptabort, 1);
301	errno = oerrno;
302}
303
304void
305cmdtimeout(int notused)
306{
307	int oerrno = errno;
308
309	alarmtimer(0);
310	if (fromatty)
311		write(fileno(ttyout), "\n", 1);
312	timeoutflag++;
313	if (ptflag)
314		siglongjmp(ptabort, 1);
315	errno = oerrno;
316}
317
318/*VARARGS*/
319int
320command(const char *fmt, ...)
321{
322	va_list ap;
323	int r;
324	sigfunc oldsigint;
325
326#ifndef NO_DEBUG
327	if (ftp_debug) {
328		fputs("---> ", ttyout);
329		va_start(ap, fmt);
330		if (strncmp("PASS ", fmt, 5) == 0)
331			fputs("PASS XXXX", ttyout);
332		else if (strncmp("ACCT ", fmt, 5) == 0)
333			fputs("ACCT XXXX", ttyout);
334		else
335			vfprintf(ttyout, fmt, ap);
336		va_end(ap);
337		putc('\n', ttyout);
338	}
339#endif
340	if (cout == NULL) {
341		warnx("No control connection for command");
342		code = -1;
343		return (0);
344	}
345
346	abrtflag = 0;
347
348	oldsigint = xsignal(SIGINT, cmdabort);
349
350	va_start(ap, fmt);
351	vfprintf(cout, fmt, ap);
352	va_end(ap);
353	fputs("\r\n", cout);
354	(void)fflush(cout);
355	cpend = 1;
356	r = getreply(!strcmp(fmt, "QUIT"));
357	if (abrtflag && oldsigint != SIG_IGN)
358		(*oldsigint)(SIGINT);
359	(void)xsignal(SIGINT, oldsigint);
360	return (r);
361}
362
363static const char *m421[] = {
364	"remote server timed out. Connection closed",
365	"user interrupt. Connection closed",
366	"remote server has closed connection",
367};
368
369int
370getreply(int expecteof)
371{
372	char current_line[BUFSIZ];	/* last line of previous reply */
373	int c, n, lineno;
374	int dig;
375	int originalcode = 0, continuation = 0;
376	sigfunc oldsigint, oldsigalrm;
377	int pflag = 0;
378	char *cp, *pt = pasv;
379
380	abrtflag = 0;
381	timeoutflag = 0;
382
383	oldsigint = xsignal(SIGINT, cmdabort);
384	oldsigalrm = xsignal(SIGALRM, cmdtimeout);
385
386	for (lineno = 0 ;; lineno++) {
387		dig = n = code = 0;
388		cp = current_line;
389		while (alarmtimer(quit_time ? quit_time : 60),
390		       ((c = getc(cin)) != '\n')) {
391			if (c == IAC) {     /* handle telnet commands */
392				switch (c = getc(cin)) {
393				case WILL:
394				case WONT:
395					c = getc(cin);
396					fprintf(cout, "%c%c%c", IAC, DONT, c);
397					(void)fflush(cout);
398					break;
399				case DO:
400				case DONT:
401					c = getc(cin);
402					fprintf(cout, "%c%c%c", IAC, WONT, c);
403					(void)fflush(cout);
404					break;
405				default:
406					break;
407				}
408				continue;
409			}
410			dig++;
411			if (c == EOF) {
412				/*
413				 * these will get trashed by pswitch()
414				 * in lostpeer()
415				 */
416				int reply_timeoutflag = timeoutflag;
417				int reply_abrtflag = abrtflag;
418
419				alarmtimer(0);
420				if (expecteof && feof(cin)) {
421					(void)xsignal(SIGINT, oldsigint);
422					(void)xsignal(SIGALRM, oldsigalrm);
423					code = 221;
424					return (0);
425				}
426				cpend = 0;
427				lostpeer(0);
428				if (verbose) {
429					size_t midx;
430					if (reply_timeoutflag)
431						midx = 0;
432					else if (reply_abrtflag)
433						midx = 1;
434					else
435						midx = 2;
436					(void)fprintf(ttyout,
437			    "421 Service not available, %s.\n", m421[midx]);
438					(void)fflush(ttyout);
439				}
440				code = 421;
441				(void)xsignal(SIGINT, oldsigint);
442				(void)xsignal(SIGALRM, oldsigalrm);
443				return (4);
444			}
445			if (c != '\r' && (verbose > 0 ||
446			    ((verbose > -1 && n == '5' && dig > 4) &&
447			    (((!n && c < '5') || (n && n < '5'))
448			     || !retry_connect)))) {
449				if (proxflag &&
450				   (dig == 1 || (dig == 5 && verbose == 0)))
451					fprintf(ttyout, "%s:", hostname);
452				(void)putc(c, ttyout);
453			}
454			if (dig < 4 && isdigit(c))
455				code = code * 10 + (c - '0');
456			if (!pflag && (code == 227 || code == 228))
457				pflag = 1;
458			else if (!pflag && code == 229)
459				pflag = 100;
460			if (dig > 4 && pflag == 1 && isdigit(c))
461				pflag = 2;
462			if (pflag == 2) {
463				if (c != '\r' && c != ')') {
464					if (pt < &pasv[sizeof(pasv) - 1])
465						*pt++ = c;
466				} else {
467					*pt = '\0';
468					pflag = 3;
469				}
470			}
471			if (pflag == 100 && c == '(')
472				pflag = 2;
473			if (dig == 4 && c == '-') {
474				if (continuation)
475					code = 0;
476				continuation++;
477			}
478			if (n == 0)
479				n = c;
480			if (cp < &current_line[sizeof(current_line) - 1])
481				*cp++ = c;
482		}
483		if (verbose > 0 || ((verbose > -1 && n == '5') &&
484		    (n < '5' || !retry_connect))) {
485			(void)putc(c, ttyout);
486			(void)fflush(ttyout);
487		}
488		if (cp[-1] == '\r')
489			cp[-1] = '\0';
490		*cp = '\0';
491		if (lineno == 0)
492			(void)strlcpy(reply_string, current_line,
493			    sizeof(reply_string));
494		if (lineno > 0 && code == 0 && reply_callback != NULL)
495			(*reply_callback)(current_line);
496		if (continuation && code != originalcode) {
497			if (originalcode == 0)
498				originalcode = code;
499			continue;
500		}
501		if (n != '1')
502			cpend = 0;
503		alarmtimer(0);
504		(void)xsignal(SIGINT, oldsigint);
505		(void)xsignal(SIGALRM, oldsigalrm);
506		if (code == 421 || originalcode == 421)
507			lostpeer(0);
508		if (abrtflag && oldsigint != cmdabort && oldsigint != SIG_IGN)
509			(*oldsigint)(SIGINT);
510		if (timeoutflag && oldsigalrm != cmdtimeout &&
511		    oldsigalrm != SIG_IGN)
512			(*oldsigalrm)(SIGINT);
513		return (n - '0');
514	}
515}
516
517static int
518empty(FILE *ecin, FILE *din, int sec)
519{
520	int		nr, nfd;
521	struct pollfd	pfd[2];
522
523	nfd = 0;
524	if (ecin) {
525		pfd[nfd].fd = fileno(ecin);
526		pfd[nfd++].events = POLLIN;
527	}
528
529	if (din) {
530		pfd[nfd].fd = fileno(din);
531		pfd[nfd++].events = POLLIN;
532	}
533
534	if ((nr = ftp_poll(pfd, nfd, sec * 1000)) <= 0)
535		return nr;
536
537	nr = 0;
538	nfd = 0;
539	if (ecin)
540		nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0;
541	if (din)
542		nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0;
543	return nr;
544}
545
546sigjmp_buf	xferabort;
547
548void
549abortxfer(int notused)
550{
551	char msgbuf[100];
552	size_t len;
553
554	sigint_raised = 1;
555	alarmtimer(0);
556	mflag = 0;
557	abrtflag = 0;
558	switch (direction[0]) {
559	case 'r':
560		strlcpy(msgbuf, "\nreceive", sizeof(msgbuf));
561		break;
562	case 's':
563		strlcpy(msgbuf, "\nsend", sizeof(msgbuf));
564		break;
565	default:
566		errx(1, "abortxfer: unknown direction `%s'", direction);
567	}
568	len = strlcat(msgbuf, " aborted. Waiting for remote to finish abort.\n",
569	    sizeof(msgbuf));
570	write(fileno(ttyout), msgbuf, len);
571	siglongjmp(xferabort, 1);
572}
573
574/*
575 * Read data from infd & write to outfd, using buf/bufsize as the temporary
576 * buffer, dealing with short writes.
577 * If rate_limit != 0, rate-limit the transfer.
578 * If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes.
579 * Updates global variables: bytes.
580 * Returns 0 if ok, 1 if there was a read error, 2 if there was a write error.
581 * In the case of error, errno contains the appropriate error code.
582 */
583static int
584copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
585	int rate_limit, int hash_interval)
586{
587	volatile off_t	hashc;
588	ssize_t		inc, outc;
589	char		*bufp;
590	struct timeval	tvthen, tvnow, tvdiff;
591	off_t		bufrem, bufchunk;
592	int		serr;
593
594	hashc = hash_interval;
595	if (rate_limit)
596		bufchunk = rate_limit;
597	else
598		bufchunk = bufsize;
599
600	while (1) {
601		if (rate_limit) {
602			(void)gettimeofday(&tvthen, NULL);
603		}
604		errno = 0;
605		inc = outc = 0;
606					/* copy bufchunk at a time */
607		bufrem = bufchunk;
608		while (bufrem > 0) {
609			inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
610			if (inc <= 0)
611				goto copy_done;
612			bytes += inc;
613			bufrem -= inc;
614			bufp = buf;
615			while (inc > 0) {
616				outc = write(outfd, bufp, inc);
617				if (outc < 0)
618					goto copy_done;
619				inc -= outc;
620				bufp += outc;
621			}
622			if (hash_interval) {
623				while (bytes >= hashc) {
624					(void)putc('#', ttyout);
625					hashc += hash_interval;
626				}
627				(void)fflush(ttyout);
628			}
629		}
630		if (rate_limit) {	/* rate limited; wait if necessary */
631			while (1) {
632				(void)gettimeofday(&tvnow, NULL);
633				timersub(&tvnow, &tvthen, &tvdiff);
634				if (tvdiff.tv_sec > 0)
635					break;
636				usleep(1000000 - tvdiff.tv_usec);
637			}
638		}
639	}
640
641 copy_done:
642	serr = errno;
643	if (hash_interval && bytes > 0) {
644		if (bytes < hash_interval)
645			(void)putc('#', ttyout);
646		(void)putc('\n', ttyout);
647		(void)fflush(ttyout);
648	}
649	errno = serr;
650	if (inc == -1)
651		return 1;
652	if (outc == -1)
653		return 2;
654
655	return 0;
656}
657
658void
659sendrequest(const char *cmd, const char *local, const char *remote,
660	    int printnames)
661{
662	struct stat st;
663	int c;
664	FILE *volatile fin;
665	FILE *volatile dout;
666	int (*volatile closefunc)(FILE *);
667	sigfunc volatile oldintr;
668	sigfunc volatile oldintp;
669	off_t volatile hashbytes;
670	int hash_interval;
671	const char *lmode;
672	static size_t bufsize;
673	static char *buf;
674	int oprogress;
675
676	hashbytes = mark;
677	direction = "sent";
678	dout = NULL;
679	bytes = 0;
680	filesize = -1;
681	oprogress = progress;
682	if (verbose && printnames) {
683		if (*local != '-')
684			fprintf(ttyout, "local: %s ", local);
685		if (remote)
686			fprintf(ttyout, "remote: %s\n", remote);
687	}
688	if (proxy) {
689		proxtrans(cmd, local, remote);
690		return;
691	}
692	if (curtype != type)
693		changetype(type, 0);
694	closefunc = NULL;
695	oldintr = NULL;
696	oldintp = NULL;
697	lmode = "w";
698	if (sigsetjmp(xferabort, 1)) {
699		while (cpend)
700			(void)getreply(0);
701		code = -1;
702		goto cleanupsend;
703	}
704	(void)xsignal(SIGQUIT, psummary);
705	oldintr = xsignal(SIGINT, abortxfer);
706	if (strcmp(local, "-") == 0) {
707		fin = stdin;
708		progress = 0;
709	} else if (*local == '|') {
710		oldintp = xsignal(SIGPIPE, SIG_IGN);
711		fin = popen(local + 1, "r");
712		if (fin == NULL) {
713			warn("Can't execute `%s'", local + 1);
714			code = -1;
715			goto cleanupsend;
716		}
717		progress = 0;
718		closefunc = pclose;
719	} else {
720		fin = fopen(local, "r");
721		if (fin == NULL) {
722			warn("Can't open `%s'", local);
723			code = -1;
724			goto cleanupsend;
725		}
726		closefunc = fclose;
727		if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
728			fprintf(ttyout, "%s: not a plain file.\n", local);
729			code = -1;
730			goto cleanupsend;
731		}
732		filesize = st.st_size;
733	}
734	if (initconn()) {
735		code = -1;
736		goto cleanupsend;
737	}
738	if (sigsetjmp(xferabort, 1))
739		goto abort;
740
741	if (restart_point &&
742	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
743		int rc;
744
745		rc = -1;
746		switch (curtype) {
747		case TYPE_A:
748			rc = fseeko(fin, restart_point, SEEK_SET);
749			break;
750		case TYPE_I:
751		case TYPE_L:
752			rc = lseek(fileno(fin), restart_point, SEEK_SET);
753			break;
754		}
755		if (rc < 0) {
756			warn("Can't seek to restart `%s'", local);
757			goto cleanupsend;
758		}
759		if (command("REST " LLF, (LLT)restart_point) != CONTINUE)
760			goto cleanupsend;
761		lmode = "r+";
762	}
763	if (remote) {
764		if (command("%s %s", cmd, remote) != PRELIM)
765			goto cleanupsend;
766	} else {
767		if (command("%s", cmd) != PRELIM)
768			goto cleanupsend;
769	}
770	dirchange = 1;
771	dout = dataconn(lmode);
772	if (dout == NULL)
773		goto abort;
774
775	if ((size_t)sndbuf_size > bufsize) {
776		if (buf)
777			(void)free(buf);
778		bufsize = sndbuf_size;
779		buf = ftp_malloc(bufsize);
780	}
781
782	progressmeter(-1);
783	oldintp = xsignal(SIGPIPE, SIG_IGN);
784	hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
785
786	switch (curtype) {
787
788	case TYPE_I:
789	case TYPE_L:
790		c = copy_bytes(fileno(fin), fileno(dout), buf, bufsize,
791			       rate_put, hash_interval);
792		if (c == 1) {
793			warn("Reading `%s'", local);
794		} else if (c == 2) {
795			if (errno != EPIPE)
796				warn("Writing to network");
797			bytes = -1;
798		}
799		break;
800
801	case TYPE_A:
802		while ((c = getc(fin)) != EOF) {
803			if (c == '\n') {
804				while (hash_interval && bytes >= hashbytes) {
805					(void)putc('#', ttyout);
806					(void)fflush(ttyout);
807					hashbytes += mark;
808				}
809				if (ferror(dout))
810					break;
811				(void)putc('\r', dout);
812				bytes++;
813			}
814			(void)putc(c, dout);
815			bytes++;
816#if 0	/* this violates RFC0959 */
817			if (c == '\r') {
818				(void)putc('\0', dout);
819				bytes++;
820			}
821#endif
822		}
823		if (hash_interval) {
824			if (bytes < hashbytes)
825				(void)putc('#', ttyout);
826			(void)putc('\n', ttyout);
827		}
828		if (ferror(fin))
829			warn("Reading `%s'", local);
830		if (ferror(dout)) {
831			if (errno != EPIPE)
832				warn("Writing to network");
833			bytes = -1;
834		}
835		break;
836	}
837
838	progressmeter(1);
839	if (closefunc != NULL) {
840		(*closefunc)(fin);
841		fin = NULL;
842	}
843	(void)fclose(dout);
844	dout = NULL;
845	(void)getreply(0);
846	if (bytes > 0)
847		ptransfer(0);
848	goto cleanupsend;
849
850 abort:
851	(void)xsignal(SIGINT, oldintr);
852	oldintr = NULL;
853	if (!cpend) {
854		code = -1;
855		goto cleanupsend;
856	}
857	if (data >= 0) {
858		(void)close(data);
859		data = -1;
860	}
861	if (dout) {
862		(void)fclose(dout);
863		dout = NULL;
864	}
865	(void)getreply(0);
866	code = -1;
867	if (bytes > 0)
868		ptransfer(0);
869
870 cleanupsend:
871	if (oldintr)
872		(void)xsignal(SIGINT, oldintr);
873	if (oldintp)
874		(void)xsignal(SIGPIPE, oldintp);
875	if (data >= 0) {
876		(void)close(data);
877		data = -1;
878	}
879	if (closefunc != NULL && fin != NULL)
880		(*closefunc)(fin);
881	if (dout)
882		(void)fclose(dout);
883	progress = oprogress;
884	restart_point = 0;
885	bytes = 0;
886}
887
888void
889recvrequest(const char *cmd, const char *volatile local, const char *remote,
890	    const char *lmode, int printnames, int ignorespecial)
891{
892	FILE *volatile fout;
893	FILE *volatile din;
894	int (*volatile closefunc)(FILE *);
895	sigfunc volatile oldintr;
896	sigfunc volatile oldintp;
897	int c, d;
898	int volatile is_retr;
899	int volatile tcrflag;
900	int volatile bare_lfs;
901	static size_t bufsize;
902	static char *buf;
903	off_t volatile hashbytes;
904	int hash_interval;
905	struct stat st;
906	time_t mtime;
907	struct timeval tval[2];
908	int oprogress;
909	int opreserve;
910
911	fout = NULL;
912	din = NULL;
913	hashbytes = mark;
914	direction = "received";
915	bytes = 0;
916	bare_lfs = 0;
917	filesize = -1;
918	oprogress = progress;
919	opreserve = preserve;
920	is_retr = (strcmp(cmd, "RETR") == 0);
921	if (is_retr && verbose && printnames) {
922		if (ignorespecial || *local != '-')
923			fprintf(ttyout, "local: %s ", local);
924		if (remote)
925			fprintf(ttyout, "remote: %s\n", remote);
926	}
927	if (proxy && is_retr) {
928		proxtrans(cmd, local, remote);
929		return;
930	}
931	closefunc = NULL;
932	oldintr = NULL;
933	oldintp = NULL;
934	tcrflag = !crflag && is_retr;
935	if (sigsetjmp(xferabort, 1)) {
936		while (cpend)
937			(void)getreply(0);
938		code = -1;
939		goto cleanuprecv;
940	}
941	(void)xsignal(SIGQUIT, psummary);
942	oldintr = xsignal(SIGINT, abortxfer);
943	if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
944		if (access(local, W_OK) < 0) {
945			char *dir = strrchr(local, '/');
946
947			if (errno != ENOENT && errno != EACCES) {
948				warn("Can't access `%s'", local);
949				code = -1;
950				goto cleanuprecv;
951			}
952			if (dir != NULL)
953				*dir = 0;
954			d = access(dir == local ? "/" :
955			    dir ? local : ".", W_OK);
956			if (dir != NULL)
957				*dir = '/';
958			if (d < 0) {
959				warn("Can't access `%s'", local);
960				code = -1;
961				goto cleanuprecv;
962			}
963			if (!runique && errno == EACCES &&
964			    chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
965				warn("Can't chmod `%s'", local);
966				code = -1;
967				goto cleanuprecv;
968			}
969			if (runique && errno == EACCES &&
970			   (local = gunique(local)) == NULL) {
971				code = -1;
972				goto cleanuprecv;
973			}
974		}
975		else if (runique && (local = gunique(local)) == NULL) {
976			code = -1;
977			goto cleanuprecv;
978		}
979	}
980	if (!is_retr) {
981		if (curtype != TYPE_A)
982			changetype(TYPE_A, 0);
983	} else {
984		if (curtype != type)
985			changetype(type, 0);
986		filesize = remotesize(remote, 0);
987		if (code == 421 || code == -1)
988			goto cleanuprecv;
989	}
990	if (initconn()) {
991		code = -1;
992		goto cleanuprecv;
993	}
994	if (sigsetjmp(xferabort, 1))
995		goto abort;
996	if (is_retr && restart_point &&
997	    command("REST " LLF, (LLT) restart_point) != CONTINUE)
998		goto cleanuprecv;
999	if (! EMPTYSTRING(remote)) {
1000		if (command("%s %s", cmd, remote) != PRELIM)
1001			goto cleanuprecv;
1002	} else {
1003		if (command("%s", cmd) != PRELIM)
1004			goto cleanuprecv;
1005	}
1006	din = dataconn("r");
1007	if (din == NULL)
1008		goto abort;
1009	if (!ignorespecial && strcmp(local, "-") == 0) {
1010		fout = stdout;
1011		progress = 0;
1012		preserve = 0;
1013	} else if (!ignorespecial && *local == '|') {
1014		oldintp = xsignal(SIGPIPE, SIG_IGN);
1015		fout = popen(local + 1, "w");
1016		if (fout == NULL) {
1017			warn("Can't execute `%s'", local+1);
1018			goto abort;
1019		}
1020		progress = 0;
1021		preserve = 0;
1022		closefunc = pclose;
1023	} else {
1024		fout = fopen(local, lmode);
1025		if (fout == NULL) {
1026			warn("Can't open `%s'", local);
1027			goto abort;
1028		}
1029		closefunc = fclose;
1030	}
1031
1032	if (fstat(fileno(fout), &st) != -1 && !S_ISREG(st.st_mode)) {
1033		progress = 0;
1034		preserve = 0;
1035	}
1036	if ((size_t)rcvbuf_size > bufsize) {
1037		if (buf)
1038			(void)free(buf);
1039		bufsize = rcvbuf_size;
1040		buf = ftp_malloc(bufsize);
1041	}
1042
1043	progressmeter(-1);
1044	hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
1045
1046	switch (curtype) {
1047
1048	case TYPE_I:
1049	case TYPE_L:
1050		if (is_retr && restart_point &&
1051		    lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1052			warn("Can't seek to restart `%s'", local);
1053			goto cleanuprecv;
1054		}
1055		c = copy_bytes(fileno(din), fileno(fout), buf, bufsize,
1056			       rate_get, hash_interval);
1057		if (c == 1) {
1058			if (errno != EPIPE)
1059				warn("Reading from network");
1060			bytes = -1;
1061		} else if (c == 2) {
1062			warn("Writing `%s'", local);
1063		}
1064		break;
1065
1066	case TYPE_A:
1067		if (is_retr && restart_point) {
1068			int ch;
1069			off_t i;
1070
1071			if (fseeko(fout, (off_t)0, SEEK_SET) < 0)
1072				goto done;
1073			for (i = 0; i++ < restart_point;) {
1074				if ((ch = getc(fout)) == EOF)
1075					goto done;
1076				if (ch == '\n')
1077					i++;
1078			}
1079			if (fseeko(fout, (off_t)0, SEEK_CUR) < 0) {
1080 done:
1081				warn("Can't seek to restart `%s'", local);
1082				goto cleanuprecv;
1083			}
1084		}
1085		while ((c = getc(din)) != EOF) {
1086			if (c == '\n')
1087				bare_lfs++;
1088			while (c == '\r') {
1089				while (hash_interval && bytes >= hashbytes) {
1090					(void)putc('#', ttyout);
1091					(void)fflush(ttyout);
1092					hashbytes += mark;
1093				}
1094				bytes++;
1095				if ((c = getc(din)) != '\n' || tcrflag) {
1096					if (ferror(fout))
1097						goto break2;
1098					(void)putc('\r', fout);
1099					if (c == '\0') {
1100						bytes++;
1101						goto contin2;
1102					}
1103					if (c == EOF)
1104						goto contin2;
1105				}
1106			}
1107			(void)putc(c, fout);
1108			bytes++;
1109	contin2:	;
1110		}
1111 break2:
1112		if (hash_interval) {
1113			if (bytes < hashbytes)
1114				(void)putc('#', ttyout);
1115			(void)putc('\n', ttyout);
1116		}
1117		if (ferror(din)) {
1118			if (errno != EPIPE)
1119				warn("Reading from network");
1120			bytes = -1;
1121		}
1122		if (ferror(fout))
1123			warn("Writing `%s'", local);
1124		break;
1125	}
1126
1127	progressmeter(1);
1128	if (closefunc != NULL) {
1129		(*closefunc)(fout);
1130		fout = NULL;
1131	}
1132	(void)fclose(din);
1133	din = NULL;
1134	(void)getreply(0);
1135	if (bare_lfs) {
1136		fprintf(ttyout,
1137		    "WARNING! %d bare linefeeds received in ASCII mode.\n",
1138		    bare_lfs);
1139		fputs("File may not have transferred correctly.\n", ttyout);
1140	}
1141	if (bytes >= 0 && is_retr) {
1142		if (bytes > 0)
1143			ptransfer(0);
1144		if (preserve && (closefunc == fclose)) {
1145			mtime = remotemodtime(remote, 0);
1146			if (mtime != -1) {
1147				(void)gettimeofday(&tval[0], NULL);
1148				tval[1].tv_sec = mtime;
1149				tval[1].tv_usec = 0;
1150				if (utimes(local, tval) == -1) {
1151					fprintf(ttyout,
1152				"Can't change modification time on %s to %s",
1153					    local,
1154					    rfc2822time(localtime(&mtime)));
1155				}
1156			}
1157		}
1158	}
1159	goto cleanuprecv;
1160
1161 abort:
1162			/*
1163			 * abort using RFC0959 recommended IP,SYNC sequence
1164			 */
1165	if (! sigsetjmp(xferabort, 1)) {
1166			/* this is the first call */
1167		(void)xsignal(SIGINT, abort_squared);
1168		if (!cpend) {
1169			code = -1;
1170			goto cleanuprecv;
1171		}
1172		abort_remote(din);
1173	}
1174	code = -1;
1175	if (bytes > 0)
1176		ptransfer(0);
1177
1178 cleanuprecv:
1179	if (oldintr)
1180		(void)xsignal(SIGINT, oldintr);
1181	if (oldintp)
1182		(void)xsignal(SIGPIPE, oldintp);
1183	if (data >= 0) {
1184		(void)close(data);
1185		data = -1;
1186	}
1187	if (closefunc != NULL && fout != NULL)
1188		(*closefunc)(fout);
1189	if (din)
1190		(void)fclose(din);
1191	progress = oprogress;
1192	preserve = opreserve;
1193	bytes = 0;
1194}
1195
1196/*
1197 * Need to start a listen on the data channel before we send the command,
1198 * otherwise the server's connect may fail.
1199 */
1200int
1201initconn(void)
1202{
1203	char *p, *a;
1204	int result, tmpno = 0;
1205	int on = 1;
1206	int error;
1207	unsigned int addr[16], port[2];
1208	unsigned int af, hal, pal;
1209	socklen_t len;
1210	const char *pasvcmd = NULL;
1211	int overbose;
1212
1213#ifdef INET6
1214#ifndef NO_DEBUG
1215	if (myctladdr.su_family == AF_INET6 && ftp_debug &&
1216	    (IN6_IS_ADDR_LINKLOCAL(&myctladdr.si_su.su_sin6.sin6_addr) ||
1217	     IN6_IS_ADDR_SITELOCAL(&myctladdr.si_su.su_sin6.sin6_addr))) {
1218		warnx("Use of scoped addresses can be troublesome");
1219	}
1220#endif
1221#endif
1222
1223 reinit:
1224	if (passivemode) {
1225		data_addr = myctladdr;
1226		data = socket(data_addr.su_family, SOCK_STREAM, 0);
1227		if (data < 0) {
1228			warn("Can't create socket for data connection");
1229			return (1);
1230		}
1231		if ((options & SO_DEBUG) &&
1232		    setsockopt(data, SOL_SOCKET, SO_DEBUG,
1233				(void *)&on, sizeof(on)) == -1) {
1234			DWARN("setsockopt %s (ignored)", "SO_DEBUG");
1235		}
1236		result = COMPLETE + 1;
1237		switch (data_addr.su_family) {
1238		case AF_INET:
1239			if (epsv4 && !epsv4bad) {
1240				pasvcmd = "EPSV";
1241				overbose = verbose;
1242				if (ftp_debug == 0)
1243					verbose = -1;
1244				result = command("EPSV");
1245				verbose = overbose;
1246				if (verbose > 0 &&
1247				    (result == COMPLETE || !connected))
1248					fprintf(ttyout, "%s\n", reply_string);
1249				if (!connected)
1250					return (1);
1251				/*
1252				 * this code is to be friendly with broken
1253				 * BSDI ftpd
1254				 */
1255				if (code / 10 == 22 && code != 229) {
1256					fputs(
1257"wrong server: return code must be 229\n",
1258						ttyout);
1259					result = COMPLETE + 1;
1260				}
1261				if (result != COMPLETE) {
1262					epsv4bad = 1;
1263					DPRINTF("disabling epsv4 for this "
1264					    "connection\n");
1265				}
1266			}
1267			if (result != COMPLETE) {
1268				pasvcmd = "PASV";
1269				result = command("PASV");
1270				if (!connected)
1271					return (1);
1272			}
1273			break;
1274#ifdef INET6
1275		case AF_INET6:
1276			if (epsv6 && !epsv6bad) {
1277				pasvcmd = "EPSV";
1278				overbose = verbose;
1279				if (ftp_debug == 0)
1280					verbose = -1;
1281				result = command("EPSV");
1282				verbose = overbose;
1283				if (verbose > 0 &&
1284				    (result == COMPLETE || !connected))
1285					fprintf(ttyout, "%s\n", reply_string);
1286				if (!connected)
1287					return (1);
1288				/*
1289				 * this code is to be friendly with
1290				 * broken BSDI ftpd
1291				 */
1292				if (code / 10 == 22 && code != 229) {
1293					fputs(
1294						"wrong server: return code must be 229\n",
1295						ttyout);
1296					result = COMPLETE + 1;
1297				}
1298				if (result != COMPLETE) {
1299					epsv6bad = 1;
1300					DPRINTF("disabling epsv6 for this "
1301					    "connection\n");
1302				}
1303			}
1304			if (result != COMPLETE) {
1305				pasvcmd = "LPSV";
1306				result = command("LPSV");
1307			}
1308			if (!connected)
1309				return (1);
1310			break;
1311#endif
1312		default:
1313			result = COMPLETE + 1;
1314			break;
1315		}
1316		if (result != COMPLETE) {
1317			if (activefallback) {
1318				(void)close(data);
1319				data = -1;
1320				passivemode = 0;
1321#if 0
1322				activefallback = 0;
1323#endif
1324				goto reinit;
1325			}
1326			fputs("Passive mode refused.\n", ttyout);
1327			goto bad;
1328		}
1329
1330#define	pack2(var, off) \
1331	(((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
1332#define	pack4(var, off) \
1333	(((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
1334	 ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
1335#define	UC(b)	(((int)b)&0xff)
1336
1337		/*
1338		 * What we've got at this point is a string of comma separated
1339		 * one-byte unsigned integer values, separated by commas.
1340		 */
1341		if (strcmp(pasvcmd, "PASV") == 0) {
1342			if (data_addr.su_family != AF_INET) {
1343				fputs(
1344    "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1345				error = 1;
1346				goto bad;
1347			}
1348			if (code / 10 == 22 && code != 227) {
1349				fputs("wrong server: return code must be 227\n",
1350					ttyout);
1351				error = 1;
1352				goto bad;
1353			}
1354			error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
1355					&addr[0], &addr[1], &addr[2], &addr[3],
1356					&port[0], &port[1]);
1357			if (error != 6) {
1358				fputs(
1359"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1360				error = 1;
1361				goto bad;
1362			}
1363			error = 0;
1364			memset(&data_addr, 0, sizeof(data_addr));
1365			data_addr.su_family = AF_INET;
1366			data_addr.su_len = sizeof(struct sockaddr_in);
1367			data_addr.si_su.su_sin.sin_addr.s_addr =
1368			    htonl(pack4(addr, 0));
1369			data_addr.su_port = htons(pack2(port, 0));
1370		} else if (strcmp(pasvcmd, "LPSV") == 0) {
1371			if (code / 10 == 22 && code != 228) {
1372				fputs("wrong server: return code must be 228\n",
1373					ttyout);
1374				error = 1;
1375				goto bad;
1376			}
1377			switch (data_addr.su_family) {
1378			case AF_INET:
1379				error = sscanf(pasv,
1380"%u,%u,%u,%u,%u,%u,%u,%u,%u",
1381					&af, &hal,
1382					&addr[0], &addr[1], &addr[2], &addr[3],
1383					&pal, &port[0], &port[1]);
1384				if (error != 9) {
1385					fputs(
1386"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1387					error = 1;
1388					goto bad;
1389				}
1390				if (af != 4 || hal != 4 || pal != 2) {
1391					fputs(
1392"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1393					error = 1;
1394					goto bad;
1395				}
1396
1397				error = 0;
1398				memset(&data_addr, 0, sizeof(data_addr));
1399				data_addr.su_family = AF_INET;
1400				data_addr.su_len = sizeof(struct sockaddr_in);
1401				data_addr.si_su.su_sin.sin_addr.s_addr =
1402				    htonl(pack4(addr, 0));
1403				data_addr.su_port = htons(pack2(port, 0));
1404				break;
1405#ifdef INET6
1406			case AF_INET6:
1407				error = sscanf(pasv,
1408"%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
1409					&af, &hal,
1410					&addr[0], &addr[1], &addr[2], &addr[3],
1411					&addr[4], &addr[5], &addr[6], &addr[7],
1412					&addr[8], &addr[9], &addr[10],
1413					&addr[11], &addr[12], &addr[13],
1414					&addr[14], &addr[15],
1415					&pal, &port[0], &port[1]);
1416				if (error != 21) {
1417					fputs(
1418"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1419					error = 1;
1420					goto bad;
1421				}
1422				if (af != 6 || hal != 16 || pal != 2) {
1423					fputs(
1424"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1425					error = 1;
1426					goto bad;
1427				}
1428
1429				error = 0;
1430				memset(&data_addr, 0, sizeof(data_addr));
1431				data_addr.su_family = AF_INET6;
1432				data_addr.su_len = sizeof(struct sockaddr_in6);
1433			    {
1434				size_t i;
1435				for (i = 0; i < sizeof(struct in6_addr); i++) {
1436					data_addr.si_su.su_sin6.sin6_addr.s6_addr[i] =
1437					    UC(addr[i]);
1438				}
1439			    }
1440				data_addr.su_port = htons(pack2(port, 0));
1441				break;
1442#endif
1443			default:
1444				error = 1;
1445			}
1446		} else if (strcmp(pasvcmd, "EPSV") == 0) {
1447			char delim[4];
1448
1449			port[0] = 0;
1450			if (code / 10 == 22 && code != 229) {
1451				fputs("wrong server: return code must be 229\n",
1452					ttyout);
1453				error = 1;
1454				goto bad;
1455			}
1456			if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
1457					&delim[1], &delim[2], &port[1],
1458					&delim[3]) != 5) {
1459				fputs("parse error!\n", ttyout);
1460				error = 1;
1461				goto bad;
1462			}
1463			if (delim[0] != delim[1] || delim[0] != delim[2]
1464			 || delim[0] != delim[3]) {
1465				fputs("parse error!\n", ttyout);
1466				error = 1;
1467				goto bad;
1468			}
1469			data_addr = hisctladdr;
1470			data_addr.su_port = htons(port[1]);
1471		} else
1472			goto bad;
1473
1474		if (ftp_connect(data, (struct sockaddr *)&data_addr.si_su,
1475		    data_addr.su_len) < 0) {
1476			if (activefallback) {
1477				(void)close(data);
1478				data = -1;
1479				passivemode = 0;
1480#if 0
1481				activefallback = 0;
1482#endif
1483				goto reinit;
1484			}
1485			goto bad;
1486		}
1487#ifdef IPTOS_THROUGHPUT
1488		if (data_addr.su_family == AF_INET) {
1489			on = IPTOS_THROUGHPUT;
1490			if (setsockopt(data, IPPROTO_IP, IP_TOS,
1491					(void *)&on, sizeof(on)) == -1) {
1492				DWARN("setsockopt %s (ignored)",
1493				    "IPTOS_THROUGHPUT");
1494			}
1495		}
1496#endif
1497		return (0);
1498	}
1499
1500 noport:
1501	data_addr = myctladdr;
1502	if (sendport)
1503		data_addr.su_port = 0;	/* let system pick one */
1504	if (data != -1)
1505		(void)close(data);
1506	data = socket(data_addr.su_family, SOCK_STREAM, 0);
1507	if (data < 0) {
1508		warn("Can't create socket for data connection");
1509		if (tmpno)
1510			sendport = 1;
1511		return (1);
1512	}
1513	if (!sendport)
1514		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR,
1515				(void *)&on, sizeof(on)) == -1) {
1516			warn("Can't set SO_REUSEADDR on data connection");
1517			goto bad;
1518		}
1519	if (bind(data, (struct sockaddr *)&data_addr.si_su,
1520	    data_addr.su_len) < 0) {
1521		warn("Can't bind for data connection");
1522		goto bad;
1523	}
1524	if ((options & SO_DEBUG) &&
1525	    setsockopt(data, SOL_SOCKET, SO_DEBUG,
1526			(void *)&on, sizeof(on)) == -1) {
1527		DWARN("setsockopt %s (ignored)", "SO_DEBUG");
1528	}
1529	len = sizeof(data_addr.si_su);
1530	memset((char *)&data_addr, 0, sizeof (data_addr));
1531	if (getsockname(data, (struct sockaddr *)&data_addr.si_su, &len) == -1) {
1532		warn("Can't determine my address of data connection");
1533		goto bad;
1534	}
1535	data_addr.su_len = len;
1536	if (ftp_listen(data, 1) < 0)
1537		warn("Can't listen to data connection");
1538
1539	if (sendport) {
1540		char hname[NI_MAXHOST], sname[NI_MAXSERV];
1541		struct sockinet tmp;
1542
1543		switch (data_addr.su_family) {
1544		case AF_INET:
1545			if (!epsv4 || epsv4bad) {
1546				result = COMPLETE + 1;
1547				break;
1548			}
1549			/* FALLTHROUGH */
1550#ifdef INET6
1551		case AF_INET6:
1552			if (!epsv6 || epsv6bad) {
1553				result = COMPLETE + 1;
1554				break;
1555			}
1556#endif
1557			af = (data_addr.su_family == AF_INET) ? 1 : 2;
1558			tmp = data_addr;
1559#ifdef INET6
1560			if (tmp.su_family == AF_INET6)
1561				tmp.si_su.su_sin6.sin6_scope_id = 0;
1562#endif
1563			if (getnameinfo((struct sockaddr *)&tmp.si_su,
1564			    tmp.su_len, hname, sizeof(hname), sname,
1565			    sizeof(sname), NI_NUMERICHOST | NI_NUMERICSERV)) {
1566				result = ERROR;
1567			} else {
1568				overbose = verbose;
1569				if (ftp_debug == 0)
1570					verbose = -1;
1571				result = command("EPRT |%u|%s|%s|", af, hname,
1572				    sname);
1573				verbose = overbose;
1574				if (verbose > 0 &&
1575				    (result == COMPLETE || !connected))
1576					fprintf(ttyout, "%s\n", reply_string);
1577				if (!connected)
1578					return (1);
1579				if (result != COMPLETE) {
1580					epsv4bad = 1;
1581					DPRINTF("disabling epsv4 for this "
1582					    "connection\n");
1583				}
1584			}
1585			break;
1586		default:
1587			result = COMPLETE + 1;
1588			break;
1589		}
1590		if (result == COMPLETE)
1591			goto skip_port;
1592
1593		switch (data_addr.su_family) {
1594		case AF_INET:
1595			a = (char *)&data_addr.si_su.su_sin.sin_addr;
1596			p = (char *)&data_addr.su_port;
1597			result = command("PORT %d,%d,%d,%d,%d,%d",
1598				 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1599				 UC(p[0]), UC(p[1]));
1600			break;
1601#ifdef INET6
1602		case AF_INET6:
1603			a = (char *)&data_addr.si_su.su_sin6.sin6_addr;
1604			p = (char *)&data_addr.su_port;
1605			result = command(
1606	"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1607				 6, 16,
1608				 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1609				 UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1610				 UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1611				 UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1612				 2, UC(p[0]), UC(p[1]));
1613			break;
1614#endif
1615		default:
1616			result = COMPLETE + 1; /* xxx */
1617		}
1618		if (!connected)
1619			return (1);
1620	skip_port:
1621
1622		if (result == ERROR && sendport == -1) {
1623			sendport = 0;
1624			tmpno = 1;
1625			goto noport;
1626		}
1627		return (result != COMPLETE);
1628	}
1629	if (tmpno)
1630		sendport = 1;
1631#ifdef IPTOS_THROUGHPUT
1632	if (data_addr.su_family == AF_INET) {
1633		on = IPTOS_THROUGHPUT;
1634		if (setsockopt(data, IPPROTO_IP, IP_TOS,
1635				(void *)&on, sizeof(on)) == -1) {
1636			DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
1637		}
1638	}
1639#endif
1640	return (0);
1641 bad:
1642	(void)close(data);
1643	data = -1;
1644	if (tmpno)
1645		sendport = 1;
1646	return (1);
1647}
1648
1649FILE *
1650dataconn(const char *lmode)
1651{
1652	struct sockinet	from;
1653	int		s, flags, rv, timeout;
1654	struct timeval	endtime, now, td;
1655	struct pollfd	pfd[1];
1656	socklen_t	fromlen;
1657
1658	if (passivemode)	/* passive data connection */
1659		return (fdopen(data, lmode));
1660
1661				/* active mode data connection */
1662
1663	if ((flags = fcntl(data, F_GETFL, 0)) == -1)
1664		goto dataconn_failed;		/* get current socket flags  */
1665	if (fcntl(data, F_SETFL, flags | O_NONBLOCK) == -1)
1666		goto dataconn_failed;		/* set non-blocking connect */
1667
1668		/* NOTE: we now must restore socket flags on successful exit */
1669
1670				/* limit time waiting on listening socket */
1671	pfd[0].fd = data;
1672	pfd[0].events = POLLIN;
1673	(void)gettimeofday(&endtime, NULL);	/* determine end time */
1674	endtime.tv_sec += (quit_time > 0) ? quit_time: 60;
1675						/* without -q, default to 60s */
1676	do {
1677		(void)gettimeofday(&now, NULL);
1678		timersub(&endtime, &now, &td);
1679		timeout = td.tv_sec * 1000 + td.tv_usec/1000;
1680		if (timeout < 0)
1681			timeout = 0;
1682		rv = ftp_poll(pfd, 1, timeout);
1683	} while (rv == -1 && errno == EINTR);	/* loop until poll ! EINTR */
1684	if (rv == -1) {
1685		warn("Can't poll waiting before accept");
1686		goto dataconn_failed;
1687	}
1688	if (rv == 0) {
1689		warnx("Poll timeout waiting before accept");
1690		goto dataconn_failed;
1691	}
1692
1693				/* (non-blocking) accept the connection */
1694	fromlen = myctladdr.su_len;
1695	do {
1696		s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
1697	} while (s == -1 && errno == EINTR);	/* loop until accept ! EINTR */
1698	if (s == -1) {
1699		warn("Can't accept data connection");
1700		goto dataconn_failed;
1701	}
1702
1703	(void)close(data);
1704	data = s;
1705	if (fcntl(data, F_SETFL, flags) == -1)	/* restore socket flags */
1706		goto dataconn_failed;
1707
1708#ifdef IPTOS_THROUGHPUT
1709	if (from.su_family == AF_INET) {
1710		int tos = IPTOS_THROUGHPUT;
1711		if (setsockopt(s, IPPROTO_IP, IP_TOS,
1712				(void *)&tos, sizeof(tos)) == -1) {
1713			DWARN("setsockopt %s (ignored)", "IPTOS_THROUGHPUT");
1714		}
1715	}
1716#endif
1717	return (fdopen(data, lmode));
1718
1719 dataconn_failed:
1720	(void)close(data);
1721	data = -1;
1722	return (NULL);
1723}
1724
1725void
1726psabort(int notused)
1727{
1728	int oerrno = errno;
1729
1730	sigint_raised = 1;
1731	alarmtimer(0);
1732	abrtflag++;
1733	errno = oerrno;
1734}
1735
1736void
1737pswitch(int flag)
1738{
1739	sigfunc oldintr;
1740	static struct comvars {
1741		int connect;
1742		char name[MAXHOSTNAMELEN];
1743		struct sockinet mctl;
1744		struct sockinet hctl;
1745		FILE *in;
1746		FILE *out;
1747		int tpe;
1748		int curtpe;
1749		int cpnd;
1750		int sunqe;
1751		int runqe;
1752		int mcse;
1753		int ntflg;
1754		char nti[17];
1755		char nto[17];
1756		int mapflg;
1757		char mi[MAXPATHLEN];
1758		char mo[MAXPATHLEN];
1759	} proxstruct, tmpstruct;
1760	struct comvars *ip, *op;
1761
1762	abrtflag = 0;
1763	oldintr = xsignal(SIGINT, psabort);
1764	if (flag) {
1765		if (proxy)
1766			return;
1767		ip = &tmpstruct;
1768		op = &proxstruct;
1769		proxy++;
1770	} else {
1771		if (!proxy)
1772			return;
1773		ip = &proxstruct;
1774		op = &tmpstruct;
1775		proxy = 0;
1776	}
1777	ip->connect = connected;
1778	connected = op->connect;
1779	if (hostname)
1780		(void)strlcpy(ip->name, hostname, sizeof(ip->name));
1781	else
1782		ip->name[0] = '\0';
1783	hostname = op->name;
1784	ip->hctl = hisctladdr;
1785	hisctladdr = op->hctl;
1786	ip->mctl = myctladdr;
1787	myctladdr = op->mctl;
1788	ip->in = cin;
1789	cin = op->in;
1790	ip->out = cout;
1791	cout = op->out;
1792	ip->tpe = type;
1793	type = op->tpe;
1794	ip->curtpe = curtype;
1795	curtype = op->curtpe;
1796	ip->cpnd = cpend;
1797	cpend = op->cpnd;
1798	ip->sunqe = sunique;
1799	sunique = op->sunqe;
1800	ip->runqe = runique;
1801	runique = op->runqe;
1802	ip->mcse = mcase;
1803	mcase = op->mcse;
1804	ip->ntflg = ntflag;
1805	ntflag = op->ntflg;
1806	(void)strlcpy(ip->nti, ntin, sizeof(ip->nti));
1807	(void)strlcpy(ntin, op->nti, sizeof(ntin));
1808	(void)strlcpy(ip->nto, ntout, sizeof(ip->nto));
1809	(void)strlcpy(ntout, op->nto, sizeof(ntout));
1810	ip->mapflg = mapflag;
1811	mapflag = op->mapflg;
1812	(void)strlcpy(ip->mi, mapin, sizeof(ip->mi));
1813	(void)strlcpy(mapin, op->mi, sizeof(mapin));
1814	(void)strlcpy(ip->mo, mapout, sizeof(ip->mo));
1815	(void)strlcpy(mapout, op->mo, sizeof(mapout));
1816	(void)xsignal(SIGINT, oldintr);
1817	if (abrtflag) {
1818		abrtflag = 0;
1819		(*oldintr)(SIGINT);
1820	}
1821}
1822
1823void
1824abortpt(int notused)
1825{
1826
1827	sigint_raised = 1;
1828	alarmtimer(0);
1829	if (fromatty)
1830		write(fileno(ttyout), "\n", 1);
1831	ptabflg++;
1832	mflag = 0;
1833	abrtflag = 0;
1834	siglongjmp(ptabort, 1);
1835}
1836
1837void
1838proxtrans(const char *cmd, const char *local, const char *remote)
1839{
1840	sigfunc volatile oldintr;
1841	int prox_type, nfnd;
1842	int volatile secndflag;
1843	const char *volatile cmd2;
1844
1845	oldintr = NULL;
1846	secndflag = 0;
1847	if (strcmp(cmd, "RETR"))
1848		cmd2 = "RETR";
1849	else
1850		cmd2 = runique ? "STOU" : "STOR";
1851	if ((prox_type = type) == 0) {
1852		if (unix_server && unix_proxy)
1853			prox_type = TYPE_I;
1854		else
1855			prox_type = TYPE_A;
1856	}
1857	if (curtype != prox_type)
1858		changetype(prox_type, 1);
1859	if (command("PASV") != COMPLETE) {
1860		fputs("proxy server does not support third party transfers.\n",
1861		    ttyout);
1862		return;
1863	}
1864	pswitch(0);
1865	if (!connected) {
1866		fputs("No primary connection.\n", ttyout);
1867		pswitch(1);
1868		code = -1;
1869		return;
1870	}
1871	if (curtype != prox_type)
1872		changetype(prox_type, 1);
1873	if (command("PORT %s", pasv) != COMPLETE) {
1874		pswitch(1);
1875		return;
1876	}
1877	if (sigsetjmp(ptabort, 1))
1878		goto abort;
1879	oldintr = xsignal(SIGINT, abortpt);
1880	if ((restart_point &&
1881	    (command("REST " LLF, (LLT) restart_point) != CONTINUE))
1882	    || (command("%s %s", cmd, remote) != PRELIM)) {
1883		(void)xsignal(SIGINT, oldintr);
1884		pswitch(1);
1885		return;
1886	}
1887	sleep(2);
1888	pswitch(1);
1889	secndflag++;
1890	if ((restart_point &&
1891	    (command("REST " LLF, (LLT) restart_point) != CONTINUE))
1892	    || (command("%s %s", cmd2, local) != PRELIM))
1893		goto abort;
1894	ptflag++;
1895	(void)getreply(0);
1896	pswitch(0);
1897	(void)getreply(0);
1898	(void)xsignal(SIGINT, oldintr);
1899	pswitch(1);
1900	ptflag = 0;
1901	fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1902	return;
1903 abort:
1904	if (sigsetjmp(xferabort, 1)) {
1905		(void)xsignal(SIGINT, oldintr);
1906		return;
1907	}
1908	(void)xsignal(SIGINT, abort_squared);
1909	ptflag = 0;
1910	if (strcmp(cmd, "RETR") && !proxy)
1911		pswitch(1);
1912	else if (!strcmp(cmd, "RETR") && proxy)
1913		pswitch(0);
1914	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1915		if (command("%s %s", cmd2, local) != PRELIM) {
1916			pswitch(0);
1917			if (cpend)
1918				abort_remote(NULL);
1919		}
1920		pswitch(1);
1921		if (ptabflg)
1922			code = -1;
1923		(void)xsignal(SIGINT, oldintr);
1924		return;
1925	}
1926	if (cpend)
1927		abort_remote(NULL);
1928	pswitch(!proxy);
1929	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1930		if (command("%s %s", cmd2, local) != PRELIM) {
1931			pswitch(0);
1932			if (cpend)
1933				abort_remote(NULL);
1934			pswitch(1);
1935			if (ptabflg)
1936				code = -1;
1937			(void)xsignal(SIGINT, oldintr);
1938			return;
1939		}
1940	}
1941	if (cpend)
1942		abort_remote(NULL);
1943	pswitch(!proxy);
1944	if (cpend) {
1945		if ((nfnd = empty(cin, NULL, 10)) <= 0) {
1946			if (nfnd < 0)
1947				warn("Error aborting proxy command");
1948			if (ptabflg)
1949				code = -1;
1950			lostpeer(0);
1951		}
1952		(void)getreply(0);
1953		(void)getreply(0);
1954	}
1955	if (proxy)
1956		pswitch(0);
1957	pswitch(1);
1958	if (ptabflg)
1959		code = -1;
1960	(void)xsignal(SIGINT, oldintr);
1961}
1962
1963void
1964reset(int argc, char *argv[])
1965{
1966	int nfnd = 1;
1967
1968	if (argc == 0 && argv != NULL) {
1969		UPRINTF("usage: %s\n", argv[0]);
1970		code = -1;
1971		return;
1972	}
1973	while (nfnd > 0) {
1974		if ((nfnd = empty(cin, NULL, 0)) < 0) {
1975			warn("Error resetting connection");
1976			code = -1;
1977			lostpeer(0);
1978		} else if (nfnd)
1979			(void)getreply(0);
1980	}
1981}
1982
1983char *
1984gunique(const char *local)
1985{
1986	static char new[MAXPATHLEN];
1987	char *cp = strrchr(local, '/');
1988	int d, count=0, len;
1989	char ext = '1';
1990
1991	if (cp)
1992		*cp = '\0';
1993	d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1994	if (cp)
1995		*cp = '/';
1996	if (d < 0) {
1997		warn("Can't access `%s'", local);
1998		return (NULL);
1999	}
2000	len = strlcpy(new, local, sizeof(new));
2001	cp = &new[len];
2002	*cp++ = '.';
2003	while (!d) {
2004		if (++count == 100) {
2005			fputs("runique: can't find unique file name.\n",
2006			    ttyout);
2007			return (NULL);
2008		}
2009		*cp++ = ext;
2010		*cp = '\0';
2011		if (ext == '9')
2012			ext = '0';
2013		else
2014			ext++;
2015		if ((d = access(new, F_OK)) < 0)
2016			break;
2017		if (ext != '0')
2018			cp--;
2019		else if (*(cp - 2) == '.')
2020			*(cp - 1) = '1';
2021		else {
2022			*(cp - 2) = *(cp - 2) + 1;
2023			cp--;
2024		}
2025	}
2026	return (new);
2027}
2028
2029/*
2030 * abort_squared --
2031 *	aborts abort_remote(). lostpeer() is called because if the user is
2032 *	too impatient to wait or there's another problem then ftp really
2033 *	needs to get back to a known state.
2034 */
2035void
2036abort_squared(int dummy)
2037{
2038	char msgbuf[100];
2039	size_t len;
2040
2041	sigint_raised = 1;
2042	alarmtimer(0);
2043	len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n",
2044	    sizeof(msgbuf));
2045	write(fileno(ttyout), msgbuf, len);
2046	lostpeer(0);
2047	siglongjmp(xferabort, 1);
2048}
2049
2050void
2051abort_remote(FILE *din)
2052{
2053	unsigned char buf[BUFSIZ];
2054	int nfnd;
2055
2056	if (cout == NULL) {
2057		warnx("Lost control connection for abort");
2058		if (ptabflg)
2059			code = -1;
2060		lostpeer(0);
2061		return;
2062	}
2063	/*
2064	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
2065	 * after urgent byte rather than before as is protocol now
2066	 */
2067	buf[0] = IAC;
2068	buf[1] = IP;
2069	buf[2] = IAC;
2070	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
2071		warn("Can't send abort message");
2072	fprintf(cout, "%cABOR\r\n", DM);
2073	(void)fflush(cout);
2074	if ((nfnd = empty(cin, din, 10)) <= 0) {
2075		if (nfnd < 0)
2076			warn("Can't send abort message");
2077		if (ptabflg)
2078			code = -1;
2079		lostpeer(0);
2080	}
2081	if (din && (nfnd & 2)) {
2082		while (read(fileno(din), buf, BUFSIZ) > 0)
2083			continue;
2084	}
2085	if (getreply(0) == ERROR && code == 552) {
2086		/* 552 needed for nic style abort */
2087		(void)getreply(0);
2088	}
2089	(void)getreply(0);
2090}
2091
2092/*
2093 * Ensure that ai->ai_addr is NOT an IPv4 mapped address.
2094 * IPv4 mapped address complicates too many things in FTP
2095 * protocol handling, as FTP protocol is defined differently
2096 * between IPv4 and IPv6.
2097 *
2098 * This may not be the best way to handle this situation,
2099 * since the semantics of IPv4 mapped address is defined in
2100 * the kernel.  There are configurations where we should use
2101 * IPv4 mapped address as native IPv6 address, not as
2102 * "an IPv6 address that embeds IPv4 address" (namely, SIIT).
2103 *
2104 * More complete solution would be to have an additional
2105 * getsockopt to grab "real" peername/sockname.  "real"
2106 * peername/sockname will be AF_INET if IPv4 mapped address
2107 * is used to embed IPv4 address, and will be AF_INET6 if
2108 * we use it as native.  What a mess!
2109 */
2110void
2111ai_unmapped(struct addrinfo *ai)
2112{
2113#ifdef INET6
2114	struct sockaddr_in6 *sin6;
2115	struct sockaddr_in sin;
2116	socklen_t len;
2117
2118	if (ai->ai_family != AF_INET6)
2119		return;
2120	if (ai->ai_addrlen != sizeof(struct sockaddr_in6) ||
2121	    sizeof(sin) > ai->ai_addrlen)
2122		return;
2123	sin6 = (struct sockaddr_in6 *)ai->ai_addr;
2124	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
2125		return;
2126
2127	memset(&sin, 0, sizeof(sin));
2128	sin.sin_family = AF_INET;
2129	len = sizeof(struct sockaddr_in);
2130	memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
2131	    sizeof(sin.sin_addr));
2132	sin.sin_port = sin6->sin6_port;
2133
2134	ai->ai_family = AF_INET;
2135#if defined(HAVE_STRUCT_SOCKADDR_IN_SIN_LEN)
2136	sin.sin_len = len;
2137#endif
2138	memcpy(ai->ai_addr, &sin, len);
2139	ai->ai_addrlen = len;
2140#endif
2141}
2142
2143#ifdef NO_USAGE
2144void
2145xusage(void)
2146{
2147	fputs("Usage error\n", ttyout);
2148}
2149#endif
2150