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