xref: /csrg-svn/libexec/ftpd/ftpd.c (revision 10321)
1 #ifndef lint
2 static char sccsid[] = "@(#)ftpd.c	4.6 (Berkeley) 83/01/16";
3 #endif
4 
5 /*
6  * FTP server.
7  */
8 #include <sys/param.h>
9 #include <sys/stat.h>
10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
12 
13 #include <netinet/in.h>
14 
15 #include <stdio.h>
16 #include <signal.h>
17 #include <wait.h>
18 #include <pwd.h>
19 #include <setjmp.h>
20 #include <netdb.h>
21 
22 #include "ftp.h"
23 
24 extern	int errno;
25 extern	char *sys_errlist[];
26 extern	char *crypt();
27 extern	char version[];
28 extern	char *home;		/* pointer to home directory for glob */
29 extern	FILE *popen(), *fopen();
30 extern	int pclose(), fclose();
31 
32 struct	sockaddr_in ctrl_addr;
33 struct	sockaddr_in data_source;
34 struct	sockaddr_in data_dest;
35 struct	sockaddr_in his_addr;
36 
37 struct	hostent *hp;
38 
39 int	data;
40 jmp_buf	errcatch;
41 int	logged_in;
42 struct	passwd *pw;
43 int	debug;
44 int	logging = 1;
45 int	guest;
46 int	type;
47 int	form;
48 int	stru;			/* avoid C keyword */
49 int	mode;
50 int	usedefault = 1;		/* for data transfers */
51 char	hostname[32];
52 char	*remotehost;
53 struct	servent *sp;
54 
55 int	lostconn();
56 FILE	*getdatasock(), *dataconn();
57 char	*ntoa();
58 
59 main(argc, argv)
60 	int argc;
61 	char *argv[];
62 {
63 	int ctrl, s, options = 0;
64 	union wait status;
65 	char *cp;
66 
67 	sp = getservbyname("ftp", "tcp");
68 	if (sp == 0) {
69 		fprintf(stderr, "ftpd: fpt/tcp: unknown service\n");
70 		exit(1);
71 	}
72 	ctrl_addr.sin_port = sp->s_port;
73 	data_source.sin_port = htons(ntohs(sp->s_port) - 1);
74 	signal(SIGPIPE, lostconn);
75 	debug = 0;
76 	argc--, argv++;
77 	while (argc > 0 && *argv[0] == '-') {
78 		for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
79 
80 		case 'd':
81 			debug = 1;
82 			options |= SO_DEBUG;
83 			break;
84 
85 		default:
86 			fprintf(stderr, "Unknown flag -%c ignored.\n", cp);
87 			break;
88 		}
89 		argc--, argv++;
90 	}
91 #ifndef DEBUG
92 	if (fork())
93 		exit(0);
94 	for (s = 0; s < 10; s++)
95 		(void) close(s);
96 	(void) open("/dev/null", 0);
97 	(void) dup2(0, 1);
98 	{ int tt = open("/dev/tty", 2);
99 	  if (tt > 0) {
100 		ioctl(tt, TIOCNOTTY, 0);
101 		close(tt);
102 	  }
103 	}
104 #endif
105 	while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) {
106 		perror("ftpd: socket");
107 		sleep(5);
108 	}
109 	while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) {
110 		perror("ftpd: bind");
111 		sleep(5);
112 	}
113 	listen(s, 10);
114 	for (;;) {
115 		int hisaddrlen = sizeof (his_addr);
116 
117 		ctrl = accept(s, &his_addr, &hisaddrlen, 0);
118 		if (ctrl < 0) {
119 			perror("ftpd: accept");
120 			sleep(5);
121 			continue;
122 		}
123 		if (fork() == 0) {
124 			if (logging)
125 				dolog(&his_addr);
126 			close(s);
127 			dup2(ctrl, 0), close(ctrl), dup2(0, 1);
128 			/* do telnet option negotiation here */
129 			/*
130 			 * Set up default state
131 			 */
132 			logged_in = 0;
133 			data = -1;
134 			type = TYPE_A;
135 			form = FORM_N;
136 			stru = STRU_F;
137 			mode = MODE_S;
138 			gethostname(hostname, sizeof (hostname));
139 			reply(220, "%s FTP server (%s) ready.",
140 				hostname, version);
141 			for (;;) {
142 				setjmp(errcatch);
143 				yyparse();
144 			}
145 		}
146 		close(ctrl);
147 		while (wait3(status, WNOHANG, 0) > 0)
148 			continue;
149 	}
150 }
151 
152 lostconn()
153 {
154 
155 	fatal("Connection closed.");
156 }
157 
158 pass(passwd)
159 	char *passwd;
160 {
161 	char *xpasswd, *savestr();
162 	static struct passwd save;
163 
164 	if (logged_in || pw == NULL) {
165 		reply(503, "Login with USER first.");
166 		return;
167 	}
168 	if (!guest) {		/* "ftp" is only account allowed no password */
169 		xpasswd = crypt(passwd, pw->pw_passwd);
170 		if (strcmp(xpasswd, pw->pw_passwd) != 0) {
171 			reply(530, "Login incorrect.");
172 			pw = NULL;
173 			return;
174 		}
175 	}
176 	setegid(pw->pw_gid);
177 	initgroups(pw->pw_name, pw->pw_gid);
178 	if (chdir(pw->pw_dir)) {
179 		reply(550, "User %s: can't change directory to $s.",
180 			pw->pw_name, pw->pw_dir);
181 		goto bad;
182 	}
183 	if (guest && chroot(pw->pw_dir) < 0) {
184 		reply(550, "Can't set guest privileges.");
185 		goto bad;
186 	}
187 	if (!guest)
188 		reply(230, "User %s logged in.", pw->pw_name);
189 	else
190 		reply(230, "Guest login ok, access restrictions apply.");
191 	logged_in = 1;
192 	seteuid(pw->pw_uid);
193 	/*
194 	 * Save everything so globbing doesn't
195 	 * clobber the fields.
196 	 */
197 	save = *pw;
198 	save.pw_name = savestr(pw->pw_name);
199 	save.pw_passwd = savestr(pw->pw_passwd);
200 	save.pw_comment = savestr(pw->pw_comment);
201 	save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos);
202 	save.pw_dir = savestr(pw->pw_dir);
203 	save.pw_shell = savestr(pw->pw_shell);
204 	pw = &save;
205 	home = pw->pw_dir;		/* home dir for globbing */
206 	return;
207 bad:
208 	seteuid(0);
209 	pw = NULL;
210 }
211 
212 char *
213 savestr(s)
214 	char *s;
215 {
216 	char *malloc();
217 	char *new = malloc(strlen(s) + 1);
218 
219 	if (new != NULL)
220 		strcpy(new, s);
221 	return(new);
222 }
223 
224 retrieve(cmd, name)
225 	char *cmd, *name;
226 {
227 	FILE *fin, *dout;
228 	struct stat st;
229 	int (*closefunc)();
230 
231 	if (cmd == 0) {
232 #ifdef notdef
233 		/* no remote command execution -- it's a security hole */
234 		if (*name == '!')
235 			fin = popen(name + 1, "r"), closefunc = pclose;
236 		else
237 #endif
238 			fin = fopen(name, "r"), closefunc = fclose;
239 	} else {
240 		char line[BUFSIZ];
241 
242 		sprintf(line, cmd, name);
243 		fin = popen(line, "r"), closefunc = pclose;
244 	}
245 	if (fin == NULL) {
246 		reply(550, "%s: %s.", name, sys_errlist[errno]);
247 		return;
248 	}
249 	st.st_size = 0;
250 	if (cmd == 0 &&
251 	    (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
252 		reply(550, "%s: not a plain file.", name);
253 		goto done;
254 	}
255 	dout = dataconn(name, st.st_size, "w");
256 	if (dout == NULL)
257 		goto done;
258 	if (send_data(fin, dout) || ferror(dout))
259 		reply(550, "%s: %s.", name, sys_errlist[errno]);
260 	else
261 		reply(226, "Transfer complete.");
262 	fclose(dout), data = -1;
263 done:
264 	(*closefunc)(fin);
265 }
266 
267 store(name, mode)
268 	char *name, *mode;
269 {
270 	FILE *fout, *din;
271 	int (*closefunc)(), dochown = 0;
272 
273 #ifdef notdef
274 	/* no remote command execution -- it's a security hole */
275 	if (name[0] == '!')
276 		fout = popen(&name[1], "w"), closefunc = pclose;
277 	else
278 #endif
279 	{
280 		struct stat st;
281 
282 		if (stat(name, &st) < 0)
283 			dochown++;
284 		fout = fopen(name, mode), closefunc = fclose;
285 	}
286 	if (fout == NULL) {
287 		reply(550, "%s: %s.", name, sys_errlist[errno]);
288 		return;
289 	}
290 	din = dataconn(name, -1, "r");
291 	if (din == NULL)
292 		goto done;
293 	if (receive_data(din, fout) || ferror(fout))
294 		reply(550, "%s: %s.", name, sys_errlist[errno]);
295 	else
296 		reply(226, "Transfer complete.");
297 	fclose(din), data = -1;
298 done:
299 	if (dochown)
300 		(void) chown(name, pw->pw_uid, -1);
301 	(*closefunc)(fout);
302 }
303 
304 FILE *
305 getdatasock(mode)
306 	char *mode;
307 {
308 	int retrytime, s;
309 
310 	if (data >= 0)
311 		return (fdopen(data, mode));
312 	retrytime = 1;
313 	while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) {
314 		if (retrytime < 5) {
315 			sleep(retrytime);
316 			retrytime <<= 1;
317 			continue;
318 		}
319 		return (NULL);
320 	}
321 	retrytime = 1;
322 	seteuid(0);
323 	while (bind(s, &data_source, sizeof (data_source), 0) < 0) {
324 		if (retrytime < 5) {
325 			sleep(retrytime);
326 			retrytime <<= 1;
327 			continue;
328 		}
329 		seteuid(pw->pw_uid);
330 		close(s);
331 		return (NULL);
332 	}
333 	seteuid(pw->pw_uid);
334 	return (fdopen(s, mode));
335 }
336 
337 FILE *
338 dataconn(name, size, mode)
339 	char *name;
340 	int size;
341 	char *mode;
342 {
343 	char sizebuf[32];
344 	FILE *file;
345 
346 	if (size >= 0)
347 		sprintf(sizebuf, " (%d bytes)", size);
348 	else
349 		(void) strcpy(sizebuf, "");
350 	if (data >= 0) {
351 		reply(125, "Using existing data connection for %s%s.",
352 		    name, sizebuf);
353 		usedefault = 1;
354 		return (fdopen(data, mode));
355 	}
356 	reply(150, "Opening data connection for %s (%s,%d)%s.",
357 	    name, ntoa(data_dest.sin_addr.s_addr),
358 	    ntohs(data_dest.sin_port), sizebuf);
359 	file = getdatasock(mode);
360 	if (file == NULL) {
361 		reply(425, "Can't create data socket (%s,%d): %s.",
362 		    ntoa(data_source.sin_addr),
363 		    ntohs(data_source.sin_port),
364 		    sys_errlist[errno]);
365 		usedefault = 1;
366 		return (NULL);
367 	}
368 	data = fileno(file);
369 	/*
370 	 * If no PORT command was specified,
371 	 * use the default address.
372 	 */
373 	if (usedefault) {
374 		data_dest = his_addr;
375 		data_dest.sin_port = htons(ntohs(sp->s_port) - 1);
376 	}
377 	usedefault = 0;
378 	if (connect(data, &data_dest, sizeof (data_dest), 0) < 0) {
379 		reply(425, "Can't build data connection: %s.",
380 		    sys_errlist[errno]);
381 		(void) fclose(file);
382 		data = -1;
383 		return (NULL);
384 	}
385 	return (file);
386 }
387 
388 /*
389  * Tranfer the contents of "instr" to
390  * "outstr" peer using the appropriate
391  * encapulation of the date subject
392  * to Mode, Structure, and Type.
393  *
394  * NB: Form isn't handled.
395  */
396 send_data(instr, outstr)
397 	FILE *instr, *outstr;
398 {
399 	register int c;
400 	int netfd, filefd, cnt;
401 	char buf[BUFSIZ];
402 
403 	switch (type) {
404 
405 	case TYPE_A:
406 		while ((c = getc(instr)) != EOF) {
407 			if (c == '\n')
408 				putc('\r', outstr);
409 			if (putc(c, outstr) == EOF)
410 				return (1);
411 		}
412 		return (0);
413 
414 	case TYPE_I:
415 	case TYPE_L:
416 		netfd = fileno(outstr);
417 		filefd = fileno(instr);
418 
419 		while ((cnt = read(filefd, buf, sizeof (buf))) > 0)
420 			if (write(netfd, buf, cnt) < 0)
421 				return (1);
422 		return (cnt < 0);
423 	}
424 	reply(504,"Unimplemented TYPE %d in send_data", type);
425 	return (1);
426 }
427 
428 /*
429  * Transfer data from peer to
430  * "outstr" using the appropriate
431  * encapulation of the data subject
432  * to Mode, Structure, and Type.
433  *
434  * N.B.: Form isn't handled.
435  */
436 receive_data(instr, outstr)
437 	FILE *instr, *outstr;
438 {
439 	register int c;
440 	int cr, escape, eof;
441 	int netfd, filefd, cnt;
442 	char buf[BUFSIZ];
443 
444 
445 	switch (type) {
446 
447 	case TYPE_I:
448 	case TYPE_L:
449 		netfd = fileno(instr);
450 		netfd = fileno(outstr);
451 		while ((cnt = read(netfd, buf, sizeof buf)) > 0)
452 			if (write(filefd, buf, cnt) < 0)
453 				return (1);
454 		return (cnt < 0);
455 
456 	case TYPE_E:
457 		reply(504, "TYPE E not implemented.");
458 		return (1);
459 
460 	case TYPE_A:
461 		cr = 0;
462 		while ((c = getc(instr)) != EOF) {
463 			if (cr) {
464 				if (c != '\r' && c != '\n')
465 					putc('\r', outstr);
466 				putc(c, outstr);
467 				cr = c == '\r';
468 				continue;
469 			}
470 			if (c == '\r') {
471 				cr = 1;
472 				continue;
473 			}
474 			putc(c, outstr);
475 		}
476 		if (cr)
477 			putc('\r', outstr);
478 		return (0);
479 	}
480 	fatal("Unknown type in receive_data.");
481 	/*NOTREACHED*/
482 }
483 
484 fatal(s)
485 	char *s;
486 {
487 	reply(451, "Error in server: %s\n", s);
488 	reply(221, "Closing connection due to server error.");
489 	exit(0);
490 }
491 
492 reply(n, s, args)
493 	int n;
494 	char *s;
495 {
496 
497 	printf("%d ", n);
498 	_doprnt(s, &args, stdout);
499 	printf("\r\n");
500 	fflush(stdout);
501 	if (debug) {
502 		fprintf(stderr, "<--- %d ", n);
503 		_doprnt(s, &args, stderr);
504 		fprintf(stderr, "\n");
505 		fflush(stderr);
506 	}
507 }
508 
509 lreply(n, s, args)
510 	int n;
511 	char *s;
512 {
513 	printf("%d-", n);
514 	_doprnt(s, &args, stdout);
515 	printf("\r\n");
516 	fflush(stdout);
517 	if (debug) {
518 		fprintf(stderr, "<--- %d-", n);
519 		_doprnt(s, &args, stderr);
520 		fprintf(stderr, "\n");
521 	}
522 }
523 
524 replystr(s)
525 	char *s;
526 {
527 	printf("%s\r\n", s);
528 	fflush(stdout);
529 	if (debug)
530 		fprintf(stderr, "<--- %s\n", s);
531 }
532 
533 ack(s)
534 	char *s;
535 {
536 	reply(200, "%s command okay.", s);
537 }
538 
539 nack(s)
540 	char *s;
541 {
542 	reply(502, "%s command not implemented.", s);
543 }
544 
545 yyerror()
546 {
547 	reply(500, "Command not understood.");
548 }
549 
550 delete(name)
551 	char *name;
552 {
553 	struct stat st;
554 
555 	if (stat(name, &st) < 0) {
556 		reply(550, "%s: %s.", name, sys_errlist[errno]);
557 		return;
558 	}
559 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
560 		if (rmdir(name) < 0) {
561 			reply(550, "%s: %s.", name, sys_errlist[errno]);
562 			return;
563 		}
564 		goto done;
565 	}
566 	if (unlink(name) < 0) {
567 		reply(550, "%s: %s.", name, sys_errlist[errno]);
568 		return;
569 	}
570 done:
571 	ack("DELE");
572 }
573 
574 cwd(path)
575 	char *path;
576 {
577 
578 	if (chdir(path) < 0) {
579 		reply(550, "%s: %s.", path, sys_errlist[errno]);
580 		return;
581 	}
582 	ack("CWD");
583 }
584 
585 makedir(name)
586 	char *name;
587 {
588 	struct stat st;
589 	int dochown = stat(name, &st) < 0;
590 
591 	if (mkdir(name, 0777) < 0) {
592 		reply(550, "%s: %s.", name, sys_errlist[errno]);
593 		return;
594 	}
595 	if (dochown)
596 		(void) chown(name, pw->pw_uid, -1);
597 	ack("MKDIR");
598 }
599 
600 removedir(name)
601 	char *name;
602 {
603 
604 	if (rmdir(name) < 0) {
605 		reply(550, "%s: %s.", name, sys_errlist[errno]);
606 		return;
607 	}
608 	ack("RMDIR");
609 }
610 
611 pwd()
612 {
613 	char path[MAXPATHLEN + 1];
614 	char *p;
615 
616 	if (getwd(path) == NULL) {
617 		reply(451, "%s.", path);
618 		return;
619 	}
620 	reply(251, "\"%s\" is current directory.", path);
621 }
622 
623 char *
624 renamefrom(name)
625 	char *name;
626 {
627 	struct stat st;
628 
629 	if (stat(name, &st) < 0) {
630 		reply(550, "%s: %s.", name, sys_errlist[errno]);
631 		return ((char *)0);
632 	}
633 	reply(350, "File exists, ready for destination name");
634 	return (name);
635 }
636 
637 renamecmd(from, to)
638 	char *from, *to;
639 {
640 
641 	if (rename(from, to) < 0) {
642 		reply(550, "rename: %s.", sys_errlist[errno]);
643 		return;
644 	}
645 	ack("RNTO");
646 }
647 
648 int guest;
649 /*
650  * Test pathname for guest-user safety.
651  */
652 inappropriate_request(name)
653 	char *name;
654 {
655 	int bogus = 0, depth = 0, length = strlen(name);
656 	char *p, *s;
657 
658 	if (!guest)
659 		return (0);
660 	if (name[0] == '/' || name[0] == '|')
661 		bogus = 1;
662 	for (p = name; p < name+length;) {
663 		s = p;				/* start of token */
664 		while ( *p && *p!= '/')
665 			p++;
666 		*p = 0;
667 		if (strcmp(s, "..") == 0)
668 			depth -= 1;		/* backing up */
669 		else if (strcmp(s, ".") == 0)
670 			depth += 0;		/* no change */
671 		else
672 			depth += 1;		/* descending */
673 		if (depth < 0) {
674 			bogus = 1;
675 			break;
676 		}
677 	}
678 	if (bogus)
679 		reply(553, "%s: pathname disallowed guest users", name);
680 	return (bogus);
681 }
682 
683 /*
684  * Convert network-format internet address
685  * to base 256 d.d.d.d representation.
686  */
687 char *
688 ntoa(in)
689 	struct in_addr in;
690 {
691 	static char b[18];
692 	register char *p;
693 
694 	in.s_addr = ntohl(in.s_addr);
695 	p = (char *)&in;
696 #define	UC(b)	(((int)b)&0xff)
697 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
698 	return (b);
699 }
700 
701 dolog(sin)
702 	struct sockaddr_in *sin;
703 {
704 	struct hostent *hp = gethostbyaddr(&sin->sin_addr,
705 		sizeof (struct in_addr), AF_INET);
706 	char *remotehost;
707 	time_t t;
708 
709 	if (hp)
710 		remotehost = hp->h_name;
711 	else
712 		remotehost = "UNKNOWNHOST";
713 	t = time(0);
714 	fprintf(stderr,"FTP: connection from %s at %s", remotehost, ctime(&t));
715 	fflush(stderr);
716 }
717