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