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