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