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