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