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