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