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