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