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