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