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