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