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