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