xref: /original-bsd/libexec/ftpd/ftpd.c (revision abe165e9)
1 /*
2  * Copyright (c) 1985, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1985, 1988 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)ftpd.c	5.36	(Berkeley) 06/01/90";
16 #endif /* not lint */
17 
18 /*
19  * FTP server.
20  */
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/file.h>
26 #include <sys/wait.h>
27 #include <sys/dir.h>
28 
29 #include <netinet/in.h>
30 
31 #define	FTP_NAMES
32 #include <arpa/ftp.h>
33 #include <arpa/inet.h>
34 #include <arpa/telnet.h>
35 
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <signal.h>
39 #include <pwd.h>
40 #include <setjmp.h>
41 #include <netdb.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <varargs.h>
46 #include "pathnames.h"
47 
48 /*
49  * File containing login names
50  * NOT to be used on this machine.
51  * Commonly used to disallow uucp.
52  */
53 extern	int errno;
54 extern	char *crypt();
55 extern	char version[];
56 extern	char *home;		/* pointer to home directory for glob */
57 extern	FILE *ftpd_popen(), *fopen(), *freopen();
58 extern	int  ftpd_pclose(), fclose();
59 extern	char *getline();
60 extern	char cbuf[];
61 extern	off_t restart_point;
62 
63 struct	sockaddr_in ctrl_addr;
64 struct	sockaddr_in data_source;
65 struct	sockaddr_in data_dest;
66 struct	sockaddr_in his_addr;
67 struct	sockaddr_in pasv_addr;
68 
69 int	data;
70 jmp_buf	errcatch, urgcatch;
71 int	logged_in;
72 struct	passwd *pw;
73 int	debug;
74 int	timeout = 900;    /* timeout after 15 minutes of inactivity */
75 int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
76 int	logging;
77 int	guest;
78 int	type;
79 int	form;
80 int	stru;			/* avoid C keyword */
81 int	mode;
82 int	usedefault = 1;		/* for data transfers */
83 int	pdata = -1;		/* for passive mode */
84 int	transflag;
85 off_t	file_size;
86 off_t	byte_count;
87 #if !defined(CMASK) || CMASK == 0
88 #undef CMASK
89 #define CMASK 027
90 #endif
91 int	defumask = CMASK;		/* default umask value */
92 char	tmpline[7];
93 char	hostname[MAXHOSTNAMELEN];
94 char	remotehost[MAXHOSTNAMELEN];
95 
96 /*
97  * Timeout intervals for retrying connections
98  * to hosts that don't accept PORT cmds.  This
99  * is a kludge, but given the problems with TCP...
100  */
101 #define	SWAITMAX	90	/* wait at most 90 seconds */
102 #define	SWAITINT	5	/* interval between retries */
103 
104 int	swaitmax = SWAITMAX;
105 int	swaitint = SWAITINT;
106 
107 int	lostconn();
108 int	myoob();
109 FILE	*getdatasock(), *dataconn();
110 
111 #ifdef SETPROCTITLE
112 char	**Argv = NULL;		/* pointer to argument vector */
113 char	*LastArgv = NULL;	/* end of argv */
114 char	proctitle[BUFSIZ];	/* initial part of title */
115 #endif /* SETPROCTITLE */
116 
117 main(argc, argv, envp)
118 	int argc;
119 	char *argv[];
120 	char **envp;
121 {
122 	int addrlen, on = 1;
123 	char *cp;
124 
125 	addrlen = sizeof (his_addr);
126 	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
127 		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
128 		exit(1);
129 	}
130 	addrlen = sizeof (ctrl_addr);
131 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
132 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
133 		exit(1);
134 	}
135 	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
136 	debug = 0;
137 	openlog("ftpd", LOG_PID, LOG_DAEMON);
138 #ifdef SETPROCTITLE
139 	/*
140 	 *  Save start and extent of argv for setproctitle.
141 	 */
142 	Argv = argv;
143 	while (*envp)
144 		envp++;
145 	LastArgv = envp[-1] + strlen(envp[-1]);
146 #endif /* SETPROCTITLE */
147 
148 	argc--, argv++;
149 	while (argc > 0 && *argv[0] == '-') {
150 		for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
151 
152 		case 'v':
153 			debug = 1;
154 			break;
155 
156 		case 'd':
157 			debug = 1;
158 			break;
159 
160 		case 'l':
161 			logging = 1;
162 			break;
163 
164 		case 't':
165 			timeout = atoi(++cp);
166 			if (maxtimeout < timeout)
167 				maxtimeout = timeout;
168 			goto nextopt;
169 
170 		case 'T':
171 			maxtimeout = atoi(++cp);
172 			if (timeout > maxtimeout)
173 				timeout = maxtimeout;
174 			goto nextopt;
175 
176 		case 'u':
177 		    {
178 			int val = 0;
179 
180 			while (*++cp && *cp >= '0' && *cp <= '9')
181 				val = val*8 + *cp - '0';
182 			if (*cp)
183 				fprintf(stderr, "ftpd: Bad value for -u\n");
184 			else
185 				defumask = val;
186 			goto nextopt;
187 		    }
188 
189 		default:
190 			fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
191 			     *cp);
192 			break;
193 		}
194 nextopt:
195 		argc--, argv++;
196 	}
197 	(void) freopen(_PATH_DEVNULL, "w", stderr);
198 	(void) signal(SIGPIPE, lostconn);
199 	(void) signal(SIGCHLD, SIG_IGN);
200 	if ((int)signal(SIGURG, myoob) < 0)
201 		syslog(LOG_ERR, "signal: %m");
202 
203 	/* Try to handle urgent data inline */
204 #ifdef SO_OOBINLINE
205 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
206 		syslog(LOG_ERR, "setsockopt: %m");
207 #endif
208 
209 #ifdef	F_SETOWN
210 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
211 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
212 #endif
213 	dolog(&his_addr);
214 	/*
215 	 * Set up default state
216 	 */
217 	data = -1;
218 	type = TYPE_A;
219 	form = FORM_N;
220 	stru = STRU_F;
221 	mode = MODE_S;
222 	tmpline[0] = '\0';
223 	(void) gethostname(hostname, sizeof (hostname));
224 	reply(220, "%s FTP server (%s) ready.", hostname, version);
225 	(void) setjmp(errcatch);
226 	for (;;)
227 		(void) yyparse();
228 	/* NOTREACHED */
229 }
230 
231 lostconn()
232 {
233 
234 	if (debug)
235 		syslog(LOG_DEBUG, "lost connection");
236 	dologout(-1);
237 }
238 
239 static char ttyline[20];
240 
241 /*
242  * Helper function for sgetpwnam().
243  */
244 char *
245 sgetsave(s)
246 	char *s;
247 {
248 	char *malloc();
249 	char *new = malloc((unsigned) strlen(s) + 1);
250 
251 	if (new == NULL) {
252 		perror_reply(421, "Local resource failure: malloc");
253 		dologout(1);
254 		/* NOTREACHED */
255 	}
256 	(void) strcpy(new, s);
257 	return (new);
258 }
259 
260 /*
261  * Save the result of a getpwnam.  Used for USER command, since
262  * the data returned must not be clobbered by any other command
263  * (e.g., globbing).
264  */
265 struct passwd *
266 sgetpwnam(name)
267 	char *name;
268 {
269 	static struct passwd save;
270 	register struct passwd *p;
271 	char *sgetsave();
272 
273 	if ((p = getpwnam(name)) == NULL)
274 		return (p);
275 	if (save.pw_name) {
276 		free(save.pw_name);
277 		free(save.pw_passwd);
278 		free(save.pw_gecos);
279 		free(save.pw_dir);
280 		free(save.pw_shell);
281 	}
282 	save = *p;
283 	save.pw_name = sgetsave(p->pw_name);
284 	save.pw_passwd = sgetsave(p->pw_passwd);
285 	save.pw_gecos = sgetsave(p->pw_gecos);
286 	save.pw_dir = sgetsave(p->pw_dir);
287 	save.pw_shell = sgetsave(p->pw_shell);
288 	return (&save);
289 }
290 
291 int login_attempts;		/* number of failed login attempts */
292 int askpasswd;			/* had user command, ask for passwd */
293 
294 /*
295  * USER command.
296  * Sets global passwd pointer pw if named account exists and is acceptable;
297  * sets askpasswd if a PASS command is expected.  If logged in previously,
298  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
299  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
300  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
301  * requesting login privileges.  Disallow anyone who does not have a standard
302  * shell as returned by getusershell().  Disallow anyone mentioned in the file
303  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
304  */
305 user(name)
306 	char *name;
307 {
308 	register char *cp;
309 	char *shell;
310 	char *getusershell();
311 
312 	if (logged_in) {
313 		if (guest) {
314 			reply(530, "Can't change user from guest login.");
315 			return;
316 		}
317 		end_login();
318 	}
319 
320 	guest = 0;
321 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
322 		if (checkuser("ftp") || checkuser("anonymous"))
323 			reply(530, "User %s access denied.", name);
324 		else if ((pw = sgetpwnam("ftp")) != NULL) {
325 			guest = 1;
326 			askpasswd = 1;
327 			reply(331, "Guest login ok, send ident as password.");
328 		} else
329 			reply(530, "User %s unknown.", name);
330 		return;
331 	}
332 	if (pw = sgetpwnam(name)) {
333 		if ((shell = pw->pw_shell) == NULL || *shell == 0)
334 			shell = _PATH_BSHELL;
335 		while ((cp = getusershell()) != NULL)
336 			if (strcmp(cp, shell) == 0)
337 				break;
338 		endusershell();
339 		if (cp == NULL || checkuser(name)) {
340 			reply(530, "User %s access denied.", name);
341 			if (logging)
342 				syslog(LOG_NOTICE,
343 				    "FTP LOGIN REFUSED FROM %s, %s",
344 				    remotehost, name);
345 			pw = (struct passwd *) NULL;
346 			return;
347 		}
348 	}
349 	reply(331, "Password required for %s.", name);
350 	askpasswd = 1;
351 	/*
352 	 * Delay before reading passwd after first failed
353 	 * attempt to slow down passwd-guessing programs.
354 	 */
355 	if (login_attempts)
356 		sleep((unsigned) login_attempts);
357 }
358 
359 /*
360  * Check if a user is in the file _PATH_FTPUSERS
361  */
362 checkuser(name)
363 	char *name;
364 {
365 	register FILE *fd;
366 	register char *p;
367 	char line[BUFSIZ];
368 
369 	if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
370 		while (fgets(line, sizeof(line), fd) != NULL)
371 			if ((p = index(line, '\n')) != NULL) {
372 				*p = '\0';
373 				if (line[0] == '#')
374 					continue;
375 				if (strcmp(line, name) == 0)
376 					return (1);
377 			}
378 		(void) fclose(fd);
379 	}
380 	return (0);
381 }
382 
383 /*
384  * Terminate login as previous user, if any, resetting state;
385  * used when USER command is given or login fails.
386  */
387 end_login()
388 {
389 
390 	(void) seteuid((uid_t)0);
391 	if (logged_in)
392 		logwtmp(ttyline, "", "");
393 	pw = NULL;
394 	logged_in = 0;
395 	guest = 0;
396 }
397 
398 pass(passwd)
399 	char *passwd;
400 {
401 	char *xpasswd, *salt;
402 
403 	if (logged_in || askpasswd == 0) {
404 		reply(503, "Login with USER first.");
405 		return;
406 	}
407 	askpasswd = 0;
408 	if (!guest) {		/* "ftp" is only account allowed no password */
409 		if (pw == NULL)
410 			salt = "xx";
411 		else
412 			salt = pw->pw_passwd;
413 		xpasswd = crypt(passwd, salt);
414 		/* The strcmp does not catch null passwords! */
415 		if (pw == NULL || *pw->pw_passwd == '\0' ||
416 		    strcmp(xpasswd, pw->pw_passwd)) {
417 			reply(530, "Login incorrect.");
418 			pw = NULL;
419 			if (login_attempts++ >= 5) {
420 				syslog(LOG_NOTICE,
421 				    "repeated login failures from %s",
422 				    remotehost);
423 				exit(0);
424 			}
425 			return;
426 		}
427 	}
428 	login_attempts = 0;		/* this time successful */
429 	(void) setegid((gid_t)pw->pw_gid);
430 	(void) initgroups(pw->pw_name, pw->pw_gid);
431 
432 	/* open wtmp before chroot */
433 	(void)sprintf(ttyline, "ftp%d", getpid());
434 	logwtmp(ttyline, pw->pw_name, remotehost);
435 	logged_in = 1;
436 
437 	if (guest) {
438 		/*
439 		 * We MUST do a chdir() after the chroot. Otherwise
440 		 * the old current directory will be accessible as "."
441 		 * outside the new root!
442 		 */
443 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
444 			reply(550, "Can't set guest privileges.");
445 			goto bad;
446 		}
447 	} else if (chdir(pw->pw_dir) < 0) {
448 		if (chdir("/") < 0) {
449 			reply(530, "User %s: can't change directory to %s.",
450 			    pw->pw_name, pw->pw_dir);
451 			goto bad;
452 		} else
453 			lreply(230, "No directory! Logging in with home=/");
454 	}
455 	if (seteuid((uid_t)pw->pw_uid) < 0) {
456 		reply(550, "Can't set uid.");
457 		goto bad;
458 	}
459 	if (guest) {
460 		reply(230, "Guest login ok, access restrictions apply.");
461 #ifdef SETPROCTITLE
462 		sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
463 		    sizeof(proctitle) - sizeof(remotehost) -
464 		    sizeof(": anonymous/"), passwd);
465 		setproctitle(proctitle);
466 #endif /* SETPROCTITLE */
467 		if (logging)
468 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
469 			    remotehost, passwd);
470 	} else {
471 		reply(230, "User %s logged in.", pw->pw_name);
472 #ifdef SETPROCTITLE
473 		sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
474 		setproctitle(proctitle);
475 #endif /* SETPROCTITLE */
476 		if (logging)
477 			syslog(LOG_INFO, "FTP LOGIN FROM %s, %s",
478 			    remotehost, pw->pw_name);
479 	}
480 	home = pw->pw_dir;		/* home dir for globbing */
481 	(void) umask(defumask);
482 	return;
483 bad:
484 	/* Forget all about it... */
485 	end_login();
486 }
487 
488 retrieve(cmd, name)
489 	char *cmd, *name;
490 {
491 	FILE *fin, *dout;
492 	struct stat st;
493 	int (*closefunc)();
494 
495 	if (cmd == 0) {
496 		fin = fopen(name, "r"), closefunc = fclose;
497 		st.st_size = 0;
498 	} else {
499 		char line[BUFSIZ];
500 
501 		(void) sprintf(line, cmd, name), name = line;
502 		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
503 		st.st_size = -1;
504 		st.st_blksize = BUFSIZ;
505 	}
506 	if (fin == NULL) {
507 		if (errno != 0)
508 			perror_reply(550, name);
509 		return;
510 	}
511 	if (cmd == 0 &&
512 	    (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
513 		reply(550, "%s: not a plain file.", name);
514 		goto done;
515 	}
516 	if (restart_point) {
517 		if (type == TYPE_A) {
518 			register int i, n, c;
519 
520 			n = restart_point;
521 			i = 0;
522 			while (i++ < n) {
523 				if ((c=getc(fin)) == EOF) {
524 					perror_reply(550, name);
525 					goto done;
526 				}
527 				if (c == '\n')
528 					i++;
529 			}
530 		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
531 			perror_reply(550, name);
532 			goto done;
533 		}
534 	}
535 	dout = dataconn(name, st.st_size, "w");
536 	if (dout == NULL)
537 		goto done;
538 	send_data(fin, dout, st.st_blksize);
539 	(void) fclose(dout);
540 	data = -1;
541 	pdata = -1;
542 done:
543 	(*closefunc)(fin);
544 }
545 
546 store(name, mode, unique)
547 	char *name, *mode;
548 	int unique;
549 {
550 	FILE *fout, *din;
551 	struct stat st;
552 	int (*closefunc)();
553 	char *gunique();
554 
555 	if (unique && stat(name, &st) == 0 &&
556 	    (name = gunique(name)) == NULL)
557 		return;
558 
559 	if (restart_point)
560 		mode = "r+w";
561 	fout = fopen(name, mode);
562 	closefunc = fclose;
563 	if (fout == NULL) {
564 		perror_reply(553, name);
565 		return;
566 	}
567 	if (restart_point) {
568 		if (type == TYPE_A) {
569 			register int i, n, c;
570 
571 			n = restart_point;
572 			i = 0;
573 			while (i++ < n) {
574 				if ((c=getc(fout)) == EOF) {
575 					perror_reply(550, name);
576 					goto done;
577 				}
578 				if (c == '\n')
579 					i++;
580 			}
581 			/*
582 			 * We must do this seek to "current" position
583 			 * because we are changing from reading to
584 			 * writing.
585 			 */
586 			if (fseek(fout, 0L, L_INCR) < 0) {
587 				perror_reply(550, name);
588 				goto done;
589 			}
590 		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
591 			perror_reply(550, name);
592 			goto done;
593 		}
594 	}
595 	din = dataconn(name, (off_t)-1, "r");
596 	if (din == NULL)
597 		goto done;
598 	if (receive_data(din, fout) == 0) {
599 		if (unique)
600 			reply(226, "Transfer complete (unique file name:%s).",
601 			    name);
602 		else
603 			reply(226, "Transfer complete.");
604 	}
605 	(void) fclose(din);
606 	data = -1;
607 	pdata = -1;
608 done:
609 	(*closefunc)(fout);
610 }
611 
612 FILE *
613 getdatasock(mode)
614 	char *mode;
615 {
616 	int s, on = 1, tries;
617 
618 	if (data >= 0)
619 		return (fdopen(data, mode));
620 	s = socket(AF_INET, SOCK_STREAM, 0);
621 	if (s < 0)
622 		return (NULL);
623 	(void) seteuid((uid_t)0);
624 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
625 	    (char *) &on, sizeof (on)) < 0)
626 		goto bad;
627 	/* anchor socket to avoid multi-homing problems */
628 	data_source.sin_family = AF_INET;
629 	data_source.sin_addr = ctrl_addr.sin_addr;
630 	for (tries = 1; ; tries++) {
631 		if (bind(s, (struct sockaddr *)&data_source,
632 		    sizeof (data_source)) >= 0)
633 			break;
634 		if (errno != EADDRINUSE || tries > 10)
635 			goto bad;
636 		sleep(tries);
637 	}
638 	(void) seteuid((uid_t)pw->pw_uid);
639 	return (fdopen(s, mode));
640 bad:
641 	(void) seteuid((uid_t)pw->pw_uid);
642 	(void) close(s);
643 	return (NULL);
644 }
645 
646 FILE *
647 dataconn(name, size, mode)
648 	char *name;
649 	off_t size;
650 	char *mode;
651 {
652 	char sizebuf[32];
653 	FILE *file;
654 	int retry = 0;
655 
656 	file_size = size;
657 	byte_count = 0;
658 	if (size != (off_t) -1)
659 		(void) sprintf (sizebuf, " (%ld bytes)", size);
660 	else
661 		(void) strcpy(sizebuf, "");
662 	if (pdata >= 0) {
663 		struct sockaddr_in from;
664 		int s, fromlen = sizeof(from);
665 
666 		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
667 		if (s < 0) {
668 			reply(425, "Can't open data connection.");
669 			(void) close(pdata);
670 			pdata = -1;
671 			return(NULL);
672 		}
673 		(void) close(pdata);
674 		pdata = s;
675 		reply(150, "Opening %s mode data connection for %s%s.",
676 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
677 		return(fdopen(pdata, mode));
678 	}
679 	if (data >= 0) {
680 		reply(125, "Using existing data connection for %s%s.",
681 		    name, sizebuf);
682 		usedefault = 1;
683 		return (fdopen(data, mode));
684 	}
685 	if (usedefault)
686 		data_dest = his_addr;
687 	usedefault = 1;
688 	file = getdatasock(mode);
689 	if (file == NULL) {
690 		reply(425, "Can't create data socket (%s,%d): %s.",
691 		    inet_ntoa(data_source.sin_addr),
692 		    ntohs(data_source.sin_port), strerror(errno));
693 		return (NULL);
694 	}
695 	data = fileno(file);
696 	while (connect(data, (struct sockaddr *)&data_dest,
697 	    sizeof (data_dest)) < 0) {
698 		if (errno == EADDRINUSE && retry < swaitmax) {
699 			sleep((unsigned) swaitint);
700 			retry += swaitint;
701 			continue;
702 		}
703 		perror_reply(425, "Can't build data connection");
704 		(void) fclose(file);
705 		data = -1;
706 		return (NULL);
707 	}
708 	reply(150, "Opening %s mode data connection for %s%s.",
709 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
710 	return (file);
711 }
712 
713 /*
714  * Tranfer the contents of "instr" to
715  * "outstr" peer using the appropriate
716  * encapsulation of the data subject
717  * to Mode, Structure, and Type.
718  *
719  * NB: Form isn't handled.
720  */
721 send_data(instr, outstr, blksize)
722 	FILE *instr, *outstr;
723 	off_t blksize;
724 {
725 	register int c, cnt;
726 	register char *buf;
727 	int netfd, filefd;
728 
729 	transflag++;
730 	if (setjmp(urgcatch)) {
731 		transflag = 0;
732 		return;
733 	}
734 	switch (type) {
735 
736 	case TYPE_A:
737 		while ((c = getc(instr)) != EOF) {
738 			byte_count++;
739 			if (c == '\n') {
740 				if (ferror(outstr))
741 					goto data_err;
742 				(void) putc('\r', outstr);
743 			}
744 			(void) putc(c, outstr);
745 		}
746 		fflush(outstr);
747 		transflag = 0;
748 		if (ferror(instr))
749 			goto file_err;
750 		if (ferror(outstr))
751 			goto data_err;
752 		reply(226, "Transfer complete.");
753 		return;
754 
755 	case TYPE_I:
756 	case TYPE_L:
757 		if ((buf = malloc((u_int)blksize)) == NULL) {
758 			transflag = 0;
759 			perror_reply(451, "Local resource failure: malloc");
760 			return;
761 		}
762 		netfd = fileno(outstr);
763 		filefd = fileno(instr);
764 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
765 		    write(netfd, buf, cnt) == cnt)
766 			byte_count += cnt;
767 		transflag = 0;
768 		(void)free(buf);
769 		if (cnt != 0) {
770 			if (cnt < 0)
771 				goto file_err;
772 			goto data_err;
773 		}
774 		reply(226, "Transfer complete.");
775 		return;
776 	default:
777 		transflag = 0;
778 		reply(550, "Unimplemented TYPE %d in send_data", type);
779 		return;
780 	}
781 
782 data_err:
783 	transflag = 0;
784 	perror_reply(426, "Data connection");
785 	return;
786 
787 file_err:
788 	transflag = 0;
789 	perror_reply(551, "Error on input file");
790 }
791 
792 /*
793  * Transfer data from peer to
794  * "outstr" using the appropriate
795  * encapulation of the data subject
796  * to Mode, Structure, and Type.
797  *
798  * N.B.: Form isn't handled.
799  */
800 receive_data(instr, outstr)
801 	FILE *instr, *outstr;
802 {
803 	register int c;
804 	int cnt, bare_lfs = 0;
805 	char buf[BUFSIZ];
806 
807 	transflag++;
808 	if (setjmp(urgcatch)) {
809 		transflag = 0;
810 		return (-1);
811 	}
812 	switch (type) {
813 
814 	case TYPE_I:
815 	case TYPE_L:
816 		while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
817 			if (write(fileno(outstr), buf, cnt) != cnt)
818 				goto file_err;
819 			byte_count += cnt;
820 		}
821 		if (cnt < 0)
822 			goto data_err;
823 		transflag = 0;
824 		return (0);
825 
826 	case TYPE_E:
827 		reply(553, "TYPE E not implemented.");
828 		transflag = 0;
829 		return (-1);
830 
831 	case TYPE_A:
832 		while ((c = getc(instr)) != EOF) {
833 			byte_count++;
834 			if (c == '\n')
835 				bare_lfs++;
836 			while (c == '\r') {
837 				if (ferror(outstr))
838 					goto data_err;
839 				if ((c = getc(instr)) != '\n') {
840 					(void) putc ('\r', outstr);
841 					if (c == '\0' || c == EOF)
842 						goto contin2;
843 				}
844 			}
845 			(void) putc(c, outstr);
846 	contin2:	;
847 		}
848 		fflush(outstr);
849 		if (ferror(instr))
850 			goto data_err;
851 		if (ferror(outstr))
852 			goto file_err;
853 		transflag = 0;
854 		if (bare_lfs) {
855 			lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
856 			printf("   File may not have transferred correctly.\r\n");
857 		}
858 		return (0);
859 	default:
860 		reply(550, "Unimplemented TYPE %d in receive_data", type);
861 		transflag = 0;
862 		return (-1);
863 	}
864 
865 data_err:
866 	transflag = 0;
867 	perror_reply(426, "Data Connection");
868 	return (-1);
869 
870 file_err:
871 	transflag = 0;
872 	perror_reply(452, "Error writing file");
873 	return (-1);
874 }
875 
876 statfilecmd(filename)
877 	char *filename;
878 {
879 	char line[BUFSIZ];
880 	FILE *fin;
881 	int c;
882 
883 	(void) sprintf(line, "/bin/ls -lgA %s", filename);
884 	fin = ftpd_popen(line, "r");
885 	lreply(211, "status of %s:", filename);
886 	while ((c = getc(fin)) != EOF) {
887 		if (c == '\n') {
888 			if (ferror(stdout)){
889 				perror_reply(421, "control connection");
890 				(void) ftpd_pclose(fin);
891 				dologout(1);
892 				/* NOTREACHED */
893 			}
894 			if (ferror(fin)) {
895 				perror_reply(551, filename);
896 				(void) ftpd_pclose(fin);
897 				return;
898 			}
899 			(void) putc('\r', stdout);
900 		}
901 		(void) putc(c, stdout);
902 	}
903 	(void) ftpd_pclose(fin);
904 	reply(211, "End of Status");
905 }
906 
907 statcmd()
908 {
909 	struct sockaddr_in *sin;
910 	u_char *a, *p;
911 
912 	lreply(211, "%s FTP server status:", hostname, version);
913 	printf("     %s\r\n", version);
914 	printf("     Connected to %s", remotehost);
915 	if (!isdigit(remotehost[0]))
916 		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
917 	printf("\r\n");
918 	if (logged_in) {
919 		if (guest)
920 			printf("     Logged in anonymously\r\n");
921 		else
922 			printf("     Logged in as %s\r\n", pw->pw_name);
923 	} else if (askpasswd)
924 		printf("     Waiting for password\r\n");
925 	else
926 		printf("     Waiting for user name\r\n");
927 	printf("     TYPE: %s", typenames[type]);
928 	if (type == TYPE_A || type == TYPE_E)
929 		printf(", FORM: %s", formnames[form]);
930 	if (type == TYPE_L)
931 #if NBBY == 8
932 		printf(" %d", NBBY);
933 #else
934 		printf(" %d", bytesize);	/* need definition! */
935 #endif
936 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
937 	    strunames[stru], modenames[mode]);
938 	if (data != -1)
939 		printf("     Data connection open\r\n");
940 	else if (pdata != -1) {
941 		printf("     in Passive mode");
942 		sin = &pasv_addr;
943 		goto printaddr;
944 	} else if (usedefault == 0) {
945 		printf("     PORT");
946 		sin = &data_dest;
947 printaddr:
948 		a = (u_char *) &sin->sin_addr;
949 		p = (u_char *) &sin->sin_port;
950 #define UC(b) (((int) b) & 0xff)
951 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
952 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
953 #undef UC
954 	} else
955 		printf("     No data connection\r\n");
956 	reply(211, "End of status");
957 }
958 
959 fatal(s)
960 	char *s;
961 {
962 	reply(451, "Error in server: %s\n", s);
963 	reply(221, "Closing connection due to server error.");
964 	dologout(0);
965 	/* NOTREACHED */
966 }
967 
968 /* VARARGS2 */
969 reply(n, fmt, p0, p1, p2, p3, p4, p5)
970 	int n;
971 	char *fmt;
972 {
973 	printf("%d ", n);
974 	printf(fmt, p0, p1, p2, p3, p4, p5);
975 	printf("\r\n");
976 	(void)fflush(stdout);
977 	if (debug) {
978 		syslog(LOG_DEBUG, "<--- %d ", n);
979 		syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
980 }
981 }
982 
983 /* VARARGS2 */
984 lreply(n, fmt, p0, p1, p2, p3, p4, p5)
985 	int n;
986 	char *fmt;
987 {
988 	printf("%d- ", n);
989 	printf(fmt, p0, p1, p2, p3, p4, p5);
990 	printf("\r\n");
991 	(void)fflush(stdout);
992 	if (debug) {
993 		syslog(LOG_DEBUG, "<--- %d- ", n);
994 		syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
995 	}
996 }
997 
998 ack(s)
999 	char *s;
1000 {
1001 	reply(250, "%s command successful.", s);
1002 }
1003 
1004 nack(s)
1005 	char *s;
1006 {
1007 	reply(502, "%s command not implemented.", s);
1008 }
1009 
1010 /* ARGSUSED */
1011 yyerror(s)
1012 	char *s;
1013 {
1014 	char *cp;
1015 
1016 	if (cp = index(cbuf,'\n'))
1017 		*cp = '\0';
1018 	reply(500, "'%s': command not understood.", cbuf);
1019 }
1020 
1021 delete(name)
1022 	char *name;
1023 {
1024 	struct stat st;
1025 
1026 	if (stat(name, &st) < 0) {
1027 		perror_reply(550, name);
1028 		return;
1029 	}
1030 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1031 		if (rmdir(name) < 0) {
1032 			perror_reply(550, name);
1033 			return;
1034 		}
1035 		goto done;
1036 	}
1037 	if (unlink(name) < 0) {
1038 		perror_reply(550, name);
1039 		return;
1040 	}
1041 done:
1042 	ack("DELE");
1043 }
1044 
1045 cwd(path)
1046 	char *path;
1047 {
1048 	if (chdir(path) < 0)
1049 		perror_reply(550, path);
1050 	else
1051 		ack("CWD");
1052 }
1053 
1054 makedir(name)
1055 	char *name;
1056 {
1057 	if (mkdir(name, 0777) < 0)
1058 		perror_reply(550, name);
1059 	else
1060 		reply(257, "MKD command successful.");
1061 }
1062 
1063 removedir(name)
1064 	char *name;
1065 {
1066 	if (rmdir(name) < 0)
1067 		perror_reply(550, name);
1068 	else
1069 		ack("RMD");
1070 }
1071 
1072 pwd()
1073 {
1074 	char path[MAXPATHLEN + 1];
1075 	extern char *getwd();
1076 
1077 	if (getwd(path) == (char *)NULL)
1078 		reply(550, "%s.", path);
1079 	else
1080 		reply(257, "\"%s\" is current directory.", path);
1081 }
1082 
1083 char *
1084 renamefrom(name)
1085 	char *name;
1086 {
1087 	struct stat st;
1088 
1089 	if (stat(name, &st) < 0) {
1090 		perror_reply(550, name);
1091 		return ((char *)0);
1092 	}
1093 	reply(350, "File exists, ready for destination name");
1094 	return (name);
1095 }
1096 
1097 renamecmd(from, to)
1098 	char *from, *to;
1099 {
1100 	if (rename(from, to) < 0)
1101 		perror_reply(550, "rename");
1102 	else
1103 		ack("RNTO");
1104 }
1105 
1106 dolog(sin)
1107 	struct sockaddr_in *sin;
1108 {
1109 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1110 		sizeof (struct in_addr), AF_INET);
1111 	time_t t, time();
1112 	extern char *ctime();
1113 
1114 	if (hp)
1115 		(void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
1116 	else
1117 		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1118 		    sizeof (remotehost));
1119 #ifdef SETPROCTITLE
1120 	sprintf(proctitle, "%s: connected", remotehost);
1121 	setproctitle(proctitle);
1122 #endif /* SETPROCTITLE */
1123 
1124 	if (logging) {
1125 		t = time((time_t *) 0);
1126 		syslog(LOG_INFO, "connection from %s at %s",
1127 		    remotehost, ctime(&t));
1128 	}
1129 }
1130 
1131 /*
1132  * Record logout in wtmp file
1133  * and exit with supplied status.
1134  */
1135 dologout(status)
1136 	int status;
1137 {
1138 	if (logged_in) {
1139 		(void) seteuid((uid_t)0);
1140 		logwtmp(ttyline, "", "");
1141 	}
1142 	/* beware of flushing buffers after a SIGPIPE */
1143 	_exit(status);
1144 }
1145 
1146 myoob()
1147 {
1148 	char *cp;
1149 
1150 	/* only process if transfer occurring */
1151 	if (!transflag)
1152 		return;
1153 	cp = tmpline;
1154 	if (getline(cp, 7, stdin) == NULL) {
1155 		reply(221, "You could at least say goodbye.");
1156 		dologout(0);
1157 	}
1158 	upper(cp);
1159 	if (strcmp(cp, "ABOR\r\n") == 0) {
1160 		tmpline[0] = '\0';
1161 		reply(426, "Transfer aborted. Data connection closed.");
1162 		reply(226, "Abort successful");
1163 		longjmp(urgcatch, 1);
1164 	}
1165 	if (strcmp(cp, "STAT\r\n") == 0) {
1166 		if (file_size != (off_t) -1)
1167 			reply(213, "Status: %lu of %lu bytes transferred",
1168 			    byte_count, file_size);
1169 		else
1170 			reply(213, "Status: %lu bytes transferred", byte_count);
1171 	}
1172 }
1173 
1174 /*
1175  * Note: a response of 425 is not mentioned as a possible response to
1176  * 	the PASV command in RFC959. However, it has been blessed as
1177  * 	a legitimate response by Jon Postel in a telephone conversation
1178  *	with Rick Adams on 25 Jan 89.
1179  */
1180 passive()
1181 {
1182 	int len;
1183 	register char *p, *a;
1184 
1185 	pdata = socket(AF_INET, SOCK_STREAM, 0);
1186 	if (pdata < 0) {
1187 		perror_reply(425, "Can't open passive connection");
1188 		return;
1189 	}
1190 	pasv_addr = ctrl_addr;
1191 	pasv_addr.sin_port = 0;
1192 	(void) seteuid((uid_t)0);
1193 	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1194 		(void) seteuid((uid_t)pw->pw_uid);
1195 		goto pasv_error;
1196 	}
1197 	(void) seteuid((uid_t)pw->pw_uid);
1198 	len = sizeof(pasv_addr);
1199 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1200 		goto pasv_error;
1201 	if (listen(pdata, 1) < 0)
1202 		goto pasv_error;
1203 	a = (char *) &pasv_addr.sin_addr;
1204 	p = (char *) &pasv_addr.sin_port;
1205 
1206 #define UC(b) (((int) b) & 0xff)
1207 
1208 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1209 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1210 	return;
1211 
1212 pasv_error:
1213 	(void) close(pdata);
1214 	pdata = -1;
1215 	perror_reply(425, "Can't open passive connection");
1216 	return;
1217 }
1218 
1219 /*
1220  * Generate unique name for file with basename "local".
1221  * The file named "local" is already known to exist.
1222  * Generates failure reply on error.
1223  */
1224 char *
1225 gunique(local)
1226 	char *local;
1227 {
1228 	static char new[MAXPATHLEN];
1229 	struct stat st;
1230 	char *cp = rindex(local, '/');
1231 	int count = 0;
1232 
1233 	if (cp)
1234 		*cp = '\0';
1235 	if (stat(cp ? local : ".", &st) < 0) {
1236 		perror_reply(553, cp ? local : ".");
1237 		return((char *) 0);
1238 	}
1239 	if (cp)
1240 		*cp = '/';
1241 	(void) strcpy(new, local);
1242 	cp = new + strlen(new);
1243 	*cp++ = '.';
1244 	for (count = 1; count < 100; count++) {
1245 		(void) sprintf(cp, "%d", count);
1246 		if (stat(new, &st) < 0)
1247 			return(new);
1248 	}
1249 	reply(452, "Unique file name cannot be created.");
1250 	return((char *) 0);
1251 }
1252 
1253 /*
1254  * Format and send reply containing system error number.
1255  */
1256 perror_reply(code, string)
1257 	int code;
1258 	char *string;
1259 {
1260 	reply(code, "%s: %s.", string, strerror(errno));
1261 }
1262 
1263 static char *onefile[] = {
1264 	"",
1265 	0
1266 };
1267 
1268 send_file_list(whichfiles)
1269 	char *whichfiles;
1270 {
1271 	struct stat st;
1272 	DIR *dirp = NULL;
1273 	struct direct *dir;
1274 	FILE *dout = NULL;
1275 	register char **dirlist, *dirname;
1276 	int simple = 0;
1277 	char *strpbrk();
1278 
1279 	if (strpbrk(whichfiles, "~{[*?") != NULL) {
1280 		extern char **glob(), *globerr;
1281 
1282 		globerr = NULL;
1283 		dirlist = glob(whichfiles);
1284 		if (globerr != NULL) {
1285 			reply(550, globerr);
1286 			return;
1287 		} else if (dirlist == NULL) {
1288 			errno = ENOENT;
1289 			perror_reply(550, whichfiles);
1290 			return;
1291 		}
1292 	} else {
1293 		onefile[0] = whichfiles;
1294 		dirlist = onefile;
1295 		simple = 1;
1296 	}
1297 
1298 	if (setjmp(urgcatch)) {
1299 		transflag = 0;
1300 		return;
1301 	}
1302 	while (dirname = *dirlist++) {
1303 		if (stat(dirname, &st) < 0) {
1304 			/*
1305 			 * If user typed "ls -l", etc, and the client
1306 			 * used NLST, do what the user meant.
1307 			 */
1308 			if (dirname[0] == '-' && *dirlist == NULL &&
1309 			    transflag == 0) {
1310 				retrieve("/bin/ls %s", dirname);
1311 				return;
1312 			}
1313 			perror_reply(550, whichfiles);
1314 			if (dout != NULL) {
1315 				(void) fclose(dout);
1316 				transflag = 0;
1317 				data = -1;
1318 				pdata = -1;
1319 			}
1320 			return;
1321 		}
1322 
1323 		if ((st.st_mode&S_IFMT) == S_IFREG) {
1324 			if (dout == NULL) {
1325 				dout = dataconn("file list", (off_t)-1, "w");
1326 				if (dout == NULL)
1327 					return;
1328 				transflag++;
1329 			}
1330 			fprintf(dout, "%s%s\n", dirname,
1331 				type == TYPE_A ? "\r" : "");
1332 			byte_count += strlen(dirname) + 1;
1333 			continue;
1334 		} else if ((st.st_mode&S_IFMT) != S_IFDIR)
1335 			continue;
1336 
1337 		if ((dirp = opendir(dirname)) == NULL)
1338 			continue;
1339 
1340 		while ((dir = readdir(dirp)) != NULL) {
1341 			char nbuf[MAXPATHLEN];
1342 
1343 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1344 				continue;
1345 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1346 			    dir->d_namlen == 2)
1347 				continue;
1348 
1349 			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
1350 
1351 			/*
1352 			 * We have to do a stat to insure it's
1353 			 * not a directory or special file.
1354 			 */
1355 			if (simple || (stat(nbuf, &st) == 0 &&
1356 			    (st.st_mode&S_IFMT) == S_IFREG)) {
1357 				if (dout == NULL) {
1358 					dout = dataconn("file list", (off_t)-1,
1359 						"w");
1360 					if (dout == NULL)
1361 						return;
1362 					transflag++;
1363 				}
1364 				if (nbuf[0] == '.' && nbuf[1] == '/')
1365 					fprintf(dout, "%s%s\n", &nbuf[2],
1366 						type == TYPE_A ? "\r" : "");
1367 				else
1368 					fprintf(dout, "%s%s\n", nbuf,
1369 						type == TYPE_A ? "\r" : "");
1370 				byte_count += strlen(nbuf) + 1;
1371 			}
1372 		}
1373 		(void) closedir(dirp);
1374 	}
1375 
1376 	if (dout == NULL)
1377 		reply(550, "No files found.");
1378 	else if (ferror(dout) != 0)
1379 		perror_reply(550, "Data connection");
1380 	else
1381 		reply(226, "Transfer complete.");
1382 
1383 	transflag = 0;
1384 	if (dout != NULL)
1385 		(void) fclose(dout);
1386 	data = -1;
1387 	pdata = -1;
1388 }
1389 
1390 #ifdef SETPROCTITLE
1391 /*
1392  * clobber argv so ps will show what we're doing.
1393  * (stolen from sendmail)
1394  * warning, since this is usually started from inetd.conf, it
1395  * often doesn't have much of an environment or arglist to overwrite.
1396  */
1397 
1398 /*VARARGS1*/
1399 setproctitle(fmt, a, b, c)
1400 char *fmt;
1401 {
1402 	register char *p, *bp, ch;
1403 	register int i;
1404 	char buf[BUFSIZ];
1405 
1406 	(void) sprintf(buf, fmt, a, b, c);
1407 
1408 	/* make ps print our process name */
1409 	p = Argv[0];
1410 	*p++ = '-';
1411 
1412 	i = strlen(buf);
1413 	if (i > LastArgv - p - 2) {
1414 		i = LastArgv - p - 2;
1415 		buf[i] = '\0';
1416 	}
1417 	bp = buf;
1418 	while (ch = *bp++)
1419 		if (ch != '\n' && ch != '\r')
1420 			*p++ = ch;
1421 	while (p < LastArgv)
1422 		*p++ = ' ';
1423 }
1424 #endif /* SETPROCTITLE */
1425