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