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