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