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