xref: /original-bsd/usr.bin/ftp/ftp.c (revision 7eb91141)
1 /*
2  * Copyright (c) 1985, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ftp.c	5.38 (Berkeley) 04/22/91";
10 #endif /* not lint */
11 
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #include <sys/file.h>
18 
19 #include <netinet/in.h>
20 #include <netinet/in_systm.h>
21 #include <netinet/ip.h>
22 #include <arpa/ftp.h>
23 #include <arpa/telnet.h>
24 
25 #include <stdio.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <netdb.h>
29 #include <fcntl.h>
30 #include <pwd.h>
31 #include <varargs.h>
32 
33 #include "ftp_var.h"
34 
35 struct	sockaddr_in hisctladdr;
36 struct	sockaddr_in data_addr;
37 int	data = -1;
38 int	abrtflag = 0;
39 int	ptflag = 0;
40 struct	sockaddr_in myctladdr;
41 uid_t	getuid();
42 sig_t	lostpeer();
43 off_t	restart_point = 0;
44 
45 extern char *strerror();
46 extern int connected, errno;
47 
48 FILE	*cin, *cout;
49 FILE	*dataconn();
50 
51 char *
52 hookup(host, port)
53 	char *host;
54 	int port;
55 {
56 	register struct hostent *hp = 0;
57 	int s, len, tos;
58 	static char hostnamebuf[80];
59 
60 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
61 	hisctladdr.sin_addr.s_addr = inet_addr(host);
62 	if (hisctladdr.sin_addr.s_addr != -1) {
63 		hisctladdr.sin_family = AF_INET;
64 		(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
65 	} else {
66 		hp = gethostbyname(host);
67 		if (hp == NULL) {
68 			fprintf(stderr, "ftp: %s: ", host);
69 			herror((char *)NULL);
70 			code = -1;
71 			return((char *) 0);
72 		}
73 		hisctladdr.sin_family = hp->h_addrtype;
74 		bcopy(hp->h_addr_list[0],
75 		    (caddr_t)&hisctladdr.sin_addr, hp->h_length);
76 		(void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
77 	}
78 	hostname = hostnamebuf;
79 	s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
80 	if (s < 0) {
81 		perror("ftp: socket");
82 		code = -1;
83 		return (0);
84 	}
85 	hisctladdr.sin_port = port;
86 	while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) {
87 		if (hp && hp->h_addr_list[1]) {
88 			int oerrno = errno;
89 			extern char *inet_ntoa();
90 
91 			fprintf(stderr, "ftp: connect to address %s: ",
92 				inet_ntoa(hisctladdr.sin_addr));
93 			errno = oerrno;
94 			perror((char *) 0);
95 			hp->h_addr_list++;
96 			bcopy(hp->h_addr_list[0],
97 			     (caddr_t)&hisctladdr.sin_addr, hp->h_length);
98 			fprintf(stdout, "Trying %s...\n",
99 				inet_ntoa(hisctladdr.sin_addr));
100 			(void) close(s);
101 			s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
102 			if (s < 0) {
103 				perror("ftp: socket");
104 				code = -1;
105 				return (0);
106 			}
107 			continue;
108 		}
109 		perror("ftp: connect");
110 		code = -1;
111 		goto bad;
112 	}
113 	len = sizeof (myctladdr);
114 	if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
115 		perror("ftp: getsockname");
116 		code = -1;
117 		goto bad;
118 	}
119 #ifdef IP_TOS
120 	tos = IPTOS_LOWDELAY;
121 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
122 		perror("ftp: setsockopt TOS (ignored)");
123 #endif
124 	cin = fdopen(s, "r");
125 	cout = fdopen(s, "w");
126 	if (cin == NULL || cout == NULL) {
127 		fprintf(stderr, "ftp: fdopen failed.\n");
128 		if (cin)
129 			(void) fclose(cin);
130 		if (cout)
131 			(void) fclose(cout);
132 		code = -1;
133 		goto bad;
134 	}
135 	if (verbose)
136 		printf("Connected to %s.\n", hostname);
137 	if (getreply(0) > 2) { 	/* read startup message from server */
138 		if (cin)
139 			(void) fclose(cin);
140 		if (cout)
141 			(void) fclose(cout);
142 		code = -1;
143 		goto bad;
144 	}
145 #ifdef SO_OOBINLINE
146 	{
147 	int on = 1;
148 
149 	if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
150 		< 0 && debug) {
151 			perror("ftp: setsockopt");
152 		}
153 	}
154 #endif /* SO_OOBINLINE */
155 
156 	return (hostname);
157 bad:
158 	(void) close(s);
159 	return ((char *)0);
160 }
161 
162 login(host)
163 	char *host;
164 {
165 	char tmp[80];
166 	char *user, *pass, *acct, *getlogin(), *getpass();
167 	int n, aflag = 0;
168 
169 	user = pass = acct = 0;
170 	if (ruserpass(host, &user, &pass, &acct) < 0) {
171 		code = -1;
172 		return(0);
173 	}
174 	while (user == NULL) {
175 		char *myname = getlogin();
176 
177 		if (myname == NULL) {
178 			struct passwd *pp = getpwuid(getuid());
179 
180 			if (pp != NULL)
181 				myname = pp->pw_name;
182 		}
183 		if (myname)
184 			printf("Name (%s:%s): ", host, myname);
185 		else
186 			printf("Name (%s): ", host);
187 		(void) fgets(tmp, sizeof(tmp) - 1, stdin);
188 		tmp[strlen(tmp) - 1] = '\0';
189 		if (*tmp == '\0')
190 			user = myname;
191 		else
192 			user = tmp;
193 	}
194 	n = command("USER %s", user);
195 	if (n == CONTINUE) {
196 		if (pass == NULL)
197 			pass = getpass("Password:");
198 		n = command("PASS %s", pass);
199 	}
200 	if (n == CONTINUE) {
201 		aflag++;
202 		acct = getpass("Account:");
203 		n = command("ACCT %s", acct);
204 	}
205 	if (n != COMPLETE) {
206 		fprintf(stderr, "Login failed.\n");
207 		return (0);
208 	}
209 	if (!aflag && acct != NULL)
210 		(void) command("ACCT %s", acct);
211 	if (proxy)
212 		return(1);
213 	for (n = 0; n < macnum; ++n) {
214 		if (!strcmp("init", macros[n].mac_name)) {
215 			(void) strcpy(line, "$init");
216 			makeargv();
217 			domacro(margc, margv);
218 			break;
219 		}
220 	}
221 	return (1);
222 }
223 
224 void
225 cmdabort()
226 {
227 	extern jmp_buf ptabort;
228 
229 	printf("\n");
230 	(void) fflush(stdout);
231 	abrtflag++;
232 	if (ptflag)
233 		longjmp(ptabort,1);
234 }
235 
236 /*VARARGS*/
237 command(va_alist)
238 va_dcl
239 {
240 	va_list ap;
241 	char *fmt;
242 	int r;
243 	sig_t oldintr;
244 	void cmdabort();
245 
246 	abrtflag = 0;
247 	if (debug) {
248 		printf("---> ");
249 		va_start(ap);
250 		fmt = va_arg(ap, char *);
251 		if (strncmp("PASS ", fmt, 5) == 0)
252 			printf("PASS XXXX");
253 		else
254 			vfprintf(stdout, fmt, ap);
255 		va_end(ap);
256 		printf("\n");
257 		(void) fflush(stdout);
258 	}
259 	if (cout == NULL) {
260 		perror ("No control connection for command");
261 		code = -1;
262 		return (0);
263 	}
264 	oldintr = signal(SIGINT, cmdabort);
265 	va_start(ap);
266 	fmt = va_arg(ap, char *);
267 	vfprintf(cout, fmt, ap);
268 	va_end(ap);
269 	fprintf(cout, "\r\n");
270 	(void) fflush(cout);
271 	cpend = 1;
272 	r = getreply(!strcmp(fmt, "QUIT"));
273 	if (abrtflag && oldintr != SIG_IGN)
274 		(*oldintr)(SIGINT);
275 	(void) signal(SIGINT, oldintr);
276 	return(r);
277 }
278 
279 char reply_string[BUFSIZ];		/* last line of previous reply */
280 
281 #include <ctype.h>
282 
283 getreply(expecteof)
284 	int expecteof;
285 {
286 	register int c, n;
287 	register int dig;
288 	register char *cp;
289 	int originalcode = 0, continuation = 0;
290 	sig_t oldintr;
291 	int pflag = 0;
292 	char *pt = pasv;
293 	void cmdabort();
294 
295 	oldintr = signal(SIGINT, cmdabort);
296 	for (;;) {
297 		dig = n = code = 0;
298 		cp = reply_string;
299 		while ((c = getc(cin)) != '\n') {
300 			if (c == IAC) {     /* handle telnet commands */
301 				switch (c = getc(cin)) {
302 				case WILL:
303 				case WONT:
304 					c = getc(cin);
305 					fprintf(cout, "%c%c%c", IAC, DONT, c);
306 					(void) fflush(cout);
307 					break;
308 				case DO:
309 				case DONT:
310 					c = getc(cin);
311 					fprintf(cout, "%c%c%c", IAC, WONT, c);
312 					(void) fflush(cout);
313 					break;
314 				default:
315 					break;
316 				}
317 				continue;
318 			}
319 			dig++;
320 			if (c == EOF) {
321 				if (expecteof) {
322 					(void) signal(SIGINT,oldintr);
323 					code = 221;
324 					return (0);
325 				}
326 				lostpeer();
327 				if (verbose) {
328 					printf("421 Service not available, remote server has closed connection\n");
329 					(void) fflush(stdout);
330 				}
331 				code = 421;
332 				return(4);
333 			}
334 			if (c != '\r' && (verbose > 0 ||
335 			    (verbose > -1 && n == '5' && dig > 4))) {
336 				if (proxflag &&
337 				   (dig == 1 || dig == 5 && verbose == 0))
338 					printf("%s:",hostname);
339 				(void) putchar(c);
340 			}
341 			if (dig < 4 && isdigit(c))
342 				code = code * 10 + (c - '0');
343 			if (!pflag && code == 227)
344 				pflag = 1;
345 			if (dig > 4 && pflag == 1 && isdigit(c))
346 				pflag = 2;
347 			if (pflag == 2) {
348 				if (c != '\r' && c != ')')
349 					*pt++ = c;
350 				else {
351 					*pt = '\0';
352 					pflag = 3;
353 				}
354 			}
355 			if (dig == 4 && c == '-') {
356 				if (continuation)
357 					code = 0;
358 				continuation++;
359 			}
360 			if (n == 0)
361 				n = c;
362 			if (cp < &reply_string[sizeof(reply_string) - 1])
363 				*cp++ = c;
364 		}
365 		if (verbose > 0 || verbose > -1 && n == '5') {
366 			(void) putchar(c);
367 			(void) fflush (stdout);
368 		}
369 		if (continuation && code != originalcode) {
370 			if (originalcode == 0)
371 				originalcode = code;
372 			continue;
373 		}
374 		*cp = '\0';
375 		if (n != '1')
376 			cpend = 0;
377 		(void) signal(SIGINT,oldintr);
378 		if (code == 421 || originalcode == 421)
379 			lostpeer();
380 		if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
381 			(*oldintr)(SIGINT);
382 		return (n - '0');
383 	}
384 }
385 
386 empty(mask, sec)
387 	struct fd_set *mask;
388 	int sec;
389 {
390 	struct timeval t;
391 
392 	t.tv_sec = (long) sec;
393 	t.tv_usec = 0;
394 	return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
395 }
396 
397 jmp_buf	sendabort;
398 
399 void
400 abortsend()
401 {
402 
403 	mflag = 0;
404 	abrtflag = 0;
405 	printf("\nsend aborted\nwaiting for remote to finish abort\n");
406 	(void) fflush(stdout);
407 	longjmp(sendabort, 1);
408 }
409 
410 #define HASHBYTES 1024
411 
412 sendrequest(cmd, local, remote, printnames)
413 	char *cmd, *local, *remote;
414 	int printnames;
415 {
416 	struct stat st;
417 	struct timeval start, stop;
418 	register int c, d;
419 	FILE *fin, *dout = 0, *popen();
420 	int (*closefunc)(), pclose(), fclose();
421 	sig_t oldintr, oldintp;
422 	long bytes = 0, hashbytes = HASHBYTES;
423 	char *lmode, buf[BUFSIZ], *bufp;
424 	void abortsend();
425 
426 	if (verbose && printnames) {
427 		if (local && *local != '-')
428 			printf("local: %s ", local);
429 		if (remote)
430 			printf("remote: %s\n", remote);
431 	}
432 	if (proxy) {
433 		proxtrans(cmd, local, remote);
434 		return;
435 	}
436 	if (curtype != type)
437 		changetype(type, 0);
438 	closefunc = NULL;
439 	oldintr = NULL;
440 	oldintp = NULL;
441 	lmode = "w";
442 	if (setjmp(sendabort)) {
443 		while (cpend) {
444 			(void) getreply(0);
445 		}
446 		if (data >= 0) {
447 			(void) close(data);
448 			data = -1;
449 		}
450 		if (oldintr)
451 			(void) signal(SIGINT,oldintr);
452 		if (oldintp)
453 			(void) signal(SIGPIPE,oldintp);
454 		code = -1;
455 		return;
456 	}
457 	oldintr = signal(SIGINT, abortsend);
458 	if (strcmp(local, "-") == 0)
459 		fin = stdin;
460 	else if (*local == '|') {
461 		oldintp = signal(SIGPIPE,SIG_IGN);
462 		fin = popen(local + 1, "r");
463 		if (fin == NULL) {
464 			perror(local + 1);
465 			(void) signal(SIGINT, oldintr);
466 			(void) signal(SIGPIPE, oldintp);
467 			code = -1;
468 			return;
469 		}
470 		closefunc = pclose;
471 	} else {
472 		fin = fopen(local, "r");
473 		if (fin == NULL) {
474 			fprintf(stderr, "local: %s: %s\n", local,
475 				strerror(errno));
476 			(void) signal(SIGINT, oldintr);
477 			code = -1;
478 			return;
479 		}
480 		closefunc = fclose;
481 		if (fstat(fileno(fin), &st) < 0 ||
482 		    (st.st_mode&S_IFMT) != S_IFREG) {
483 			fprintf(stdout, "%s: not a plain file.\n", local);
484 			(void) signal(SIGINT, oldintr);
485 			fclose(fin);
486 			code = -1;
487 			return;
488 		}
489 	}
490 	if (initconn()) {
491 		(void) signal(SIGINT, oldintr);
492 		if (oldintp)
493 			(void) signal(SIGPIPE, oldintp);
494 		code = -1;
495 		if (closefunc != NULL)
496 			(*closefunc)(fin);
497 		return;
498 	}
499 	if (setjmp(sendabort))
500 		goto abort;
501 
502 	if (restart_point &&
503 	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
504 		if (fseek(fin, (long) restart_point, 0) < 0) {
505 			fprintf(stderr, "local: %s: %s\n", local,
506 				strerror(errno));
507 			restart_point = 0;
508 			if (closefunc != NULL)
509 				(*closefunc)(fin);
510 			return;
511 		}
512 		if (command("REST %ld", (long) restart_point)
513 			!= CONTINUE) {
514 			restart_point = 0;
515 			if (closefunc != NULL)
516 				(*closefunc)(fin);
517 			return;
518 		}
519 		restart_point = 0;
520 		lmode = "r+w";
521 	}
522 	if (remote) {
523 		if (command("%s %s", cmd, remote) != PRELIM) {
524 			(void) signal(SIGINT, oldintr);
525 			if (oldintp)
526 				(void) signal(SIGPIPE, oldintp);
527 			if (closefunc != NULL)
528 				(*closefunc)(fin);
529 			return;
530 		}
531 	} else
532 		if (command("%s", cmd) != PRELIM) {
533 			(void) signal(SIGINT, oldintr);
534 			if (oldintp)
535 				(void) signal(SIGPIPE, oldintp);
536 			if (closefunc != NULL)
537 				(*closefunc)(fin);
538 			return;
539 		}
540 	dout = dataconn(lmode);
541 	if (dout == NULL)
542 		goto abort;
543 	(void) gettimeofday(&start, (struct timezone *)0);
544 	oldintp = signal(SIGPIPE, SIG_IGN);
545 	switch (curtype) {
546 
547 	case TYPE_I:
548 	case TYPE_L:
549 		errno = d = 0;
550 		while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) {
551 			bytes += c;
552 			for (bufp = buf; c > 0; c -= d, bufp += d)
553 				if ((d = write(fileno(dout), bufp, c)) <= 0)
554 					break;
555 			if (hash) {
556 				while (bytes >= hashbytes) {
557 					(void) putchar('#');
558 					hashbytes += HASHBYTES;
559 				}
560 				(void) fflush(stdout);
561 			}
562 		}
563 		if (hash && bytes > 0) {
564 			if (bytes < HASHBYTES)
565 				(void) putchar('#');
566 			(void) putchar('\n');
567 			(void) fflush(stdout);
568 		}
569 		if (c < 0)
570 			fprintf(stderr, "local: %s: %s\n", local,
571 				strerror(errno));
572 		if (d < 0) {
573 			if (errno != EPIPE)
574 				perror("netout");
575 			bytes = -1;
576 		}
577 		break;
578 
579 	case TYPE_A:
580 		while ((c = getc(fin)) != EOF) {
581 			if (c == '\n') {
582 				while (hash && (bytes >= hashbytes)) {
583 					(void) putchar('#');
584 					(void) fflush(stdout);
585 					hashbytes += HASHBYTES;
586 				}
587 				if (ferror(dout))
588 					break;
589 				(void) putc('\r', dout);
590 				bytes++;
591 			}
592 			(void) putc(c, dout);
593 			bytes++;
594 	/*		if (c == '\r') {			  	*/
595 	/*		(void)	putc('\0', dout);  /* this violates rfc */
596 	/*			bytes++;				*/
597 	/*		}                          			*/
598 		}
599 		if (hash) {
600 			if (bytes < hashbytes)
601 				(void) putchar('#');
602 			(void) putchar('\n');
603 			(void) fflush(stdout);
604 		}
605 		if (ferror(fin))
606 			fprintf(stderr, "local: %s: %s\n", local,
607 				strerror(errno));
608 		if (ferror(dout)) {
609 			if (errno != EPIPE)
610 				perror("netout");
611 			bytes = -1;
612 		}
613 		break;
614 	}
615 	(void) gettimeofday(&stop, (struct timezone *)0);
616 	if (closefunc != NULL)
617 		(*closefunc)(fin);
618 	(void) fclose(dout);
619 	(void) getreply(0);
620 	(void) signal(SIGINT, oldintr);
621 	if (oldintp)
622 		(void) signal(SIGPIPE, oldintp);
623 	if (bytes > 0)
624 		ptransfer("sent", bytes, &start, &stop);
625 	return;
626 abort:
627 	(void) gettimeofday(&stop, (struct timezone *)0);
628 	(void) signal(SIGINT, oldintr);
629 	if (oldintp)
630 		(void) signal(SIGPIPE, oldintp);
631 	if (!cpend) {
632 		code = -1;
633 		return;
634 	}
635 	if (data >= 0) {
636 		(void) close(data);
637 		data = -1;
638 	}
639 	if (dout)
640 		(void) fclose(dout);
641 	(void) getreply(0);
642 	code = -1;
643 	if (closefunc != NULL && fin != NULL)
644 		(*closefunc)(fin);
645 	if (bytes > 0)
646 		ptransfer("sent", bytes, &start, &stop);
647 }
648 
649 jmp_buf	recvabort;
650 
651 void
652 abortrecv()
653 {
654 
655 	mflag = 0;
656 	abrtflag = 0;
657 	printf("\nreceive aborted\nwaiting for remote to finish abort\n");
658 	(void) fflush(stdout);
659 	longjmp(recvabort, 1);
660 }
661 
662 recvrequest(cmd, local, remote, lmode, printnames)
663 	char *cmd, *local, *remote, *lmode;
664 {
665 	FILE *fout, *din = 0, *popen();
666 	int (*closefunc)(), pclose(), fclose();
667 	sig_t oldintr, oldintp;
668 	int is_retr, tcrflag, bare_lfs = 0;
669 	char *gunique();
670 	static int bufsize;
671 	static char *buf;
672 	long bytes = 0, hashbytes = HASHBYTES;
673 	register int c, d;
674 	struct timeval start, stop;
675 	struct stat st;
676 	off_t lseek();
677 	void abortrecv();
678 	char *malloc();
679 
680 	is_retr = strcmp(cmd, "RETR") == 0;
681 	if (is_retr && verbose && printnames) {
682 		if (local && *local != '-')
683 			printf("local: %s ", local);
684 		if (remote)
685 			printf("remote: %s\n", remote);
686 	}
687 	if (proxy && is_retr) {
688 		proxtrans(cmd, local, remote);
689 		return;
690 	}
691 	closefunc = NULL;
692 	oldintr = NULL;
693 	oldintp = NULL;
694 	tcrflag = !crflag && is_retr;
695 	if (setjmp(recvabort)) {
696 		while (cpend) {
697 			(void) getreply(0);
698 		}
699 		if (data >= 0) {
700 			(void) close(data);
701 			data = -1;
702 		}
703 		if (oldintr)
704 			(void) signal(SIGINT, oldintr);
705 		code = -1;
706 		return;
707 	}
708 	oldintr = signal(SIGINT, abortrecv);
709 	if (strcmp(local, "-") && *local != '|') {
710 		if (access(local, 2) < 0) {
711 			char *dir = rindex(local, '/');
712 
713 			if (errno != ENOENT && errno != EACCES) {
714 				fprintf(stderr, "local: %s: %s\n", local,
715 					strerror(errno));
716 				(void) signal(SIGINT, oldintr);
717 				code = -1;
718 				return;
719 			}
720 			if (dir != NULL)
721 				*dir = 0;
722 			d = access(dir ? local : ".", 2);
723 			if (dir != NULL)
724 				*dir = '/';
725 			if (d < 0) {
726 				fprintf(stderr, "local: %s: %s\n", local,
727 					strerror(errno));
728 				(void) signal(SIGINT, oldintr);
729 				code = -1;
730 				return;
731 			}
732 			if (!runique && errno == EACCES &&
733 			    chmod(local, 0600) < 0) {
734 				fprintf(stderr, "local: %s: %s\n", local,
735 					strerror(errno));
736 				(void) signal(SIGINT, oldintr);
737 				(void) signal(SIGINT, oldintr);
738 				code = -1;
739 				return;
740 			}
741 			if (runique && errno == EACCES &&
742 			   (local = gunique(local)) == NULL) {
743 				(void) signal(SIGINT, oldintr);
744 				code = -1;
745 				return;
746 			}
747 		}
748 		else if (runique && (local = gunique(local)) == NULL) {
749 			(void) signal(SIGINT, oldintr);
750 			code = -1;
751 			return;
752 		}
753 	}
754 	if (!is_retr) {
755 		if (curtype != TYPE_A)
756 			changetype(TYPE_A, 0);
757 	} else if (curtype != type)
758 		changetype(type, 0);
759 	if (initconn()) {
760 		(void) signal(SIGINT, oldintr);
761 		code = -1;
762 		return;
763 	}
764 	if (setjmp(recvabort))
765 		goto abort;
766 	if (is_retr && restart_point &&
767 	    command("REST %ld", (long) restart_point) != CONTINUE)
768 		return;
769 	if (remote) {
770 		if (command("%s %s", cmd, remote) != PRELIM) {
771 			(void) signal(SIGINT, oldintr);
772 			return;
773 		}
774 	} else {
775 		if (command("%s", cmd) != PRELIM) {
776 			(void) signal(SIGINT, oldintr);
777 			return;
778 		}
779 	}
780 	din = dataconn("r");
781 	if (din == NULL)
782 		goto abort;
783 	if (strcmp(local, "-") == 0)
784 		fout = stdout;
785 	else if (*local == '|') {
786 		oldintp = signal(SIGPIPE, SIG_IGN);
787 		fout = popen(local + 1, "w");
788 		if (fout == NULL) {
789 			perror(local+1);
790 			goto abort;
791 		}
792 		closefunc = pclose;
793 	} else {
794 		fout = fopen(local, lmode);
795 		if (fout == NULL) {
796 			fprintf(stderr, "local: %s: %s\n", local,
797 				strerror(errno));
798 			goto abort;
799 		}
800 		closefunc = fclose;
801 	}
802 	if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
803 		st.st_blksize = BUFSIZ;
804 	if (st.st_blksize > bufsize) {
805 		if (buf)
806 			(void) free(buf);
807 		buf = malloc((unsigned)st.st_blksize);
808 		if (buf == NULL) {
809 			perror("malloc");
810 			bufsize = 0;
811 			goto abort;
812 		}
813 		bufsize = st.st_blksize;
814 	}
815 	(void) gettimeofday(&start, (struct timezone *)0);
816 	switch (curtype) {
817 
818 	case TYPE_I:
819 	case TYPE_L:
820 		if (restart_point &&
821 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
822 			fprintf(stderr, "local: %s: %s\n", local,
823 				strerror(errno));
824 			if (closefunc != NULL)
825 				(*closefunc)(fout);
826 			return;
827 		}
828 		errno = d = 0;
829 		while ((c = read(fileno(din), buf, bufsize)) > 0) {
830 			if ((d = write(fileno(fout), buf, c)) != c)
831 				break;
832 			bytes += c;
833 			if (hash) {
834 				while (bytes >= hashbytes) {
835 					(void) putchar('#');
836 					hashbytes += HASHBYTES;
837 				}
838 				(void) fflush(stdout);
839 			}
840 		}
841 		if (hash && bytes > 0) {
842 			if (bytes < HASHBYTES)
843 				(void) putchar('#');
844 			(void) putchar('\n');
845 			(void) fflush(stdout);
846 		}
847 		if (c < 0) {
848 			if (errno != EPIPE)
849 				perror("netin");
850 			bytes = -1;
851 		}
852 		if (d < c) {
853 			if (d < 0)
854 				fprintf(stderr, "local: %s: %s\n", local,
855 					strerror(errno));
856 			else
857 				fprintf(stderr, "%s: short write\n", local);
858 		}
859 		break;
860 
861 	case TYPE_A:
862 		if (restart_point) {
863 			register int i, n, ch;
864 
865 			if (fseek(fout, 0L, L_SET) < 0)
866 				goto done;
867 			n = restart_point;
868 			for (i = 0; i++ < n;) {
869 				if ((ch = getc(fout)) == EOF)
870 					goto done;
871 				if (ch == '\n')
872 					i++;
873 			}
874 			if (fseek(fout, 0L, L_INCR) < 0) {
875 done:
876 				fprintf(stderr, "local: %s: %s\n", local,
877 					strerror(errno));
878 				if (closefunc != NULL)
879 					(*closefunc)(fout);
880 				return;
881 			}
882 		}
883 		while ((c = getc(din)) != EOF) {
884 			if (c == '\n')
885 				bare_lfs++;
886 			while (c == '\r') {
887 				while (hash && (bytes >= hashbytes)) {
888 					(void) putchar('#');
889 					(void) fflush(stdout);
890 					hashbytes += HASHBYTES;
891 				}
892 				bytes++;
893 				if ((c = getc(din)) != '\n' || tcrflag) {
894 					if (ferror(fout))
895 						goto break2;
896 					(void) putc('\r', fout);
897 					if (c == '\0') {
898 						bytes++;
899 						goto contin2;
900 					}
901 					if (c == EOF)
902 						goto contin2;
903 				}
904 			}
905 			(void) putc(c, fout);
906 			bytes++;
907 	contin2:	;
908 		}
909 break2:
910 		if (bare_lfs) {
911 			printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs);
912 			printf("File may not have transferred correctly.\n");
913 		}
914 		if (hash) {
915 			if (bytes < hashbytes)
916 				(void) putchar('#');
917 			(void) putchar('\n');
918 			(void) fflush(stdout);
919 		}
920 		if (ferror(din)) {
921 			if (errno != EPIPE)
922 				perror("netin");
923 			bytes = -1;
924 		}
925 		if (ferror(fout))
926 			fprintf(stderr, "local: %s: %s\n", local,
927 				strerror(errno));
928 		break;
929 	}
930 	if (closefunc != NULL)
931 		(*closefunc)(fout);
932 	(void) signal(SIGINT, oldintr);
933 	if (oldintp)
934 		(void) signal(SIGPIPE, oldintp);
935 	(void) gettimeofday(&stop, (struct timezone *)0);
936 	(void) fclose(din);
937 	(void) getreply(0);
938 	if (bytes > 0 && is_retr)
939 		ptransfer("received", bytes, &start, &stop);
940 	return;
941 abort:
942 
943 /* abort using RFC959 recommended IP,SYNC sequence  */
944 
945 	(void) gettimeofday(&stop, (struct timezone *)0);
946 	if (oldintp)
947 		(void) signal(SIGPIPE, oldintr);
948 	(void) signal(SIGINT, SIG_IGN);
949 	if (!cpend) {
950 		code = -1;
951 		(void) signal(SIGINT, oldintr);
952 		return;
953 	}
954 
955 	abort_remote(din);
956 	code = -1;
957 	if (data >= 0) {
958 		(void) close(data);
959 		data = -1;
960 	}
961 	if (closefunc != NULL && fout != NULL)
962 		(*closefunc)(fout);
963 	if (din)
964 		(void) fclose(din);
965 	if (bytes > 0)
966 		ptransfer("received", bytes, &start, &stop);
967 	(void) signal(SIGINT, oldintr);
968 }
969 
970 /*
971  * Need to start a listen on the data channel before we send the command,
972  * otherwise the server's connect may fail.
973  */
974 initconn()
975 {
976 	register char *p, *a;
977 	int result, len, tmpno = 0;
978 	int on = 1;
979 
980 noport:
981 	data_addr = myctladdr;
982 	if (sendport)
983 		data_addr.sin_port = 0;	/* let system pick one */
984 	if (data != -1)
985 		(void) close(data);
986 	data = socket(AF_INET, SOCK_STREAM, 0);
987 	if (data < 0) {
988 		perror("ftp: socket");
989 		if (tmpno)
990 			sendport = 1;
991 		return (1);
992 	}
993 	if (!sendport)
994 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
995 			perror("ftp: setsockopt (reuse address)");
996 			goto bad;
997 		}
998 	if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) {
999 		perror("ftp: bind");
1000 		goto bad;
1001 	}
1002 	if (options & SO_DEBUG &&
1003 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
1004 		perror("ftp: setsockopt (ignored)");
1005 	len = sizeof (data_addr);
1006 	if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1007 		perror("ftp: getsockname");
1008 		goto bad;
1009 	}
1010 	if (listen(data, 1) < 0)
1011 		perror("ftp: listen");
1012 	if (sendport) {
1013 		a = (char *)&data_addr.sin_addr;
1014 		p = (char *)&data_addr.sin_port;
1015 #define	UC(b)	(((int)b)&0xff)
1016 		result =
1017 		    command("PORT %d,%d,%d,%d,%d,%d",
1018 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1019 		      UC(p[0]), UC(p[1]));
1020 		if (result == ERROR && sendport == -1) {
1021 			sendport = 0;
1022 			tmpno = 1;
1023 			goto noport;
1024 		}
1025 		return (result != COMPLETE);
1026 	}
1027 	if (tmpno)
1028 		sendport = 1;
1029 #ifdef IP_TOS
1030 	on = IPTOS_THROUGHPUT;
1031 	if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1032 		perror("ftp: setsockopt TOS (ignored)");
1033 #endif
1034 	return (0);
1035 bad:
1036 	(void) close(data), data = -1;
1037 	if (tmpno)
1038 		sendport = 1;
1039 	return (1);
1040 }
1041 
1042 FILE *
1043 dataconn(lmode)
1044 	char *lmode;
1045 {
1046 	struct sockaddr_in from;
1047 	int s, fromlen = sizeof (from), tos;
1048 
1049 	s = accept(data, (struct sockaddr *) &from, &fromlen);
1050 	if (s < 0) {
1051 		perror("ftp: accept");
1052 		(void) close(data), data = -1;
1053 		return (NULL);
1054 	}
1055 	(void) close(data);
1056 	data = s;
1057 #ifdef IP_TOS
1058 	tos = IPTOS_THROUGHPUT;
1059 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1060 		perror("ftp: setsockopt TOS (ignored)");
1061 #endif
1062 	return (fdopen(data, lmode));
1063 }
1064 
1065 ptransfer(direction, bytes, t0, t1)
1066 	char *direction;
1067 	long bytes;
1068 	struct timeval *t0, *t1;
1069 {
1070 	struct timeval td;
1071 	float s, bs;
1072 
1073 	if (verbose) {
1074 		tvsub(&td, t1, t0);
1075 		s = td.tv_sec + (td.tv_usec / 1000000.);
1076 #define	nz(x)	((x) == 0 ? 1 : (x))
1077 		bs = bytes / nz(s);
1078 		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
1079 		    bytes, direction, s, bs / 1024.);
1080 	}
1081 }
1082 
1083 /*tvadd(tsum, t0)
1084 	struct timeval *tsum, *t0;
1085 {
1086 
1087 	tsum->tv_sec += t0->tv_sec;
1088 	tsum->tv_usec += t0->tv_usec;
1089 	if (tsum->tv_usec > 1000000)
1090 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
1091 } */
1092 
1093 tvsub(tdiff, t1, t0)
1094 	struct timeval *tdiff, *t1, *t0;
1095 {
1096 
1097 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1098 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1099 	if (tdiff->tv_usec < 0)
1100 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1101 }
1102 
1103 void
1104 psabort()
1105 {
1106 	extern int abrtflag;
1107 
1108 	abrtflag++;
1109 }
1110 
1111 pswitch(flag)
1112 	int flag;
1113 {
1114 	extern int proxy, abrtflag;
1115 	sig_t oldintr;
1116 	static struct comvars {
1117 		int connect;
1118 		char name[MAXHOSTNAMELEN];
1119 		struct sockaddr_in mctl;
1120 		struct sockaddr_in hctl;
1121 		FILE *in;
1122 		FILE *out;
1123 		int tpe;
1124 		int curtpe;
1125 		int cpnd;
1126 		int sunqe;
1127 		int runqe;
1128 		int mcse;
1129 		int ntflg;
1130 		char nti[17];
1131 		char nto[17];
1132 		int mapflg;
1133 		char mi[MAXPATHLEN];
1134 		char mo[MAXPATHLEN];
1135 	} proxstruct, tmpstruct;
1136 	struct comvars *ip, *op;
1137 
1138 	abrtflag = 0;
1139 	oldintr = signal(SIGINT, psabort);
1140 	if (flag) {
1141 		if (proxy)
1142 			return;
1143 		ip = &tmpstruct;
1144 		op = &proxstruct;
1145 		proxy++;
1146 	} else {
1147 		if (!proxy)
1148 			return;
1149 		ip = &proxstruct;
1150 		op = &tmpstruct;
1151 		proxy = 0;
1152 	}
1153 	ip->connect = connected;
1154 	connected = op->connect;
1155 	if (hostname) {
1156 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1157 		ip->name[strlen(ip->name)] = '\0';
1158 	} else
1159 		ip->name[0] = 0;
1160 	hostname = op->name;
1161 	ip->hctl = hisctladdr;
1162 	hisctladdr = op->hctl;
1163 	ip->mctl = myctladdr;
1164 	myctladdr = op->mctl;
1165 	ip->in = cin;
1166 	cin = op->in;
1167 	ip->out = cout;
1168 	cout = op->out;
1169 	ip->tpe = type;
1170 	type = op->tpe;
1171 	ip->curtpe = curtype;
1172 	curtype = op->curtpe;
1173 	ip->cpnd = cpend;
1174 	cpend = op->cpnd;
1175 	ip->sunqe = sunique;
1176 	sunique = op->sunqe;
1177 	ip->runqe = runique;
1178 	runique = op->runqe;
1179 	ip->mcse = mcase;
1180 	mcase = op->mcse;
1181 	ip->ntflg = ntflag;
1182 	ntflag = op->ntflg;
1183 	(void) strncpy(ip->nti, ntin, 16);
1184 	(ip->nti)[strlen(ip->nti)] = '\0';
1185 	(void) strcpy(ntin, op->nti);
1186 	(void) strncpy(ip->nto, ntout, 16);
1187 	(ip->nto)[strlen(ip->nto)] = '\0';
1188 	(void) strcpy(ntout, op->nto);
1189 	ip->mapflg = mapflag;
1190 	mapflag = op->mapflg;
1191 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1192 	(ip->mi)[strlen(ip->mi)] = '\0';
1193 	(void) strcpy(mapin, op->mi);
1194 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1195 	(ip->mo)[strlen(ip->mo)] = '\0';
1196 	(void) strcpy(mapout, op->mo);
1197 	(void) signal(SIGINT, oldintr);
1198 	if (abrtflag) {
1199 		abrtflag = 0;
1200 		(*oldintr)(SIGINT);
1201 	}
1202 }
1203 
1204 jmp_buf ptabort;
1205 int ptabflg;
1206 
1207 void
1208 abortpt()
1209 {
1210 	printf("\n");
1211 	(void) fflush(stdout);
1212 	ptabflg++;
1213 	mflag = 0;
1214 	abrtflag = 0;
1215 	longjmp(ptabort, 1);
1216 }
1217 
1218 proxtrans(cmd, local, remote)
1219 	char *cmd, *local, *remote;
1220 {
1221 	sig_t oldintr;
1222 	int secndflag = 0, prox_type, nfnd;
1223 	extern jmp_buf ptabort;
1224 	char *cmd2;
1225 	struct fd_set mask;
1226 	void abortpt();
1227 
1228 	if (strcmp(cmd, "RETR"))
1229 		cmd2 = "RETR";
1230 	else
1231 		cmd2 = runique ? "STOU" : "STOR";
1232 	if ((prox_type = type) == 0) {
1233 		if (unix_server && unix_proxy)
1234 			prox_type = TYPE_I;
1235 		else
1236 			prox_type = TYPE_A;
1237 	}
1238 	if (curtype != prox_type)
1239 		changetype(prox_type, 1);
1240 	if (command("PASV") != COMPLETE) {
1241 		printf("proxy server does not support third party transfers.\n");
1242 		return;
1243 	}
1244 	pswitch(0);
1245 	if (!connected) {
1246 		printf("No primary connection\n");
1247 		pswitch(1);
1248 		code = -1;
1249 		return;
1250 	}
1251 	if (curtype != prox_type)
1252 		changetype(prox_type, 1);
1253 	if (command("PORT %s", pasv) != COMPLETE) {
1254 		pswitch(1);
1255 		return;
1256 	}
1257 	if (setjmp(ptabort))
1258 		goto abort;
1259 	oldintr = signal(SIGINT, abortpt);
1260 	if (command("%s %s", cmd, remote) != PRELIM) {
1261 		(void) signal(SIGINT, oldintr);
1262 		pswitch(1);
1263 		return;
1264 	}
1265 	sleep(2);
1266 	pswitch(1);
1267 	secndflag++;
1268 	if (command("%s %s", cmd2, local) != PRELIM)
1269 		goto abort;
1270 	ptflag++;
1271 	(void) getreply(0);
1272 	pswitch(0);
1273 	(void) getreply(0);
1274 	(void) signal(SIGINT, oldintr);
1275 	pswitch(1);
1276 	ptflag = 0;
1277 	printf("local: %s remote: %s\n", local, remote);
1278 	return;
1279 abort:
1280 	(void) signal(SIGINT, SIG_IGN);
1281 	ptflag = 0;
1282 	if (strcmp(cmd, "RETR") && !proxy)
1283 		pswitch(1);
1284 	else if (!strcmp(cmd, "RETR") && proxy)
1285 		pswitch(0);
1286 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1287 		if (command("%s %s", cmd2, local) != PRELIM) {
1288 			pswitch(0);
1289 			if (cpend)
1290 				abort_remote((FILE *) NULL);
1291 		}
1292 		pswitch(1);
1293 		if (ptabflg)
1294 			code = -1;
1295 		(void) signal(SIGINT, oldintr);
1296 		return;
1297 	}
1298 	if (cpend)
1299 		abort_remote((FILE *) NULL);
1300 	pswitch(!proxy);
1301 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1302 		if (command("%s %s", cmd2, local) != PRELIM) {
1303 			pswitch(0);
1304 			if (cpend)
1305 				abort_remote((FILE *) NULL);
1306 			pswitch(1);
1307 			if (ptabflg)
1308 				code = -1;
1309 			(void) signal(SIGINT, oldintr);
1310 			return;
1311 		}
1312 	}
1313 	if (cpend)
1314 		abort_remote((FILE *) NULL);
1315 	pswitch(!proxy);
1316 	if (cpend) {
1317 		FD_ZERO(&mask);
1318 		FD_SET(fileno(cin), &mask);
1319 		if ((nfnd = empty(&mask, 10)) <= 0) {
1320 			if (nfnd < 0) {
1321 				perror("abort");
1322 			}
1323 			if (ptabflg)
1324 				code = -1;
1325 			lostpeer();
1326 		}
1327 		(void) getreply(0);
1328 		(void) getreply(0);
1329 	}
1330 	if (proxy)
1331 		pswitch(0);
1332 	pswitch(1);
1333 	if (ptabflg)
1334 		code = -1;
1335 	(void) signal(SIGINT, oldintr);
1336 }
1337 
1338 reset()
1339 {
1340 	struct fd_set mask;
1341 	int nfnd = 1;
1342 
1343 	FD_ZERO(&mask);
1344 	while (nfnd > 0) {
1345 		FD_SET(fileno(cin), &mask);
1346 		if ((nfnd = empty(&mask,0)) < 0) {
1347 			perror("reset");
1348 			code = -1;
1349 			lostpeer();
1350 		}
1351 		else if (nfnd) {
1352 			(void) getreply(0);
1353 		}
1354 	}
1355 }
1356 
1357 char *
1358 gunique(local)
1359 	char *local;
1360 {
1361 	static char new[MAXPATHLEN];
1362 	char *cp = rindex(local, '/');
1363 	int d, count=0;
1364 	char ext = '1';
1365 
1366 	if (cp)
1367 		*cp = '\0';
1368 	d = access(cp ? local : ".", 2);
1369 	if (cp)
1370 		*cp = '/';
1371 	if (d < 0) {
1372 		fprintf(stderr, "local: %s: %s\n", local, strerror(errno));
1373 		return((char *) 0);
1374 	}
1375 	(void) strcpy(new, local);
1376 	cp = new + strlen(new);
1377 	*cp++ = '.';
1378 	while (!d) {
1379 		if (++count == 100) {
1380 			printf("runique: can't find unique file name.\n");
1381 			return((char *) 0);
1382 		}
1383 		*cp++ = ext;
1384 		*cp = '\0';
1385 		if (ext == '9')
1386 			ext = '0';
1387 		else
1388 			ext++;
1389 		if ((d = access(new, 0)) < 0)
1390 			break;
1391 		if (ext != '0')
1392 			cp--;
1393 		else if (*(cp - 2) == '.')
1394 			*(cp - 1) = '1';
1395 		else {
1396 			*(cp - 2) = *(cp - 2) + 1;
1397 			cp--;
1398 		}
1399 	}
1400 	return(new);
1401 }
1402 
1403 abort_remote(din)
1404 FILE *din;
1405 {
1406 	char buf[BUFSIZ];
1407 	int nfnd;
1408 	struct fd_set mask;
1409 
1410 	/*
1411 	 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1412 	 * after urgent byte rather than before as is protocol now
1413 	 */
1414 	sprintf(buf, "%c%c%c", IAC, IP, IAC);
1415 	if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1416 		perror("abort");
1417 	fprintf(cout,"%cABOR\r\n", DM);
1418 	(void) fflush(cout);
1419 	FD_ZERO(&mask);
1420 	FD_SET(fileno(cin), &mask);
1421 	if (din) {
1422 		FD_SET(fileno(din), &mask);
1423 	}
1424 	if ((nfnd = empty(&mask, 10)) <= 0) {
1425 		if (nfnd < 0) {
1426 			perror("abort");
1427 		}
1428 		if (ptabflg)
1429 			code = -1;
1430 		lostpeer();
1431 	}
1432 	if (din && FD_ISSET(fileno(din), &mask)) {
1433 		while (read(fileno(din), buf, BUFSIZ) > 0)
1434 			/* LOOP */;
1435 	}
1436 	if (getreply(0) == ERROR && code == 552) {
1437 		/* 552 needed for nic style abort */
1438 		(void) getreply(0);
1439 	}
1440 	(void) getreply(0);
1441 }
1442