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