xref: /original-bsd/usr.bin/ftp/ftp.c (revision 6cca134b)
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.19 (Berkeley) 06/29/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(), *mygetpass();
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 = mygetpass("Password:");
192 		n = command("PASS %s", pass);
193 	}
194 	if (n == CONTINUE) {
195 		aflag++;
196 		acct = mygetpass("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, *mypopen();
384 	int (*closefunc)(), mypclose(), 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 = mypopen(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 = mypclose;
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 && verbose)
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 && verbose)
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, *mypopen();
576 	int (*closefunc)(), mypclose(), 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 = mypopen(local + 1, "w");
713 		if (fout == NULL) {
714 			perror(local+1);
715 			goto abort;
716 		}
717 		closefunc = mypclose;
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 && verbose)
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 && verbose)
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 	tvsub(&td, t1, t0);
988 	s = td.tv_sec + (td.tv_usec / 1000000.);
989 #define	nz(x)	((x) == 0 ? 1 : (x))
990 	bs = bytes / nz(s);
991 	if (local && *local != '-')
992 		printf("local: %s ", local);
993 	if (remote)
994 		printf("remote: %s\n", remote);
995 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
996 		bytes, direction, s, bs / 1024.);
997 }
998 
999 /*tvadd(tsum, t0)
1000 	struct timeval *tsum, *t0;
1001 {
1002 
1003 	tsum->tv_sec += t0->tv_sec;
1004 	tsum->tv_usec += t0->tv_usec;
1005 	if (tsum->tv_usec > 1000000)
1006 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
1007 } */
1008 
1009 tvsub(tdiff, t1, t0)
1010 	struct timeval *tdiff, *t1, *t0;
1011 {
1012 
1013 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
1014 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
1015 	if (tdiff->tv_usec < 0)
1016 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
1017 }
1018 
1019 psabort()
1020 {
1021 	extern int abrtflag;
1022 
1023 	abrtflag++;
1024 }
1025 
1026 pswitch(flag)
1027 	int flag;
1028 {
1029 	extern int proxy, abrtflag;
1030 	int (*oldintr)();
1031 	static struct comvars {
1032 		int connect;
1033 		char name[MAXHOSTNAMELEN];
1034 		struct sockaddr_in mctl;
1035 		struct sockaddr_in hctl;
1036 		FILE *in;
1037 		FILE *out;
1038 		int tpe;
1039 		int cpnd;
1040 		int sunqe;
1041 		int runqe;
1042 		int mcse;
1043 		int ntflg;
1044 		char nti[17];
1045 		char nto[17];
1046 		int mapflg;
1047 		char mi[MAXPATHLEN];
1048 		char mo[MAXPATHLEN];
1049 		} proxstruct, tmpstruct;
1050 	struct comvars *ip, *op;
1051 
1052 	abrtflag = 0;
1053 	oldintr = signal(SIGINT, psabort);
1054 	if (flag) {
1055 		if (proxy)
1056 			return;
1057 		ip = &tmpstruct;
1058 		op = &proxstruct;
1059 		proxy++;
1060 	}
1061 	else {
1062 		if (!proxy)
1063 			return;
1064 		ip = &proxstruct;
1065 		op = &tmpstruct;
1066 		proxy = 0;
1067 	}
1068 	ip->connect = connected;
1069 	connected = op->connect;
1070 	if (hostname) {
1071 		(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1072 		ip->name[strlen(ip->name)] = '\0';
1073 	} else
1074 		ip->name[0] = 0;
1075 	hostname = op->name;
1076 	ip->hctl = hisctladdr;
1077 	hisctladdr = op->hctl;
1078 	ip->mctl = myctladdr;
1079 	myctladdr = op->mctl;
1080 	ip->in = cin;
1081 	cin = op->in;
1082 	ip->out = cout;
1083 	cout = op->out;
1084 	ip->tpe = type;
1085 	type = op->tpe;
1086 	if (!type)
1087 		type = 1;
1088 	ip->cpnd = cpend;
1089 	cpend = op->cpnd;
1090 	ip->sunqe = sunique;
1091 	sunique = op->sunqe;
1092 	ip->runqe = runique;
1093 	runique = op->runqe;
1094 	ip->mcse = mcase;
1095 	mcase = op->mcse;
1096 	ip->ntflg = ntflag;
1097 	ntflag = op->ntflg;
1098 	(void) strncpy(ip->nti, ntin, 16);
1099 	(ip->nti)[strlen(ip->nti)] = '\0';
1100 	(void) strcpy(ntin, op->nti);
1101 	(void) strncpy(ip->nto, ntout, 16);
1102 	(ip->nto)[strlen(ip->nto)] = '\0';
1103 	(void) strcpy(ntout, op->nto);
1104 	ip->mapflg = mapflag;
1105 	mapflag = op->mapflg;
1106 	(void) strncpy(ip->mi, mapin, MAXPATHLEN - 1);
1107 	(ip->mi)[strlen(ip->mi)] = '\0';
1108 	(void) strcpy(mapin, op->mi);
1109 	(void) strncpy(ip->mo, mapout, MAXPATHLEN - 1);
1110 	(ip->mo)[strlen(ip->mo)] = '\0';
1111 	(void) strcpy(mapout, op->mo);
1112 	(void) signal(SIGINT, oldintr);
1113 	if (abrtflag) {
1114 		abrtflag = 0;
1115 		(*oldintr)();
1116 	}
1117 }
1118 
1119 jmp_buf ptabort;
1120 int ptabflg;
1121 
1122 abortpt()
1123 {
1124 	printf("\n");
1125 	(void) fflush(stdout);
1126 	ptabflg++;
1127 	mflag = 0;
1128 	abrtflag = 0;
1129 	longjmp(ptabort, 1);
1130 }
1131 
1132 proxtrans(cmd, local, remote)
1133 	char *cmd, *local, *remote;
1134 {
1135 	int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd;
1136 	extern jmp_buf ptabort;
1137 	char *cmd2;
1138 	struct fd_set mask;
1139 
1140 	if (strcmp(cmd, "RETR"))
1141 		cmd2 = "RETR";
1142 	else
1143 		cmd2 = runique ? "STOU" : "STOR";
1144 	if (command("PASV") != COMPLETE) {
1145 		printf("proxy server does not support third part transfers.\n");
1146 		return;
1147 	}
1148 	tmptype = type;
1149 	pswitch(0);
1150 	if (!connected) {
1151 		printf("No primary connection\n");
1152 		pswitch(1);
1153 		code = -1;
1154 		return;
1155 	}
1156 	if (type != tmptype) {
1157 		oldtype = type;
1158 		switch (tmptype) {
1159 			case TYPE_A:
1160 				setascii();
1161 				break;
1162 			case TYPE_I:
1163 				setbinary();
1164 				break;
1165 			case TYPE_E:
1166 				setebcdic();
1167 				break;
1168 			case TYPE_L:
1169 				settenex();
1170 				break;
1171 		}
1172 	}
1173 	if (command("PORT %s", pasv) != COMPLETE) {
1174 		switch (oldtype) {
1175 			case 0:
1176 				break;
1177 			case TYPE_A:
1178 				setascii();
1179 				break;
1180 			case TYPE_I:
1181 				setbinary();
1182 				break;
1183 			case TYPE_E:
1184 				setebcdic();
1185 				break;
1186 			case TYPE_L:
1187 				settenex();
1188 				break;
1189 		}
1190 		pswitch(1);
1191 		return;
1192 	}
1193 	if (setjmp(ptabort))
1194 		goto abort;
1195 	oldintr = signal(SIGINT, abortpt);
1196 	if (command("%s %s", cmd, remote) != PRELIM) {
1197 		(void) signal(SIGINT, oldintr);
1198 		switch (oldtype) {
1199 			case 0:
1200 				break;
1201 			case TYPE_A:
1202 				setascii();
1203 				break;
1204 			case TYPE_I:
1205 				setbinary();
1206 				break;
1207 			case TYPE_E:
1208 				setebcdic();
1209 				break;
1210 			case TYPE_L:
1211 				settenex();
1212 				break;
1213 		}
1214 		pswitch(1);
1215 		return;
1216 	}
1217 	sleep(2);
1218 	pswitch(1);
1219 	secndflag++;
1220 	if (command("%s %s", cmd2, local) != PRELIM)
1221 		goto abort;
1222 	ptflag++;
1223 	(void) getreply(0);
1224 	pswitch(0);
1225 	(void) getreply(0);
1226 	(void) signal(SIGINT, oldintr);
1227 	switch (oldtype) {
1228 		case 0:
1229 			break;
1230 		case TYPE_A:
1231 			setascii();
1232 			break;
1233 		case TYPE_I:
1234 			setbinary();
1235 			break;
1236 		case TYPE_E:
1237 			setebcdic();
1238 			break;
1239 		case TYPE_L:
1240 			settenex();
1241 			break;
1242 	}
1243 	pswitch(1);
1244 	ptflag = 0;
1245 	printf("local: %s remote: %s\n", local, remote);
1246 	return;
1247 abort:
1248 	(void) signal(SIGINT, SIG_IGN);
1249 	ptflag = 0;
1250 	if (strcmp(cmd, "RETR") && !proxy)
1251 		pswitch(1);
1252 	else if (!strcmp(cmd, "RETR") && proxy)
1253 		pswitch(0);
1254 	if (!cpend && !secndflag) {  /* only here if cmd = "STOR" (proxy=1) */
1255 		if (command("%s %s", cmd2, local) != PRELIM) {
1256 			pswitch(0);
1257 			switch (oldtype) {
1258 				case 0:
1259 					break;
1260 				case TYPE_A:
1261 					setascii();
1262 					break;
1263 				case TYPE_I:
1264 					setbinary();
1265 					break;
1266 				case TYPE_E:
1267 					setebcdic();
1268 					break;
1269 				case TYPE_L:
1270 					settenex();
1271 					break;
1272 			}
1273 			if (cpend) {
1274 				char msg[2];
1275 
1276 				fprintf(cout,"%c%c",IAC,IP);
1277 				(void) fflush(cout);
1278 				*msg = IAC;
1279 				*(msg+1) = DM;
1280 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1281 					perror("abort");
1282 				fprintf(cout,"ABOR\r\n");
1283 				(void) fflush(cout);
1284 				FD_ZERO(&mask);
1285 				FD_SET(fileno(cin), &mask);
1286 				if ((nfnd = empty(&mask,10)) <= 0) {
1287 					if (nfnd < 0) {
1288 						perror("abort");
1289 					}
1290 					if (ptabflg)
1291 						code = -1;
1292 					lostpeer();
1293 				}
1294 				(void) getreply(0);
1295 				(void) getreply(0);
1296 			}
1297 		}
1298 		pswitch(1);
1299 		if (ptabflg)
1300 			code = -1;
1301 		(void) signal(SIGINT, oldintr);
1302 		return;
1303 	}
1304 	if (cpend) {
1305 		char msg[2];
1306 
1307 		fprintf(cout,"%c%c",IAC,IP);
1308 		(void) fflush(cout);
1309 		*msg = IAC;
1310 		*(msg+1) = DM;
1311 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1312 			perror("abort");
1313 		fprintf(cout,"ABOR\r\n");
1314 		(void) fflush(cout);
1315 		FD_ZERO(&mask);
1316 		FD_SET(fileno(cin), &mask);
1317 		if ((nfnd = empty(&mask,10)) <= 0) {
1318 			if (nfnd < 0) {
1319 				perror("abort");
1320 			}
1321 			if (ptabflg)
1322 				code = -1;
1323 			lostpeer();
1324 		}
1325 		(void) getreply(0);
1326 		(void) getreply(0);
1327 	}
1328 	pswitch(!proxy);
1329 	if (!cpend && !secndflag) {  /* only if cmd = "RETR" (proxy=1) */
1330 		if (command("%s %s", cmd2, local) != PRELIM) {
1331 			pswitch(0);
1332 			switch (oldtype) {
1333 				case 0:
1334 					break;
1335 				case TYPE_A:
1336 					setascii();
1337 					break;
1338 				case TYPE_I:
1339 					setbinary();
1340 					break;
1341 				case TYPE_E:
1342 					setebcdic();
1343 					break;
1344 				case TYPE_L:
1345 					settenex();
1346 					break;
1347 			}
1348 			if (cpend) {
1349 				char msg[2];
1350 
1351 				fprintf(cout,"%c%c",IAC,IP);
1352 				(void) fflush(cout);
1353 				*msg = IAC;
1354 				*(msg+1) = DM;
1355 				if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1356 					perror("abort");
1357 				fprintf(cout,"ABOR\r\n");
1358 				(void) fflush(cout);
1359 				FD_ZERO(&mask);
1360 				FD_SET(fileno(cin), &mask);
1361 				if ((nfnd = empty(&mask,10)) <= 0) {
1362 					if (nfnd < 0) {
1363 						perror("abort");
1364 					}
1365 					if (ptabflg)
1366 						code = -1;
1367 					lostpeer();
1368 				}
1369 				(void) getreply(0);
1370 				(void) getreply(0);
1371 			}
1372 			pswitch(1);
1373 			if (ptabflg)
1374 				code = -1;
1375 			(void) signal(SIGINT, oldintr);
1376 			return;
1377 		}
1378 	}
1379 	if (cpend) {
1380 		char msg[2];
1381 
1382 		fprintf(cout,"%c%c",IAC,IP);
1383 		(void) fflush(cout);
1384 		*msg = IAC;
1385 		*(msg+1) = DM;
1386 		if (send(fileno(cout),msg,2,MSG_OOB) != 2)
1387 			perror("abort");
1388 		fprintf(cout,"ABOR\r\n");
1389 		(void) fflush(cout);
1390 		FD_ZERO(&mask);
1391 		FD_SET(fileno(cin), &mask);
1392 		if ((nfnd = empty(&mask,10)) <= 0) {
1393 			if (nfnd < 0) {
1394 				perror("abort");
1395 			}
1396 			if (ptabflg)
1397 				code = -1;
1398 			lostpeer();
1399 		}
1400 		(void) getreply(0);
1401 		(void) getreply(0);
1402 	}
1403 	pswitch(!proxy);
1404 	if (cpend) {
1405 		FD_ZERO(&mask);
1406 		FD_SET(fileno(cin), &mask);
1407 		if ((nfnd = empty(&mask,10)) <= 0) {
1408 			if (nfnd < 0) {
1409 				perror("abort");
1410 			}
1411 			if (ptabflg)
1412 				code = -1;
1413 			lostpeer();
1414 		}
1415 		(void) getreply(0);
1416 		(void) getreply(0);
1417 	}
1418 	if (proxy)
1419 		pswitch(0);
1420 	switch (oldtype) {
1421 		case 0:
1422 			break;
1423 		case TYPE_A:
1424 			setascii();
1425 			break;
1426 		case TYPE_I:
1427 			setbinary();
1428 			break;
1429 		case TYPE_E:
1430 			setebcdic();
1431 			break;
1432 		case TYPE_L:
1433 			settenex();
1434 			break;
1435 	}
1436 	pswitch(1);
1437 	if (ptabflg)
1438 		code = -1;
1439 	(void) signal(SIGINT, oldintr);
1440 }
1441 
1442 reset()
1443 {
1444 	struct fd_set mask;
1445 	int nfnd = 1;
1446 
1447 	FD_ZERO(&mask);
1448 	while (nfnd > 0) {
1449 		FD_SET(fileno(cin), &mask);
1450 		if ((nfnd = empty(&mask,0)) < 0) {
1451 			perror("reset");
1452 			code = -1;
1453 			lostpeer();
1454 		}
1455 		else if (nfnd) {
1456 			(void) getreply(0);
1457 		}
1458 	}
1459 }
1460 
1461 char *
1462 gunique(local)
1463 	char *local;
1464 {
1465 	static char new[MAXPATHLEN];
1466 	char *cp = rindex(local, '/');
1467 	int d, count=0;
1468 	char ext = '1';
1469 
1470 	if (cp)
1471 		*cp = '\0';
1472 	d = access(cp ? local : ".", 2);
1473 	if (cp)
1474 		*cp = '/';
1475 	if (d < 0) {
1476 		perror(local);
1477 		return((char *) 0);
1478 	}
1479 	(void) strcpy(new, local);
1480 	cp = new + strlen(new);
1481 	*cp++ = '.';
1482 	while (!d) {
1483 		if (++count == 100) {
1484 			printf("runique: can't find unique file name.\n");
1485 			return((char *) 0);
1486 		}
1487 		*cp++ = ext;
1488 		*cp = '\0';
1489 		if (ext == '9')
1490 			ext = '0';
1491 		else
1492 			ext++;
1493 		if ((d = access(new, 0)) < 0)
1494 			break;
1495 		if (ext != '0')
1496 			cp--;
1497 		else if (*(cp - 2) == '.')
1498 			*(cp - 1) = '1';
1499 		else {
1500 			*(cp - 2) = *(cp - 2) + 1;
1501 			cp--;
1502 		}
1503 	}
1504 	return(new);
1505 }
1506