xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 25100)
1 /*
2  * Copyright (c) 1980 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.3 (Berkeley) 10/05/85";
9 #endif not lint
10 
11 #include <sys/param.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <sys/time.h>
16 
17 #include <netinet/in.h>
18 #include <arpa/ftp.h>
19 
20 #include <stdio.h>
21 #include <signal.h>
22 #include <errno.h>
23 #include <netdb.h>
24 
25 #include "ftp_var.h"
26 
27 struct	sockaddr_in hisctladdr;
28 struct	sockaddr_in data_addr;
29 int	data = -1;
30 int	connected;
31 struct	sockaddr_in myctladdr;
32 
33 FILE	*cin, *cout;
34 FILE	*dataconn();
35 
36 struct hostent *
37 hookup(host, port)
38 	char *host;
39 	int port;
40 {
41 	register struct hostent *hp;
42 	int s, len;
43 	long addr;
44 
45 	bzero((char *)&hisctladdr, sizeof (hisctladdr));
46 	if ((addr = inet_addr(host)) == -1) {
47 		hp = gethostbyname(host);
48 	} else  {
49 		static struct hostent def;
50 		static struct in_addr defaddr;
51 		static char namebuf[MAXHOSTNAMELEN];
52 		static char *addrbuf;
53 		long inet_addr();
54 
55 		defaddr.s_addr = addr;
56 		strcpy(namebuf, host);
57 		def.h_name = namebuf;
58 		hostname = namebuf;
59 		def.h_addr_list = &addrbuf;
60 		def.h_addr = (char *)&defaddr;
61 		def.h_length = sizeof (struct in_addr);
62 		def.h_addrtype = AF_INET;
63 		def.h_aliases = 0;
64 		hp = &def;
65 	}
66 	if (hp == NULL) {
67 		fprintf(stderr, "%s: Unknown host.\n", host);
68 		return (0);
69 	}
70 	hostname = hp->h_name;
71 	hisctladdr.sin_family = hp->h_addrtype;
72 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
73 	if (s < 0) {
74 		perror("ftp: socket");
75 		return (0);
76 	}
77 	if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) {
78 		perror("ftp: bind");
79 		goto bad;
80 	}
81 	bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length);
82 	hisctladdr.sin_port = port;
83 	if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) {
84 		perror("ftp: connect");
85 		goto bad;
86 	}
87 	len = sizeof (myctladdr);
88 	if (getsockname(s, (char *)&myctladdr, &len) < 0) {
89 		perror("ftp: getsockname");
90 		goto bad;
91 	}
92 	cin = fdopen(s, "r");
93 	cout = fdopen(s, "w");
94 	if (cin == NULL || cout == NULL) {
95 		fprintf(stderr, "ftp: fdopen failed.\n");
96 		if (cin)
97 			fclose(cin);
98 		if (cout)
99 			fclose(cout);
100 		goto bad;
101 	}
102 	if (verbose)
103 		printf("Connected to %s.\n", hp->h_name);
104 	(void) getreply(0); 		/* read startup message from server */
105 	return (hp);
106 bad:
107 	close(s);
108 	return ((struct hostent *)0);
109 }
110 
111 login(hp)
112 	struct hostent *hp;
113 {
114 	char acct[80];
115 	char *user, *pass;
116 	int n;
117 
118 	user = pass = 0;
119 	ruserpass(hp->h_name, &user, &pass);
120 	n = command("USER %s", user);
121 	if (n == CONTINUE)
122 		n = command("PASS %s", pass);
123 	if (n == CONTINUE) {
124 		printf("Account: "); (void) fflush(stdout);
125 		(void) fgets(acct, sizeof(acct) - 1, stdin);
126 		acct[strlen(acct) - 1] = '\0';
127 		n = command("ACCT %s", acct);
128 	}
129 	if (n != COMPLETE) {
130 		fprintf(stderr, "Login failed.\n");
131 		return (0);
132 	}
133 	return (1);
134 }
135 
136 /*VARARGS 1*/
137 command(fmt, args)
138 	char *fmt;
139 {
140 
141 	if (debug) {
142 		printf("---> ");
143 		_doprnt(fmt, &args, stdout);
144 		printf("\n");
145 		(void) fflush(stdout);
146 	}
147 	if (cout == NULL) {
148 		perror ("No control connection for command");
149 		return (0);
150 	}
151 	_doprnt(fmt, &args, cout);
152 	fprintf(cout, "\r\n");
153 	(void) fflush(cout);
154 	return (getreply(!strcmp(fmt, "QUIT")));
155 }
156 
157 #include <ctype.h>
158 
159 getreply(expecteof)
160 	int expecteof;
161 {
162 	register int c, n;
163 	register int code, dig;
164 	int originalcode = 0, continuation = 0;
165 
166 	for (;;) {
167 		dig = n = code = 0;
168 		while ((c = getc(cin)) != '\n') {
169 			dig++;
170 			if (c == EOF) {
171 				if (expecteof)
172 					return (0);
173 				lostpeer();
174 				exit(1);
175 			}
176 			if (verbose && c != '\r' ||
177 			    (n == '5' && dig > 4))
178 				putchar(c);
179 			if (dig < 4 && isdigit(c))
180 				code = code * 10 + (c - '0');
181 			if (dig == 4 && c == '-')
182 				continuation++;
183 			if (n == 0)
184 				n = c;
185 		}
186 		if (verbose || n == '5') {
187 			putchar(c);
188 			(void) fflush (stdout);
189 		}
190 		if (continuation && code != originalcode) {
191 			if (originalcode == 0)
192 				originalcode = code;
193 			continue;
194 		}
195 		if (expecteof || empty(cin))
196 			return (n - '0');
197 	}
198 }
199 
200 empty(f)
201 	FILE *f;
202 {
203 	long mask;
204 	struct timeval t;
205 
206 	if (f->_cnt > 0)
207 		return (0);
208 	mask = (1 << fileno(f));
209 	t.tv_sec = t.tv_usec = 0;
210 	(void) select(20, &mask, 0, 0, &t);
211 	return (mask == 0);
212 }
213 
214 jmp_buf	sendabort;
215 
216 abortsend()
217 {
218 
219 	longjmp(sendabort, 1);
220 }
221 
222 sendrequest(cmd, local, remote)
223 	char *cmd, *local, *remote;
224 {
225 	FILE *fin, *dout, *popen();
226 	int (*closefunc)(), pclose(), fclose(), (*oldintr)();
227 	char buf[BUFSIZ];
228 	long bytes = 0, hashbytes = sizeof (buf);
229 	register int c, d;
230 	struct stat st;
231 	struct timeval start, stop;
232 
233 	closefunc = NULL;
234 	if (setjmp(sendabort))
235 		goto bad;
236 	oldintr = signal(SIGINT, abortsend);
237 	if (strcmp(local, "-") == 0)
238 		fin = stdin;
239 	else if (*local == '|') {
240 		fin = popen(local + 1, "r");
241 		if (fin == NULL) {
242 			perror(local + 1);
243 			goto bad;
244 		}
245 		closefunc = pclose;
246 	} else {
247 		fin = fopen(local, "r");
248 		if (fin == NULL) {
249 			perror(local);
250 			goto bad;
251 		}
252 		closefunc = fclose;
253 		if (fstat(fileno(fin), &st) < 0 ||
254 		    (st.st_mode&S_IFMT) != S_IFREG) {
255 			fprintf(stderr, "%s: not a plain file.\n", local);
256 			goto bad;
257 		}
258 	}
259 	if (initconn())
260 		goto bad;
261 	if (remote) {
262 		if (command("%s %s", cmd, remote) != PRELIM)
263 			goto bad;
264 	} else
265 		if (command("%s", cmd) != PRELIM)
266 			goto bad;
267 	dout = dataconn("w");
268 	if (dout == NULL)
269 		goto bad;
270 	gettimeofday(&start, (struct timezone *)0);
271 	switch (type) {
272 
273 	case TYPE_I:
274 	case TYPE_L:
275 		errno = d = 0;
276 		while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) {
277 			if ((d = write(fileno (dout), buf, c)) < 0)
278 				break;
279 			bytes += c;
280 			if (hash) {
281 				putchar('#');
282 				fflush(stdout);
283 			}
284 		}
285 		if (hash && bytes > 0) {
286 			putchar('\n');
287 			fflush(stdout);
288 		}
289 		if (c < 0)
290 			perror(local);
291 		if (d < 0)
292 			perror("netout");
293 		break;
294 
295 	case TYPE_A:
296 		while ((c = getc(fin)) != EOF) {
297 			if (c == '\n') {
298 				while (hash && (bytes >= hashbytes)) {
299 					putchar('#');
300 					fflush(stdout);
301 					hashbytes += sizeof (buf);
302 				}
303 				if (ferror(dout))
304 					break;
305 				putc('\r', dout);
306 				bytes++;
307 			}
308 			putc(c, dout);
309 			bytes++;
310 			if (c == '\r') {
311 				putc('\0', dout);
312 				bytes++;
313 			}
314 		}
315 		if (hash) {
316 			if (bytes < hashbytes)
317 				putchar('#');
318 			putchar('\n');
319 			fflush(stdout);
320 		}
321 		if (ferror(fin))
322 			perror(local);
323 		if (ferror(dout))
324 			perror("netout");
325 		break;
326 	}
327 	gettimeofday(&stop, (struct timezone *)0);
328 	if (closefunc != NULL)
329 		(*closefunc)(fin);
330 	(void) fclose(dout);
331 	(void) getreply(0);
332 done:
333 	signal(SIGINT, oldintr);
334 	if (bytes > 0 && verbose)
335 		ptransfer("sent", bytes, &start, &stop);
336 	return;
337 bad:
338 	if (data >= 0)
339 		(void) close(data), data = -1;
340 	if (closefunc != NULL && fin != NULL)
341 		(*closefunc)(fin);
342 	goto done;
343 }
344 
345 jmp_buf	recvabort;
346 
347 abortrecv()
348 {
349 
350 	longjmp(recvabort, 1);
351 }
352 
353 recvrequest(cmd, local, remote, mode)
354 	char *cmd, *local, *remote, *mode;
355 {
356 	FILE *fout, *din, *popen();
357 	int (*closefunc)(), pclose(), fclose(), (*oldintr)();
358 	char buf[BUFSIZ];
359 	long bytes = 0, hashbytes = sizeof (buf);
360 	register int c, d;
361 	struct timeval start, stop;
362 
363 	closefunc = NULL;
364 	if (setjmp(recvabort))
365 		goto bad;
366 	oldintr = signal(SIGINT, abortrecv);
367 	if (strcmp(local, "-") && *local != '|')
368 		if (access(local, 2) < 0) {
369 			char *dir = rindex(local, '/');
370 
371 			if (dir != NULL)
372 				*dir = 0;
373 			d = access(dir ? local : ".", 2);
374 			if (dir != NULL)
375 				*dir = '/';
376 			if (d < 0) {
377 				perror(local);
378 				goto bad;
379 			}
380 		}
381 	if (initconn())
382 		goto bad;
383 	if (remote) {
384 		if (command("%s %s", cmd, remote) != PRELIM)
385 			goto bad;
386 	} else
387 		if (command("%s", cmd) != PRELIM)
388 			goto bad;
389 	if (strcmp(local, "-") == 0)
390 		fout = stdout;
391 	else if (*local == '|') {
392 		fout = popen(local + 1, "w");
393 		closefunc = pclose;
394 	} else {
395 		fout = fopen(local, mode);
396 		closefunc = fclose;
397 	}
398 	if (fout == NULL) {
399 		perror(local + 1);
400 		goto bad;
401 	}
402 	din = dataconn("r");
403 	if (din == NULL)
404 		goto bad;
405 	gettimeofday(&start, (struct timezone *)0);
406 	switch (type) {
407 
408 	case TYPE_I:
409 	case TYPE_L:
410 		errno = d = 0;
411 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
412 			if ((d = write(fileno(fout), buf, c)) < 0)
413 				break;
414 			bytes += c;
415 			if (hash) {
416 				putchar('#');
417 				fflush(stdout);
418 			}
419 		}
420 		if (hash && bytes > 0) {
421 			putchar('\n');
422 			fflush(stdout);
423 		}
424 		if (c < 0)
425 			perror("netin");
426 		if (d < 0)
427 			perror(local);
428 		break;
429 
430 	case TYPE_A:
431 		while ((c = getc(din)) != EOF) {
432 			if (c == '\r') {
433 				while (hash && (bytes >= hashbytes)) {
434 					putchar('#');
435 					fflush(stdout);
436 					hashbytes += sizeof (buf);
437 				}
438 				bytes++;
439 				if ((c = getc(din)) != '\n') {
440 					if (ferror (fout))
441 						break;
442 					putc ('\r', fout);
443 				}
444 				if (c == '\0') {
445 					bytes++;
446 					continue;
447 				}
448 			}
449 			putc (c, fout);
450 			bytes++;
451 		}
452 		if (hash) {
453 			if (bytes < hashbytes)
454 				putchar('#');
455 			putchar('\n');
456 			fflush(stdout);
457 		}
458 		if (ferror (din))
459 			perror ("netin");
460 		if (ferror (fout))
461 			perror (local);
462 		break;
463 	}
464 	gettimeofday(&stop, (struct timezone *)0);
465 	(void) fclose(din);
466 	if (closefunc != NULL)
467 		(*closefunc)(fout);
468 	(void) getreply(0);
469 done:
470 	signal(SIGINT, oldintr);
471 	if (bytes > 0 && verbose)
472 		ptransfer("received", bytes, &start, &stop);
473 	return;
474 bad:
475 	if (data >= 0)
476 		(void) close(data), data = -1;
477 	if (closefunc != NULL && fout != NULL)
478 		(*closefunc)(fout);
479 	goto done;
480 }
481 
482 /*
483  * Need to start a listen on the data channel
484  * before we send the command, otherwise the
485  * server's connect may fail.
486  */
487 static int sendport = -1;
488 
489 initconn()
490 {
491 	register char *p, *a;
492 	int result, len;
493 	int on = 1;
494 
495 noport:
496 	data_addr = myctladdr;
497 	if (sendport)
498 		data_addr.sin_port = 0;	/* let system pick one */
499 	if (data != -1)
500 		(void) close (data);
501 	data = socket(AF_INET, SOCK_STREAM, 0);
502 	if (data < 0) {
503 		perror("ftp: socket");
504 		return (1);
505 	}
506 	if (!sendport)
507 		if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) {
508 			perror("ftp: setsockopt (resuse address)");
509 			goto bad;
510 		}
511 	if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
512 		perror("ftp: bind");
513 		goto bad;
514 	}
515 	if (options & SO_DEBUG &&
516 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
517 		perror("ftp: setsockopt (ignored)");
518 	len = sizeof (data_addr);
519 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
520 		perror("ftp: getsockname");
521 		goto bad;
522 	}
523 	if (listen(data, 1) < 0) {
524 		perror("ftp: listen");
525 		goto bad;
526 	}
527 	if (sendport) {
528 		a = (char *)&data_addr.sin_addr;
529 		p = (char *)&data_addr.sin_port;
530 #define	UC(b)	(((int)b)&0xff)
531 		result =
532 		    command("PORT %d,%d,%d,%d,%d,%d",
533 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
534 		      UC(p[0]), UC(p[1]));
535 		if (result == ERROR && sendport == -1) {
536 			sendport = 0;
537 			goto noport;
538 		}
539 		return (result != COMPLETE);
540 	}
541 	return (0);
542 bad:
543 	(void) close(data), data = -1;
544 	return (1);
545 }
546 
547 FILE *
548 dataconn(mode)
549 	char *mode;
550 {
551 	struct sockaddr_in from;
552 	int s, fromlen = sizeof (from);
553 
554 	s = accept(data, &from, &fromlen, 0);
555 	if (s < 0) {
556 		perror("ftp: accept");
557 		(void) close(data), data = -1;
558 		return (NULL);
559 	}
560 	(void) close(data);
561 	data = s;
562 	return (fdopen(data, mode));
563 }
564 
565 ptransfer(direction, bytes, t0, t1)
566 	char *direction;
567 	long bytes;
568 	struct timeval *t0, *t1;
569 {
570 	struct timeval td;
571 	float s, bs;
572 
573 	tvsub(&td, t1, t0);
574 	s = td.tv_sec + (td.tv_usec / 1000000.);
575 #define	nz(x)	((x) == 0 ? 1 : (x))
576 	bs = bytes / nz(s);
577 	printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
578 		bytes, direction, s, bs / 1024.);
579 }
580 
581 tvadd(tsum, t0)
582 	struct timeval *tsum, *t0;
583 {
584 
585 	tsum->tv_sec += t0->tv_sec;
586 	tsum->tv_usec += t0->tv_usec;
587 	if (tsum->tv_usec > 1000000)
588 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
589 }
590 
591 tvsub(tdiff, t1, t0)
592 	struct timeval *tdiff, *t1, *t0;
593 {
594 
595 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
596 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
597 	if (tdiff->tv_usec < 0)
598 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
599 }
600