xref: /csrg-svn/usr.bin/ftp/ftp.c (revision 11651)
1 #ifndef lint
2 static char sccsid[] = "@(#)ftp.c	4.7 (Berkeley) 03/23/83";
3 #endif
4 
5 #include <sys/param.h>
6 #include <sys/stat.h>
7 #include <sys/ioctl.h>
8 #include <sys/socket.h>
9 
10 #include <netinet/in.h>
11 
12 #include <stdio.h>
13 #include <signal.h>
14 #include <time.h>
15 #include <errno.h>
16 #include <netdb.h>
17 
18 #include "ftp.h"
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, 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.", 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) {
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 			putchar('\n');
307 			fflush(stdout);
308 		}
309 		if (ferror(fin))
310 			perror(local);
311 		if (ferror(dout))
312 			perror("netout");
313 		break;
314 	}
315 	gettimeofday(&stop, (struct timezone *)0);
316 	if (closefunc != NULL)
317 		(*closefunc)(fin);
318 	(void) fclose(dout);
319 	(void) getreply(0);
320 done:
321 	signal(SIGINT, oldintr);
322 	if (bytes > 0 && verbose)
323 		ptransfer("sent", bytes, &start, &stop);
324 	return;
325 bad:
326 	if (data >= 0)
327 		(void) close(data), data = -1;
328 	if (closefunc != NULL && fin != NULL)
329 		(*closefunc)(fin);
330 	goto done;
331 }
332 
333 jmp_buf	recvabort;
334 
335 abortrecv()
336 {
337 
338 	longjmp(recvabort, 1);
339 }
340 
341 recvrequest(cmd, local, remote, mode)
342 	char *cmd, *local, *remote, *mode;
343 {
344 	FILE *fout, *din, *popen();
345 	int (*closefunc)(), pclose(), fclose(), (*oldintr)();
346 	char buf[BUFSIZ];
347 	long bytes = 0, hashbytes = sizeof (buf);
348 	register int c, d;
349 	struct timeval start, stop;
350 
351 	closefunc = NULL;
352 	if (setjmp(recvabort))
353 		goto bad;
354 	oldintr = signal(SIGINT, abortrecv);
355 	if (strcmp(local, "-") && *local != '|')
356 		if (access(local, 2) < 0) {
357 			char *dir = rindex(local, '/');
358 
359 			if (dir != NULL)
360 				*dir = 0;
361 			if (access(dir ? dir : ".", 2) < 0) {
362 				perror(local);
363 				goto bad;
364 			}
365 			if (dir != NULL)
366 				*dir = '/';
367 		}
368 	if (initconn())
369 		goto bad;
370 	if (remote) {
371 		if (command("%s %s", cmd, remote) != PRELIM)
372 			goto bad;
373 	} else
374 		if (command("%s", cmd) != PRELIM)
375 			goto bad;
376 	if (strcmp(local, "-") == 0)
377 		fout = stdout;
378 	else if (*local == '|') {
379 		fout = popen(local + 1, "w");
380 		closefunc = pclose;
381 	} else {
382 		fout = fopen(local, mode);
383 		closefunc = fclose;
384 	}
385 	if (fout == NULL) {
386 		perror(local + 1);
387 		goto bad;
388 	}
389 	din = dataconn("r");
390 	if (din == NULL)
391 		goto bad;
392 	gettimeofday(&start, (struct timezone *)0);
393 	switch (type) {
394 
395 	case TYPE_I:
396 	case TYPE_L:
397 		errno = d = 0;
398 		while ((c = read(fileno(din), buf, sizeof (buf))) > 0) {
399 			if ((d = write(fileno(fout), buf, c)) < 0)
400 				break;
401 			bytes += c;
402 			if (hash) {
403 				putchar('#');
404 				fflush(stdout);
405 			}
406 		}
407 		if (hash) {
408 			putchar('\n');
409 			fflush(stdout);
410 		}
411 		if (c < 0)
412 			perror("netin");
413 		if (d < 0)
414 			perror(local);
415 		break;
416 
417 	case TYPE_A:
418 		while ((c = getc(din)) != EOF) {
419 			if (c == '\r') {
420 				while (hash && (bytes >= hashbytes)) {
421 					putchar('#');
422 					fflush(stdout);
423 					hashbytes += sizeof (buf);
424 				}
425 				bytes++;
426 				if ((c = getc(din)) != '\n') {
427 					if (ferror (fout))
428 						break;
429 					putc ('\r', fout);
430 				}
431 				if (c == '\0') {
432 					bytes++;
433 					continue;
434 				}
435 			}
436 			putc (c, fout);
437 			bytes++;
438 		}
439 		if (hash) {
440 			putchar('\n');
441 			fflush(stdout);
442 		}
443 		if (ferror (din))
444 			perror ("netin");
445 		if (ferror (fout))
446 			perror (local);
447 		break;
448 	}
449 	gettimeofday(&stop, (struct timezone *)0);
450 	(void) fclose(din);
451 	if (closefunc != NULL)
452 		(*closefunc)(fout);
453 	(void) getreply(0);
454 done:
455 	signal(SIGINT, oldintr);
456 	if (bytes > 0 && verbose)
457 		ptransfer("received", bytes, &start, &stop);
458 	return;
459 bad:
460 	if (data >= 0)
461 		(void) close(data), data = -1;
462 	if (closefunc != NULL && fout != NULL)
463 		(*closefunc)(fout);
464 	goto done;
465 }
466 
467 /*
468  * Need to start a listen on the data channel
469  * before we send the command, otherwise the
470  * server's connect may fail.
471  */
472 static int sendport = -1;
473 
474 initconn()
475 {
476 	register char *p, *a;
477 	int result, len;
478 
479 noport:
480 	data_addr = myctladdr;
481 	if (sendport)
482 		data_addr.sin_port = 0;	/* let system pick one */
483 	if (data != -1)
484 		(void) close (data);
485 	data = socket(AF_INET, SOCK_STREAM, 0, 0);
486 	if (data < 0) {
487 		perror("ftp: socket");
488 		return (1);
489 	}
490 	if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
491 		perror("ftp: bind");
492 		goto bad;
493 	}
494 	if (options & SO_DEBUG &&
495 	    setsockopt(data, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
496 		perror("ftp: setsockopt (ignored)");
497 	len = sizeof (data_addr);
498 	if (getsockname(data, (char *)&data_addr, &len) < 0) {
499 		perror("ftp: getsockname");
500 		goto bad;
501 	}
502 	if (listen(data, 1) < 0) {
503 		perror("ftp: listen");
504 		goto bad;
505 	}
506 	if (sendport) {
507 		a = (char *)&data_addr.sin_addr;
508 		p = (char *)&data_addr.sin_port;
509 #define	UC(b)	(((int)b)&0xff)
510 		result =
511 		    command("PORT %d,%d,%d,%d,%d,%d",
512 		      UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
513 		      UC(p[0]), UC(p[1]));
514 		if (result == ERROR && sendport == -1) {
515 			sendport = 0;
516 			goto noport;
517 		}
518 		return (result != COMPLETE);
519 	}
520 	return (0);
521 bad:
522 	(void) close(data), data = -1;
523 	return (1);
524 }
525 
526 FILE *
527 dataconn(mode)
528 	char *mode;
529 {
530 	struct sockaddr_in from;
531 	int s, fromlen = sizeof (from);
532 
533 	s = accept(data, &from, &fromlen, 0);
534 	if (s < 0) {
535 		perror("ftp: accept");
536 		(void) close(data), data = -1;
537 		return (NULL);
538 	}
539 	(void) close(data);
540 	data = s;
541 	return (fdopen(data, mode));
542 }
543 
544 ptransfer(direction, bytes, t0, t1)
545 	char *direction;
546 	long bytes;
547 	struct timeval *t0, *t1;
548 {
549 	struct timeval td;
550 	long ms;
551 	float bs;
552 
553 	tvsub(&td, t1, t0);
554 	ms = (td.tv_sec * 1000) + (td.tv_usec / 1000);
555 #define	nz(x)	((x) == 0 ? 1 : (x))
556 	bs = ((bytes * NBBY * 1000) / (float) nz(ms)) / NBBY;
557 	printf("%ld bytes %s in %d.%02d seconds (%.2g Kbytes/s)\n",
558 		bytes, direction, td.tv_sec, td.tv_usec / 10000, bs / 1024.);
559 }
560 
561 tvadd(tsum, t0)
562 	struct timeval *tsum, *t0;
563 {
564 
565 	tsum->tv_sec += t0->tv_sec;
566 	tsum->tv_usec += t0->tv_usec;
567 	if (tsum->tv_usec > 1000000)
568 		tsum->tv_sec++, tsum->tv_usec -= 1000000;
569 }
570 
571 tvsub(tdiff, t1, t0)
572 	struct timeval *tdiff, *t1, *t0;
573 {
574 
575 	tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
576 	tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
577 	if (tdiff->tv_usec < 0)
578 		tdiff->tv_sec--, tdiff->tv_usec += 1000000;
579 }
580