xref: /freebsd/libexec/ftpd/ftpd.c (revision 05c7a37afb48ddd5ee1bd921a5d46fe59cc70b15)
1 /*
2  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	$Id: ftpd.c,v 1.15 1996/03/18 11:09:03 davidg Exp $
34  */
35 
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
39 	The Regents of the University of California.  All rights reserved.\n";
40 #endif /* not lint */
41 
42 #ifndef lint
43 static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
44 #endif /* not lint */
45 
46 /*
47  * FTP server.
48  */
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <sys/socket.h>
53 #include <sys/wait.h>
54 #include <sys/mman.h>
55 
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/ip.h>
59 #include <netinet/tcp.h>
60 
61 #define	FTP_NAMES
62 #include <arpa/ftp.h>
63 #include <arpa/inet.h>
64 #include <arpa/telnet.h>
65 
66 #include <ctype.h>
67 #include <dirent.h>
68 #include <err.h>
69 #include <errno.h>
70 #include <fcntl.h>
71 #include <glob.h>
72 #include <limits.h>
73 #include <netdb.h>
74 #include <pwd.h>
75 #include <setjmp.h>
76 #include <signal.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <syslog.h>
81 #include <time.h>
82 #include <unistd.h>
83 #include <libutil.h>
84 
85 #ifdef	SKEY
86 #include <skey.h>
87 #endif
88 
89 #include "pathnames.h"
90 #include "extern.h"
91 
92 #if __STDC__
93 #include <stdarg.h>
94 #else
95 #include <varargs.h>
96 #endif
97 
98 static char version[] = "Version 6.00";
99 
100 extern	off_t restart_point;
101 extern	char cbuf[];
102 
103 struct	sockaddr_in server_addr;
104 struct	sockaddr_in ctrl_addr;
105 struct	sockaddr_in data_source;
106 struct	sockaddr_in data_dest;
107 struct	sockaddr_in his_addr;
108 struct	sockaddr_in pasv_addr;
109 
110 int	daemon_mode;
111 int	data;
112 jmp_buf	errcatch, urgcatch;
113 int	logged_in;
114 struct	passwd *pw;
115 int	debug;
116 int	timeout = 900;    /* timeout after 15 minutes of inactivity */
117 int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
118 int	logging;
119 int	restricted_data_ports = 1;
120 int	guest;
121 #ifdef STATS
122 int	stats;
123 int	statfd = -1;
124 #endif
125 int	type;
126 int	form;
127 int	stru;			/* avoid C keyword */
128 int	mode;
129 int	usedefault = 1;		/* for data transfers */
130 int	pdata = -1;		/* for passive mode */
131 sig_atomic_t transflag;
132 off_t	file_size;
133 off_t	byte_count;
134 #if !defined(CMASK) || CMASK == 0
135 #undef CMASK
136 #define CMASK 027
137 #endif
138 int	defumask = CMASK;		/* default umask value */
139 char	tmpline[7];
140 char	hostname[MAXHOSTNAMELEN];
141 char	remotehost[MAXHOSTNAMELEN];
142 #ifdef STATS
143 char	*ident = NULL;
144 #endif
145 
146 /*
147  * Timeout intervals for retrying connections
148  * to hosts that don't accept PORT cmds.  This
149  * is a kludge, but given the problems with TCP...
150  */
151 #define	SWAITMAX	90	/* wait at most 90 seconds */
152 #define	SWAITINT	5	/* interval between retries */
153 
154 int	swaitmax = SWAITMAX;
155 int	swaitint = SWAITINT;
156 
157 #ifdef SETPROCTITLE
158 #ifdef OLD_SETPROCTITLE
159 char	**Argv = NULL;		/* pointer to argument vector */
160 char	*LastArgv = NULL;	/* end of argv */
161 #endif /* OLD_SETPROCTITLE */
162 char	proctitle[LINE_MAX];	/* initial part of title */
163 #endif /* SETPROCTITLE */
164 
165 #ifdef SKEY
166 int	pwok = 0;
167 char	addr_string[20];	/* XXX */
168 #endif
169 
170 #define LOGCMD(cmd, file) \
171 	if (logging > 1) \
172 	    syslog(LOG_INFO,"%s %s%s", cmd, \
173 		*(file) == '/' ? "" : curdir(), file);
174 #define LOGCMD2(cmd, file1, file2) \
175 	 if (logging > 1) \
176 	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
177 		*(file1) == '/' ? "" : curdir(), file1, \
178 		*(file2) == '/' ? "" : curdir(), file2);
179 #define LOGBYTES(cmd, file, cnt) \
180 	if (logging > 1) { \
181 		if (cnt == (off_t)-1) \
182 		    syslog(LOG_INFO,"%s %s%s", cmd, \
183 			*(file) == '/' ? "" : curdir(), file); \
184 		else \
185 		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
186 			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
187 	}
188 
189 static void	 ack __P((char *));
190 static void	 myoob __P((int));
191 static int	 checkuser __P((char *));
192 static FILE	*dataconn __P((char *, off_t, char *));
193 static void	 dolog __P((struct sockaddr_in *));
194 static char	*curdir __P((void));
195 static void	 end_login __P((void));
196 static FILE	*getdatasock __P((char *));
197 static char	*gunique __P((char *));
198 static void	 lostconn __P((int));
199 static int	 receive_data __P((FILE *, FILE *));
200 static void	 send_data __P((FILE *, FILE *, off_t, off_t, int));
201 static struct passwd *
202 		 sgetpwnam __P((char *));
203 static char	*sgetsave __P((char *));
204 static void	 reapchild __P((int));
205 
206 static char *
207 curdir()
208 {
209 	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */
210 
211 	if (getcwd(path, sizeof(path)-2) == NULL)
212 		return ("");
213 	if (path[1] != '\0')		/* special case for root dir. */
214 		strcat(path, "/");
215 	/* For guest account, skip / since it's chrooted */
216 	return (guest ? path+1 : path);
217 }
218 
219 int
220 main(argc, argv, envp)
221 	int argc;
222 	char *argv[];
223 	char **envp;
224 {
225 	int addrlen, ch, on = 1, tos;
226 	char *cp, line[LINE_MAX];
227 	FILE *fd;
228 
229 	tzset();		/* in case no timezone database in ~ftp */
230 
231 #ifdef OLD_SETPROCTITLE
232 	/*
233 	 *  Save start and extent of argv for setproctitle.
234 	 */
235 	Argv = argv;
236 	while (*envp)
237 		envp++;
238 	LastArgv = envp[-1] + strlen(envp[-1]);
239 #endif /* OLD_SETPROCTITLE */
240 
241 
242 #ifdef STATS
243 	while ((ch = getopt(argc, argv, "dlDSt:T:u:v")) != EOF) {
244 #else
245 	while ((ch = getopt(argc, argv, "dlDUt:T:u:v")) != EOF) {
246 #endif
247 		switch (ch) {
248 		case 'D':
249 			daemon_mode++;
250 			break;
251 
252 		case 'd':
253 			debug = 1;
254 			break;
255 
256 		case 'l':
257 			logging++;	/* > 1 == extra logging */
258 			break;
259 
260 		case 'U':
261 			restricted_data_ports = 0;
262 			break;
263 
264 		case 't':
265 			timeout = atoi(optarg);
266 			if (maxtimeout < timeout)
267 				maxtimeout = timeout;
268 			break;
269 #ifdef STATS
270 		case 'S':
271 			stats =  1;
272 			break;
273 #endif
274 		case 'T':
275 			maxtimeout = atoi(optarg);
276 			if (timeout > maxtimeout)
277 				timeout = maxtimeout;
278 			break;
279 
280 		case 'u':
281 		    {
282 			long val = 0;
283 
284 			val = strtol(optarg, &optarg, 8);
285 			if (*optarg != '\0' || val < 0)
286 				warnx("bad value for -u");
287 			else
288 				defumask = val;
289 			break;
290 		    }
291 
292 		case 'v':
293 			debug = 1;
294 			break;
295 
296 		default:
297 			warnx("unknown flag -%c ignored", optopt);
298 			break;
299 		}
300 	}
301 
302 	(void) freopen(_PATH_DEVNULL, "w", stderr);
303 
304 	/*
305 	 * LOG_NDELAY sets up the logging connection immediately,
306 	 * necessary for anonymous ftp's that chroot and can't do it later.
307 	 */
308 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
309 
310 	if (daemon_mode) {
311 		int ctl_sock, fd;
312 		struct servent *sv;
313 
314 		/*
315 		 * Detach from parent.
316 		 */
317 		if (daemon(1, 1) < 0) {
318 			syslog(LOG_ERR, "failed to become a daemon");
319 			exit(1);
320 		}
321 		(void) signal(SIGCHLD, reapchild);
322 		/*
323 		 * Get port number for ftp/tcp.
324 		 */
325 		sv = getservbyname("ftp", "tcp");
326 		if (sv == NULL) {
327 			syslog(LOG_ERR, "getservbyname for ftp failed");
328 			exit(1);
329 		}
330 		/*
331 		 * Open a socket, bind it to the FTP port, and start
332 		 * listening.
333 		 */
334 		ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
335 		if (ctl_sock < 0) {
336 			syslog(LOG_ERR, "control socket: %m");
337 			exit(1);
338 		}
339 		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
340 		    (char *)&on, sizeof(on)) < 0)
341 			syslog(LOG_ERR, "control setsockopt: %m");;
342 		server_addr.sin_family = AF_INET;
343 		server_addr.sin_addr.s_addr = INADDR_ANY;
344 		server_addr.sin_port = sv->s_port;
345 		if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
346 			syslog(LOG_ERR, "control bind: %m");
347 			exit(1);
348 		}
349 		if (listen(ctl_sock, 32) < 0) {
350 			syslog(LOG_ERR, "control listen: %m");
351 			exit(1);
352 		}
353 		/*
354 		 * Loop forever accepting connection requests and forking off
355 		 * children to handle them.
356 		 */
357 		while (1) {
358 			addrlen = sizeof(his_addr);
359 			fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
360 			if (fork() == 0) {
361 				/* child */
362 				(void) dup2(fd, 0);
363 				(void) dup2(fd, 1);
364 				close(ctl_sock);
365 				break;
366 			}
367 			close(fd);
368 		}
369 	} else {
370 		addrlen = sizeof(his_addr);
371 		if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
372 			syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
373 			exit(1);
374 		}
375 	}
376 
377 	(void) signal(SIGCHLD, SIG_IGN);
378 	(void) signal(SIGPIPE, lostconn);
379 	if ((int)signal(SIGURG, myoob) < 0)
380 		syslog(LOG_ERR, "signal: %m");
381 
382 #ifdef SKEY
383 	strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
384 #endif
385 	addrlen = sizeof(ctrl_addr);
386 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
387 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
388 		exit(1);
389 	}
390 #ifdef IP_TOS
391 	tos = IPTOS_LOWDELAY;
392 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
393 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
394 #endif
395 	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
396 
397 	/* Try to handle urgent data inline */
398 #ifdef SO_OOBINLINE
399 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
400 		syslog(LOG_ERR, "setsockopt: %m");
401 #endif
402 
403 #ifdef	F_SETOWN
404 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
405 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
406 #endif
407 	dolog(&his_addr);
408 	/*
409 	 * Set up default state
410 	 */
411 	data = -1;
412 	type = TYPE_A;
413 	form = FORM_N;
414 	stru = STRU_F;
415 	mode = MODE_S;
416 	tmpline[0] = '\0';
417 
418 	/* If logins are disabled, print out the message. */
419 	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
420 		while (fgets(line, sizeof(line), fd) != NULL) {
421 			if ((cp = strchr(line, '\n')) != NULL)
422 				*cp = '\0';
423 			lreply(530, "%s", line);
424 		}
425 		(void) fflush(stdout);
426 		(void) fclose(fd);
427 		reply(530, "System not available.");
428 		exit(0);
429 	}
430 	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
431 		while (fgets(line, sizeof(line), fd) != NULL) {
432 			if ((cp = strchr(line, '\n')) != NULL)
433 				*cp = '\0';
434 			lreply(220, "%s", line);
435 		}
436 		(void) fflush(stdout);
437 		(void) fclose(fd);
438 		/* reply(220,) must follow */
439 	}
440 	(void) gethostname(hostname, sizeof(hostname));
441 	reply(220, "%s FTP server (%s) ready.", hostname, version);
442 	(void) setjmp(errcatch);
443 	for (;;)
444 		(void) yyparse();
445 	/* NOTREACHED */
446 }
447 
448 static void
449 lostconn(signo)
450 	int signo;
451 {
452 
453 	if (debug)
454 		syslog(LOG_DEBUG, "lost connection");
455 	dologout(-1);
456 }
457 
458 static char ttyline[20];
459 
460 /*
461  * Helper function for sgetpwnam().
462  */
463 static char *
464 sgetsave(s)
465 	char *s;
466 {
467 	char *new = malloc((unsigned) strlen(s) + 1);
468 
469 	if (new == NULL) {
470 		perror_reply(421, "Local resource failure: malloc");
471 		dologout(1);
472 		/* NOTREACHED */
473 	}
474 	(void) strcpy(new, s);
475 	return (new);
476 }
477 
478 /*
479  * Save the result of a getpwnam.  Used for USER command, since
480  * the data returned must not be clobbered by any other command
481  * (e.g., globbing).
482  */
483 static struct passwd *
484 sgetpwnam(name)
485 	char *name;
486 {
487 	static struct passwd save;
488 	struct passwd *p;
489 
490 	if ((p = getpwnam(name)) == NULL)
491 		return (p);
492 	if (save.pw_name) {
493 		free(save.pw_name);
494 		free(save.pw_passwd);
495 		free(save.pw_gecos);
496 		free(save.pw_dir);
497 		free(save.pw_shell);
498 	}
499 	save = *p;
500 	save.pw_name = sgetsave(p->pw_name);
501 	save.pw_passwd = sgetsave(p->pw_passwd);
502 	save.pw_gecos = sgetsave(p->pw_gecos);
503 	save.pw_dir = sgetsave(p->pw_dir);
504 	save.pw_shell = sgetsave(p->pw_shell);
505 	return (&save);
506 }
507 
508 static int login_attempts;	/* number of failed login attempts */
509 static int askpasswd;		/* had user command, ask for passwd */
510 static char curname[10];	/* current USER name */
511 
512 /*
513  * USER command.
514  * Sets global passwd pointer pw if named account exists and is acceptable;
515  * sets askpasswd if a PASS command is expected.  If logged in previously,
516  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
517  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
518  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
519  * requesting login privileges.  Disallow anyone who does not have a standard
520  * shell as returned by getusershell().  Disallow anyone mentioned in the file
521  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
522  */
523 void
524 user(name)
525 	char *name;
526 {
527 	char *cp, *shell;
528 
529 	if (logged_in) {
530 		if (guest) {
531 			reply(530, "Can't change user from guest login.");
532 			return;
533 		}
534 		end_login();
535 	}
536 
537 	guest = 0;
538 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
539 		if (checkuser("ftp") || checkuser("anonymous"))
540 			reply(530, "User %s access denied.", name);
541 		else if ((pw = sgetpwnam("ftp")) != NULL) {
542 			guest = 1;
543 			askpasswd = 1;
544 			reply(331,
545 			"Guest login ok, send your email address as password.");
546 		} else
547 			reply(530, "User %s unknown.", name);
548 		if (!askpasswd && logging)
549 			syslog(LOG_NOTICE,
550 			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
551 		return;
552 	}
553 	if (pw = sgetpwnam(name)) {
554 		if ((shell = pw->pw_shell) == NULL || *shell == 0)
555 			shell = _PATH_BSHELL;
556 		while ((cp = getusershell()) != NULL)
557 			if (strcmp(cp, shell) == 0)
558 				break;
559 		endusershell();
560 
561 		if (cp == NULL || checkuser(name)) {
562 			reply(530, "User %s access denied.", name);
563 			if (logging)
564 				syslog(LOG_NOTICE,
565 				    "FTP LOGIN REFUSED FROM %s, %s",
566 				    remotehost, name);
567 			pw = (struct passwd *) NULL;
568 			return;
569 		}
570 	}
571 	if (logging)
572 		strncpy(curname, name, sizeof(curname)-1);
573 #ifdef SKEY
574 	pwok = skeyaccess(name, NULL, remotehost, addr_string);
575 	reply(331, "%s", skey_challenge(name, pw, pwok));
576 #else
577 	reply(331, "Password required for %s.", name);
578 #endif
579 	askpasswd = 1;
580 	/*
581 	 * Delay before reading passwd after first failed
582 	 * attempt to slow down passwd-guessing programs.
583 	 */
584 	if (login_attempts)
585 		sleep((unsigned) login_attempts);
586 }
587 
588 /*
589  * Check if a user is in the file _PATH_FTPUSERS
590  */
591 static int
592 checkuser(name)
593 	char *name;
594 {
595 	FILE *fd;
596 	int found = 0;
597 	char *p, line[BUFSIZ];
598 
599 	if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
600 		while (fgets(line, sizeof(line), fd) != NULL)
601 			if ((p = strchr(line, '\n')) != NULL) {
602 				*p = '\0';
603 				if (line[0] == '#')
604 					continue;
605 				if (strcmp(line, name) == 0) {
606 					found = 1;
607 					break;
608 				}
609 			}
610 		(void) fclose(fd);
611 	}
612 	return (found);
613 }
614 
615 /*
616  * Terminate login as previous user, if any, resetting state;
617  * used when USER command is given or login fails.
618  */
619 static void
620 end_login()
621 {
622 
623 	(void) seteuid((uid_t)0);
624 	if (logged_in)
625 		logwtmp(ttyline, "", "");
626 	pw = NULL;
627 	logged_in = 0;
628 	guest = 0;
629 }
630 
631 void
632 pass(passwd)
633 	char *passwd;
634 {
635 	char *salt, *xpasswd;
636 	FILE *fd;
637 	static char homedir[MAXPATHLEN];
638 
639 	if (logged_in || askpasswd == 0) {
640 		reply(503, "Login with USER first.");
641 		return;
642 	}
643 	askpasswd = 0;
644 	if (!guest) {		/* "ftp" is only account allowed no password */
645 		if (pw == NULL)
646 			salt = "xx";
647 		else
648 			salt = pw->pw_passwd;
649 #ifdef SKEY
650 		xpasswd = skey_crypt(passwd, salt, pw, pwok);
651 		pwok = 0;
652 #else
653 		xpasswd = crypt(passwd, salt);
654 #endif
655 		/* The strcmp does not catch null passwords! */
656 		if (pw == NULL || *pw->pw_passwd == '\0' ||
657 		    (pw->pw_expire && time(NULL) >= pw->pw_expire) ||
658 		    strcmp(xpasswd, pw->pw_passwd)) {
659 			reply(530, "Login incorrect.");
660 			if (logging)
661 				syslog(LOG_NOTICE,
662 				    "FTP LOGIN FAILED FROM %s, %s",
663 				    remotehost, curname);
664 			pw = NULL;
665 			if (login_attempts++ >= 5) {
666 				syslog(LOG_NOTICE,
667 				    "repeated login failures from %s",
668 				    remotehost);
669 				exit(0);
670 			}
671 			return;
672 		}
673 	}
674 	login_attempts = 0;		/* this time successful */
675 	if (setegid((gid_t)pw->pw_gid) < 0) {
676 		reply(550, "Can't set gid.");
677 		return;
678 	}
679 	(void) initgroups(pw->pw_name, pw->pw_gid);
680 
681 	/* open wtmp before chroot */
682 	(void)sprintf(ttyline, "ftp%d", getpid());
683 	logwtmp(ttyline, pw->pw_name, remotehost);
684 	logged_in = 1;
685 
686 #ifdef STATS
687 	if (guest && stats == 1 && statfd < 0)
688 		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
689 			stats = 0;
690 #endif
691 
692 	if (guest) {
693 		/*
694 		 * We MUST do a chdir() after the chroot. Otherwise
695 		 * the old current directory will be accessible as "."
696 		 * outside the new root!
697 		 */
698 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
699 			reply(550, "Can't set guest privileges.");
700 			goto bad;
701 		}
702 	} else if (chdir(pw->pw_dir) < 0) {
703 		if (chdir("/") < 0) {
704 			reply(530, "User %s: can't change directory to %s.",
705 			    pw->pw_name, pw->pw_dir);
706 			goto bad;
707 		} else
708 			lreply(230, "No directory! Logging in with home=/");
709 	}
710 	if (seteuid((uid_t)pw->pw_uid) < 0) {
711 		reply(550, "Can't set uid.");
712 		goto bad;
713 	}
714 
715 	/*
716 	 * Set home directory so that use of ~ (tilde) works correctly.
717 	 */
718 	if (getcwd(homedir, MAXPATHLEN) != NULL)
719 		setenv("HOME", homedir, 1);
720 
721 	/*
722 	 * Display a login message, if it exists.
723 	 * N.B. reply(230,) must follow the message.
724 	 */
725 	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
726 		char *cp, line[LINE_MAX];
727 
728 		while (fgets(line, sizeof(line), fd) != NULL) {
729 			if ((cp = strchr(line, '\n')) != NULL)
730 				*cp = '\0';
731 			lreply(230, "%s", line);
732 		}
733 		(void) fflush(stdout);
734 		(void) fclose(fd);
735 	}
736 	if (guest) {
737 #ifdef STATS
738 		char * copy();
739 
740 		if (ident != NULL)
741 			free(ident);
742 		ident = (char *) copy(passwd);
743 #endif
744 		reply(230, "Guest login ok, access restrictions apply.");
745 #ifdef SETPROCTITLE
746 		snprintf(proctitle, sizeof(proctitle),
747 		    "%s: anonymous/%.*s", remotehost,
748 		    sizeof(proctitle) - sizeof(remotehost) -
749 		    sizeof(": anonymous/"), passwd);
750 		setproctitle("%s", proctitle);
751 #endif /* SETPROCTITLE */
752 		if (logging)
753 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
754 			    remotehost, passwd);
755 	} else {
756 		reply(230, "User %s logged in.", pw->pw_name);
757 #ifdef SETPROCTITLE
758 		snprintf(proctitle, sizeof(proctitle),
759 		    "%s: %s", remotehost, pw->pw_name);
760 		setproctitle("%s", proctitle);
761 #endif /* SETPROCTITLE */
762 		if (logging)
763 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
764 			    remotehost, pw->pw_name);
765 	}
766 	(void) umask(defumask);
767 	return;
768 bad:
769 	/* Forget all about it... */
770 	end_login();
771 }
772 
773 void
774 retrieve(cmd, name)
775 	char *cmd, *name;
776 {
777 	FILE *fin, *dout;
778 	struct stat st;
779 	int (*closefunc) __P((FILE *));
780 #ifdef STATS
781 	long start;
782 #endif
783 
784 	if (cmd == 0) {
785 		fin = fopen(name, "r"), closefunc = fclose;
786 		st.st_size = 0;
787 	} else {
788 		char line[BUFSIZ];
789 
790 		(void) sprintf(line, cmd, name), name = line;
791 		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
792 		st.st_size = -1;
793 		st.st_blksize = BUFSIZ;
794 	}
795 	if (fin == NULL) {
796 		if (errno != 0) {
797 			perror_reply(550, name);
798 			if (cmd == 0) {
799 				LOGCMD("get", name);
800 			}
801 		}
802 		return;
803 	}
804 	byte_count = -1;
805 	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
806 		reply(550, "%s: not a plain file.", name);
807 		goto done;
808 	}
809 	if (restart_point) {
810 		if (type == TYPE_A) {
811 			off_t i, n;
812 			int c;
813 
814 			n = restart_point;
815 			i = 0;
816 			while (i++ < n) {
817 				if ((c=getc(fin)) == EOF) {
818 					perror_reply(550, name);
819 					goto done;
820 				}
821 				if (c == '\n')
822 					i++;
823 			}
824 		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
825 			perror_reply(550, name);
826 			goto done;
827 		}
828 	}
829 	dout = dataconn(name, st.st_size, "w");
830 	if (dout == NULL)
831 		goto done;
832 #ifdef STATS
833 	time(&start);
834 #endif
835 	send_data(fin, dout, st.st_blksize, st.st_size,
836 		  restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
837 #ifdef STATS
838 	if (cmd == 0 && guest && stats)
839 		logxfer( name, st.st_size, start);
840 #endif
841 	(void) fclose(dout);
842 	data = -1;
843 	pdata = -1;
844 done:
845 	if (cmd == 0)
846 		LOGBYTES("get", name, byte_count);
847 	(*closefunc)(fin);
848 }
849 
850 void
851 store(name, mode, unique)
852 	char *name, *mode;
853 	int unique;
854 {
855 	FILE *fout, *din;
856 	struct stat st;
857 	int (*closefunc) __P((FILE *));
858 
859 	if (unique && stat(name, &st) == 0 &&
860 	    (name = gunique(name)) == NULL) {
861 		LOGCMD(*mode == 'w' ? "put" : "append", name);
862 		return;
863 	}
864 
865 	if (restart_point)
866 		mode = "r+";
867 	fout = fopen(name, mode);
868 	closefunc = fclose;
869 	if (fout == NULL) {
870 		perror_reply(553, name);
871 		LOGCMD(*mode == 'w' ? "put" : "append", name);
872 		return;
873 	}
874 	byte_count = -1;
875 	if (restart_point) {
876 		if (type == TYPE_A) {
877 			off_t i, n;
878 			int c;
879 
880 			n = restart_point;
881 			i = 0;
882 			while (i++ < n) {
883 				if ((c=getc(fout)) == EOF) {
884 					perror_reply(550, name);
885 					goto done;
886 				}
887 				if (c == '\n')
888 					i++;
889 			}
890 			/*
891 			 * We must do this seek to "current" position
892 			 * because we are changing from reading to
893 			 * writing.
894 			 */
895 			if (fseek(fout, 0L, L_INCR) < 0) {
896 				perror_reply(550, name);
897 				goto done;
898 			}
899 		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
900 			perror_reply(550, name);
901 			goto done;
902 		}
903 	}
904 	din = dataconn(name, (off_t)-1, "r");
905 	if (din == NULL)
906 		goto done;
907 	if (receive_data(din, fout) == 0) {
908 		if (unique)
909 			reply(226, "Transfer complete (unique file name:%s).",
910 			    name);
911 		else
912 			reply(226, "Transfer complete.");
913 	}
914 	(void) fclose(din);
915 	data = -1;
916 	pdata = -1;
917 done:
918 	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
919 	(*closefunc)(fout);
920 }
921 
922 static FILE *
923 getdatasock(mode)
924 	char *mode;
925 {
926 	int on = 1, s, t, tries;
927 
928 	if (data >= 0)
929 		return (fdopen(data, mode));
930 	(void) seteuid((uid_t)0);
931 	s = socket(AF_INET, SOCK_STREAM, 0);
932 	if (s < 0)
933 		goto bad;
934 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
935 	    (char *) &on, sizeof(on)) < 0)
936 		goto bad;
937 	/* anchor socket to avoid multi-homing problems */
938 	data_source.sin_family = AF_INET;
939 	data_source.sin_addr = ctrl_addr.sin_addr;
940 	for (tries = 1; ; tries++) {
941 		if (bind(s, (struct sockaddr *)&data_source,
942 		    sizeof(data_source)) >= 0)
943 			break;
944 		if (errno != EADDRINUSE || tries > 10)
945 			goto bad;
946 		sleep(tries);
947 	}
948 	(void) seteuid((uid_t)pw->pw_uid);
949 #ifdef IP_TOS
950 	on = IPTOS_THROUGHPUT;
951 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
952 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
953 #endif
954 #ifdef TCP_NOPUSH
955 	/*
956 	 * Turn off push flag to keep sender TCP from sending short packets
957 	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
958 	 * to set the send buffer size as well, but that may not be desirable
959 	 * in heavy-load situations.
960 	 */
961 	on = 1;
962 	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
963 		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
964 #endif
965 #ifdef SO_SNDBUF
966 	on = 65536;
967 	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
968 		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
969 #endif
970 
971 	return (fdopen(s, mode));
972 bad:
973 	/* Return the real value of errno (close may change it) */
974 	t = errno;
975 	(void) seteuid((uid_t)pw->pw_uid);
976 	(void) close(s);
977 	errno = t;
978 	return (NULL);
979 }
980 
981 static FILE *
982 dataconn(name, size, mode)
983 	char *name;
984 	off_t size;
985 	char *mode;
986 {
987 	char sizebuf[32];
988 	FILE *file;
989 	int retry = 0, tos;
990 
991 	file_size = size;
992 	byte_count = 0;
993 	if (size != (off_t) -1)
994 		(void) sprintf(sizebuf, " (%qd bytes)", size);
995 	else
996 		(void) strcpy(sizebuf, "");
997 	if (pdata >= 0) {
998 		struct sockaddr_in from;
999 		int s, fromlen = sizeof(from);
1000 		struct timeval timeout;
1001 		fd_set set;
1002 
1003 		FD_ZERO(&set);
1004 		FD_SET(pdata, &set);
1005 
1006 		timeout.tv_usec = 0;
1007 		timeout.tv_sec = 120;
1008 
1009 		if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
1010 		    (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
1011 			reply(425, "Can't open data connection.");
1012 			(void) close(pdata);
1013 			pdata = -1;
1014 			return (NULL);
1015 		}
1016 		(void) close(pdata);
1017 		pdata = s;
1018 #ifdef IP_TOS
1019 		tos = IPTOS_LOWDELAY;
1020 		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1021 		    sizeof(int));
1022 #endif
1023 		reply(150, "Opening %s mode data connection for '%s'%s.",
1024 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1025 		return (fdopen(pdata, mode));
1026 	}
1027 	if (data >= 0) {
1028 		reply(125, "Using existing data connection for '%s'%s.",
1029 		    name, sizebuf);
1030 		usedefault = 1;
1031 		return (fdopen(data, mode));
1032 	}
1033 	if (usedefault)
1034 		data_dest = his_addr;
1035 	usedefault = 1;
1036 	file = getdatasock(mode);
1037 	if (file == NULL) {
1038 		reply(425, "Can't create data socket (%s,%d): %s.",
1039 		    inet_ntoa(data_source.sin_addr),
1040 		    ntohs(data_source.sin_port), strerror(errno));
1041 		return (NULL);
1042 	}
1043 	data = fileno(file);
1044 	while (connect(data, (struct sockaddr *)&data_dest,
1045 	    sizeof(data_dest)) < 0) {
1046 		if (errno == EADDRINUSE && retry < swaitmax) {
1047 			sleep((unsigned) swaitint);
1048 			retry += swaitint;
1049 			continue;
1050 		}
1051 		perror_reply(425, "Can't build data connection");
1052 		(void) fclose(file);
1053 		data = -1;
1054 		return (NULL);
1055 	}
1056 	reply(150, "Opening %s mode data connection for '%s'%s.",
1057 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1058 	return (file);
1059 }
1060 
1061 /*
1062  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1063  * encapsulation of the data subject to Mode, Structure, and Type.
1064  *
1065  * NB: Form isn't handled.
1066  */
1067 static void
1068 send_data(instr, outstr, blksize, filesize, isreg)
1069 	FILE *instr, *outstr;
1070 	off_t blksize;
1071 	off_t filesize;
1072 	int isreg;
1073 {
1074 	int c, cnt, filefd, netfd;
1075 	char *buf, *bp;
1076 	size_t len;
1077 
1078 	transflag++;
1079 	if (setjmp(urgcatch)) {
1080 		transflag = 0;
1081 		return;
1082 	}
1083 	switch (type) {
1084 
1085 	case TYPE_A:
1086 		while ((c = getc(instr)) != EOF) {
1087 			byte_count++;
1088 			if (c == '\n') {
1089 				if (ferror(outstr))
1090 					goto data_err;
1091 				(void) putc('\r', outstr);
1092 			}
1093 			(void) putc(c, outstr);
1094 		}
1095 		fflush(outstr);
1096 		transflag = 0;
1097 		if (ferror(instr))
1098 			goto file_err;
1099 		if (ferror(outstr))
1100 			goto data_err;
1101 		reply(226, "Transfer complete.");
1102 		return;
1103 
1104 	case TYPE_I:
1105 	case TYPE_L:
1106 		/*
1107 		 * isreg is only set if we are not doing restart and we
1108 		 * are sending a regular file
1109 		 */
1110 		netfd = fileno(outstr);
1111 		filefd = fileno(instr);
1112 
1113 		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1114 			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1115 				   (off_t)0);
1116 			if (!buf) {
1117 				syslog(LOG_WARNING, "mmap(%lu): %m",
1118 				       (unsigned long)filesize);
1119 				goto oldway;
1120 			}
1121 			bp = buf;
1122 			len = filesize;
1123 			do {
1124 				cnt = write(netfd, bp, len);
1125 				len -= cnt;
1126 				bp += cnt;
1127 				if (cnt > 0) byte_count += cnt;
1128 			} while(cnt > 0 && len > 0);
1129 
1130 			transflag = 0;
1131 			munmap(buf, (size_t)filesize);
1132 			if (cnt < 0)
1133 				goto data_err;
1134 			reply(226, "Transfer complete.");
1135 			return;
1136 		}
1137 
1138 oldway:
1139 		if ((buf = malloc((u_int)blksize)) == NULL) {
1140 			transflag = 0;
1141 			perror_reply(451, "Local resource failure: malloc");
1142 			return;
1143 		}
1144 
1145 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1146 		    write(netfd, buf, cnt) == cnt)
1147 			byte_count += cnt;
1148 		transflag = 0;
1149 		(void)free(buf);
1150 		if (cnt != 0) {
1151 			if (cnt < 0)
1152 				goto file_err;
1153 			goto data_err;
1154 		}
1155 		reply(226, "Transfer complete.");
1156 		return;
1157 	default:
1158 		transflag = 0;
1159 		reply(550, "Unimplemented TYPE %d in send_data", type);
1160 		return;
1161 	}
1162 
1163 data_err:
1164 	transflag = 0;
1165 	perror_reply(426, "Data connection");
1166 	return;
1167 
1168 file_err:
1169 	transflag = 0;
1170 	perror_reply(551, "Error on input file");
1171 }
1172 
1173 /*
1174  * Transfer data from peer to "outstr" using the appropriate encapulation of
1175  * the data subject to Mode, Structure, and Type.
1176  *
1177  * N.B.: Form isn't handled.
1178  */
1179 static int
1180 receive_data(instr, outstr)
1181 	FILE *instr, *outstr;
1182 {
1183 	int c;
1184 	int cnt, bare_lfs = 0;
1185 	char buf[BUFSIZ];
1186 
1187 	transflag++;
1188 	if (setjmp(urgcatch)) {
1189 		transflag = 0;
1190 		return (-1);
1191 	}
1192 	switch (type) {
1193 
1194 	case TYPE_I:
1195 	case TYPE_L:
1196 		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1197 			if (write(fileno(outstr), buf, cnt) != cnt)
1198 				goto file_err;
1199 			byte_count += cnt;
1200 		}
1201 		if (cnt < 0)
1202 			goto data_err;
1203 		transflag = 0;
1204 		return (0);
1205 
1206 	case TYPE_E:
1207 		reply(553, "TYPE E not implemented.");
1208 		transflag = 0;
1209 		return (-1);
1210 
1211 	case TYPE_A:
1212 		while ((c = getc(instr)) != EOF) {
1213 			byte_count++;
1214 			if (c == '\n')
1215 				bare_lfs++;
1216 			while (c == '\r') {
1217 				if (ferror(outstr))
1218 					goto data_err;
1219 				if ((c = getc(instr)) != '\n') {
1220 					(void) putc ('\r', outstr);
1221 					if (c == '\0' || c == EOF)
1222 						goto contin2;
1223 				}
1224 			}
1225 			(void) putc(c, outstr);
1226 	contin2:	;
1227 		}
1228 		fflush(outstr);
1229 		if (ferror(instr))
1230 			goto data_err;
1231 		if (ferror(outstr))
1232 			goto file_err;
1233 		transflag = 0;
1234 		if (bare_lfs) {
1235 			lreply(226,
1236 		"WARNING! %d bare linefeeds received in ASCII mode",
1237 			    bare_lfs);
1238 		(void)printf("   File may not have transferred correctly.\r\n");
1239 		}
1240 		return (0);
1241 	default:
1242 		reply(550, "Unimplemented TYPE %d in receive_data", type);
1243 		transflag = 0;
1244 		return (-1);
1245 	}
1246 
1247 data_err:
1248 	transflag = 0;
1249 	perror_reply(426, "Data Connection");
1250 	return (-1);
1251 
1252 file_err:
1253 	transflag = 0;
1254 	perror_reply(452, "Error writing file");
1255 	return (-1);
1256 }
1257 
1258 void
1259 statfilecmd(filename)
1260 	char *filename;
1261 {
1262 	FILE *fin;
1263 	int c;
1264 	char line[LINE_MAX];
1265 
1266 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1267 	fin = ftpd_popen(line, "r");
1268 	lreply(211, "status of %s:", filename);
1269 	while ((c = getc(fin)) != EOF) {
1270 		if (c == '\n') {
1271 			if (ferror(stdout)){
1272 				perror_reply(421, "control connection");
1273 				(void) ftpd_pclose(fin);
1274 				dologout(1);
1275 				/* NOTREACHED */
1276 			}
1277 			if (ferror(fin)) {
1278 				perror_reply(551, filename);
1279 				(void) ftpd_pclose(fin);
1280 				return;
1281 			}
1282 			(void) putc('\r', stdout);
1283 		}
1284 		(void) putc(c, stdout);
1285 	}
1286 	(void) ftpd_pclose(fin);
1287 	reply(211, "End of Status");
1288 }
1289 
1290 void
1291 statcmd()
1292 {
1293 	struct sockaddr_in *sin;
1294 	u_char *a, *p;
1295 
1296 	lreply(211, "%s FTP server status:", hostname, version);
1297 	printf("     %s\r\n", version);
1298 	printf("     Connected to %s", remotehost);
1299 	if (!isdigit(remotehost[0]))
1300 		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1301 	printf("\r\n");
1302 	if (logged_in) {
1303 		if (guest)
1304 			printf("     Logged in anonymously\r\n");
1305 		else
1306 			printf("     Logged in as %s\r\n", pw->pw_name);
1307 	} else if (askpasswd)
1308 		printf("     Waiting for password\r\n");
1309 	else
1310 		printf("     Waiting for user name\r\n");
1311 	printf("     TYPE: %s", typenames[type]);
1312 	if (type == TYPE_A || type == TYPE_E)
1313 		printf(", FORM: %s", formnames[form]);
1314 	if (type == TYPE_L)
1315 #if NBBY == 8
1316 		printf(" %d", NBBY);
1317 #else
1318 		printf(" %d", bytesize);	/* need definition! */
1319 #endif
1320 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1321 	    strunames[stru], modenames[mode]);
1322 	if (data != -1)
1323 		printf("     Data connection open\r\n");
1324 	else if (pdata != -1) {
1325 		printf("     in Passive mode");
1326 		sin = &pasv_addr;
1327 		goto printaddr;
1328 	} else if (usedefault == 0) {
1329 		printf("     PORT");
1330 		sin = &data_dest;
1331 printaddr:
1332 		a = (u_char *) &sin->sin_addr;
1333 		p = (u_char *) &sin->sin_port;
1334 #define UC(b) (((int) b) & 0xff)
1335 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1336 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1337 #undef UC
1338 	} else
1339 		printf("     No data connection\r\n");
1340 	reply(211, "End of status");
1341 }
1342 
1343 void
1344 fatal(s)
1345 	char *s;
1346 {
1347 
1348 	reply(451, "Error in server: %s\n", s);
1349 	reply(221, "Closing connection due to server error.");
1350 	dologout(0);
1351 	/* NOTREACHED */
1352 }
1353 
1354 void
1355 #if __STDC__
1356 reply(int n, const char *fmt, ...)
1357 #else
1358 reply(n, fmt, va_alist)
1359 	int n;
1360 	char *fmt;
1361         va_dcl
1362 #endif
1363 {
1364 	va_list ap;
1365 #if __STDC__
1366 	va_start(ap, fmt);
1367 #else
1368 	va_start(ap);
1369 #endif
1370 	(void)printf("%d ", n);
1371 	(void)vprintf(fmt, ap);
1372 	(void)printf("\r\n");
1373 	(void)fflush(stdout);
1374 	if (debug) {
1375 		syslog(LOG_DEBUG, "<--- %d ", n);
1376 		vsyslog(LOG_DEBUG, fmt, ap);
1377 	}
1378 }
1379 
1380 void
1381 #if __STDC__
1382 lreply(int n, const char *fmt, ...)
1383 #else
1384 lreply(n, fmt, va_alist)
1385 	int n;
1386 	char *fmt;
1387         va_dcl
1388 #endif
1389 {
1390 	va_list ap;
1391 #if __STDC__
1392 	va_start(ap, fmt);
1393 #else
1394 	va_start(ap);
1395 #endif
1396 	(void)printf("%d- ", n);
1397 	(void)vprintf(fmt, ap);
1398 	(void)printf("\r\n");
1399 	(void)fflush(stdout);
1400 	if (debug) {
1401 		syslog(LOG_DEBUG, "<--- %d- ", n);
1402 		vsyslog(LOG_DEBUG, fmt, ap);
1403 	}
1404 }
1405 
1406 static void
1407 ack(s)
1408 	char *s;
1409 {
1410 
1411 	reply(250, "%s command successful.", s);
1412 }
1413 
1414 void
1415 nack(s)
1416 	char *s;
1417 {
1418 
1419 	reply(502, "%s command not implemented.", s);
1420 }
1421 
1422 /* ARGSUSED */
1423 void
1424 yyerror(s)
1425 	char *s;
1426 {
1427 	char *cp;
1428 
1429 	if (cp = strchr(cbuf,'\n'))
1430 		*cp = '\0';
1431 	reply(500, "'%s': command not understood.", cbuf);
1432 }
1433 
1434 void
1435 delete(name)
1436 	char *name;
1437 {
1438 	struct stat st;
1439 
1440 	LOGCMD("delete", name);
1441 	if (stat(name, &st) < 0) {
1442 		perror_reply(550, name);
1443 		return;
1444 	}
1445 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1446 		if (rmdir(name) < 0) {
1447 			perror_reply(550, name);
1448 			return;
1449 		}
1450 		goto done;
1451 	}
1452 	if (unlink(name) < 0) {
1453 		perror_reply(550, name);
1454 		return;
1455 	}
1456 done:
1457 	ack("DELE");
1458 }
1459 
1460 void
1461 cwd(path)
1462 	char *path;
1463 {
1464 
1465 	if (chdir(path) < 0)
1466 		perror_reply(550, path);
1467 	else
1468 		ack("CWD");
1469 }
1470 
1471 void
1472 makedir(name)
1473 	char *name;
1474 {
1475 
1476 	LOGCMD("mkdir", name);
1477 	if (mkdir(name, 0777) < 0)
1478 		perror_reply(550, name);
1479 	else
1480 		reply(257, "MKD command successful.");
1481 }
1482 
1483 void
1484 removedir(name)
1485 	char *name;
1486 {
1487 
1488 	LOGCMD("rmdir", name);
1489 	if (rmdir(name) < 0)
1490 		perror_reply(550, name);
1491 	else
1492 		ack("RMD");
1493 }
1494 
1495 void
1496 pwd()
1497 {
1498 	char path[MAXPATHLEN + 1];
1499 
1500 	if (getwd(path) == (char *)NULL)
1501 		reply(550, "%s.", path);
1502 	else
1503 		reply(257, "\"%s\" is current directory.", path);
1504 }
1505 
1506 char *
1507 renamefrom(name)
1508 	char *name;
1509 {
1510 	struct stat st;
1511 
1512 	if (stat(name, &st) < 0) {
1513 		perror_reply(550, name);
1514 		return ((char *)0);
1515 	}
1516 	reply(350, "File exists, ready for destination name");
1517 	return (name);
1518 }
1519 
1520 void
1521 renamecmd(from, to)
1522 	char *from, *to;
1523 {
1524 
1525 	LOGCMD2("rename", from, to);
1526 	if (rename(from, to) < 0)
1527 		perror_reply(550, "rename");
1528 	else
1529 		ack("RNTO");
1530 }
1531 
1532 static void
1533 dolog(sin)
1534 	struct sockaddr_in *sin;
1535 {
1536 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1537 		sizeof(struct in_addr), AF_INET);
1538 
1539 	if (hp)
1540 		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
1541 	else
1542 		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1543 		    sizeof(remotehost));
1544 #ifdef SETPROCTITLE
1545 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1546 	setproctitle("%s", proctitle);
1547 #endif /* SETPROCTITLE */
1548 
1549 	if (logging)
1550 		syslog(LOG_INFO, "connection from %s", remotehost);
1551 }
1552 
1553 /*
1554  * Record logout in wtmp file
1555  * and exit with supplied status.
1556  */
1557 void
1558 dologout(status)
1559 	int status;
1560 {
1561 
1562 	if (logged_in) {
1563 		(void) seteuid((uid_t)0);
1564 		logwtmp(ttyline, "", "");
1565 	}
1566 	/* beware of flushing buffers after a SIGPIPE */
1567 	_exit(status);
1568 }
1569 
1570 static void
1571 myoob(signo)
1572 	int signo;
1573 {
1574 	char *cp;
1575 
1576 	/* only process if transfer occurring */
1577 	if (!transflag)
1578 		return;
1579 	cp = tmpline;
1580 	if (getline(cp, 7, stdin) == NULL) {
1581 		reply(221, "You could at least say goodbye.");
1582 		dologout(0);
1583 	}
1584 	upper(cp);
1585 	if (strcmp(cp, "ABOR\r\n") == 0) {
1586 		tmpline[0] = '\0';
1587 		reply(426, "Transfer aborted. Data connection closed.");
1588 		reply(226, "Abort successful");
1589 		longjmp(urgcatch, 1);
1590 	}
1591 	if (strcmp(cp, "STAT\r\n") == 0) {
1592 		if (file_size != (off_t) -1)
1593 			reply(213, "Status: %qd of %qd bytes transferred",
1594 			    byte_count, file_size);
1595 		else
1596 			reply(213, "Status: %qd bytes transferred", byte_count);
1597 	}
1598 }
1599 
1600 /*
1601  * Note: a response of 425 is not mentioned as a possible response to
1602  *	the PASV command in RFC959. However, it has been blessed as
1603  *	a legitimate response by Jon Postel in a telephone conversation
1604  *	with Rick Adams on 25 Jan 89.
1605  */
1606 void
1607 passive()
1608 {
1609 	int len;
1610 	u_short port;
1611 	char *p, *a;
1612 
1613 	if (pw == NULL) {
1614 		reply(530, "Please login with USER and PASS");
1615 		return;
1616 	}
1617 	pdata = socket(AF_INET, SOCK_STREAM, 0);
1618 	if (pdata < 0) {
1619 		perror_reply(425, "Can't open passive connection");
1620 		return;
1621 	}
1622 
1623 	if (restricted_data_ports) {
1624 		for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) {
1625 			pasv_addr = ctrl_addr;
1626 			pasv_addr.sin_port = htons(port);
1627 			(void) seteuid((uid_t)0);
1628 			if (bind(pdata, (struct sockaddr *)&pasv_addr,
1629 				 sizeof(pasv_addr)) < 0) {
1630 				(void) seteuid((uid_t)pw->pw_uid);
1631 				if (errno == EADDRINUSE)
1632 					continue;
1633 				else
1634 					goto pasv_error;
1635 			}
1636 			(void) seteuid((uid_t)pw->pw_uid);
1637 			break;
1638 		}
1639 		if (port > FTP_DATA_TOP)
1640 			goto pasv_error;
1641 	} else {
1642 		pasv_addr = ctrl_addr;
1643 		pasv_addr.sin_port = 0;
1644 		(void) seteuid((uid_t)0);
1645 		if (bind(pdata, (struct sockaddr *)&pasv_addr,
1646 			 sizeof(pasv_addr)) < 0) {
1647 			(void) seteuid((uid_t)pw->pw_uid);
1648 			goto pasv_error;
1649 		}
1650 		(void) seteuid((uid_t)pw->pw_uid);
1651 	}
1652 
1653 	len = sizeof(pasv_addr);
1654 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1655 		goto pasv_error;
1656 	if (listen(pdata, 1) < 0)
1657 		goto pasv_error;
1658 	a = (char *) &pasv_addr.sin_addr;
1659 	p = (char *) &pasv_addr.sin_port;
1660 
1661 #define UC(b) (((int) b) & 0xff)
1662 
1663 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1664 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1665 	return;
1666 
1667 pasv_error:
1668 	(void) close(pdata);
1669 	pdata = -1;
1670 	perror_reply(425, "Can't open passive connection");
1671 	return;
1672 }
1673 
1674 /*
1675  * Generate unique name for file with basename "local".
1676  * The file named "local" is already known to exist.
1677  * Generates failure reply on error.
1678  */
1679 static char *
1680 gunique(local)
1681 	char *local;
1682 {
1683 	static char new[MAXPATHLEN];
1684 	struct stat st;
1685 	int count;
1686 	char *cp;
1687 
1688 	cp = strrchr(local, '/');
1689 	if (cp)
1690 		*cp = '\0';
1691 	if (stat(cp ? local : ".", &st) < 0) {
1692 		perror_reply(553, cp ? local : ".");
1693 		return ((char *) 0);
1694 	}
1695 	if (cp)
1696 		*cp = '/';
1697 	(void) strcpy(new, local);
1698 	cp = new + strlen(new);
1699 	*cp++ = '.';
1700 	for (count = 1; count < 100; count++) {
1701 		(void)sprintf(cp, "%d", count);
1702 		if (stat(new, &st) < 0)
1703 			return (new);
1704 	}
1705 	reply(452, "Unique file name cannot be created.");
1706 	return (NULL);
1707 }
1708 
1709 /*
1710  * Format and send reply containing system error number.
1711  */
1712 void
1713 perror_reply(code, string)
1714 	int code;
1715 	char *string;
1716 {
1717 
1718 	reply(code, "%s: %s.", string, strerror(errno));
1719 }
1720 
1721 static char *onefile[] = {
1722 	"",
1723 	0
1724 };
1725 
1726 void
1727 send_file_list(whichf)
1728 	char *whichf;
1729 {
1730 	struct stat st;
1731 	DIR *dirp = NULL;
1732 	struct dirent *dir;
1733 	FILE *dout = NULL;
1734 	char **dirlist, *dirname;
1735 	int simple = 0;
1736 	int freeglob = 0;
1737 	glob_t gl;
1738 
1739 	if (strpbrk(whichf, "~{[*?") != NULL) {
1740 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1741 
1742 		memset(&gl, 0, sizeof(gl));
1743 		freeglob = 1;
1744 		if (glob(whichf, flags, 0, &gl)) {
1745 			reply(550, "not found");
1746 			goto out;
1747 		} else if (gl.gl_pathc == 0) {
1748 			errno = ENOENT;
1749 			perror_reply(550, whichf);
1750 			goto out;
1751 		}
1752 		dirlist = gl.gl_pathv;
1753 	} else {
1754 		onefile[0] = whichf;
1755 		dirlist = onefile;
1756 		simple = 1;
1757 	}
1758 
1759 	if (setjmp(urgcatch)) {
1760 		transflag = 0;
1761 		goto out;
1762 	}
1763 	while (dirname = *dirlist++) {
1764 		if (stat(dirname, &st) < 0) {
1765 			/*
1766 			 * If user typed "ls -l", etc, and the client
1767 			 * used NLST, do what the user meant.
1768 			 */
1769 			if (dirname[0] == '-' && *dirlist == NULL &&
1770 			    transflag == 0) {
1771 				retrieve("/bin/ls %s", dirname);
1772 				goto out;
1773 			}
1774 			perror_reply(550, whichf);
1775 			if (dout != NULL) {
1776 				(void) fclose(dout);
1777 				transflag = 0;
1778 				data = -1;
1779 				pdata = -1;
1780 			}
1781 			goto out;
1782 		}
1783 
1784 		if (S_ISREG(st.st_mode)) {
1785 			if (dout == NULL) {
1786 				dout = dataconn("file list", (off_t)-1, "w");
1787 				if (dout == NULL)
1788 					goto out;
1789 				transflag++;
1790 			}
1791 			fprintf(dout, "%s%s\n", dirname,
1792 				type == TYPE_A ? "\r" : "");
1793 			byte_count += strlen(dirname) + 1;
1794 			continue;
1795 		} else if (!S_ISDIR(st.st_mode))
1796 			continue;
1797 
1798 		if ((dirp = opendir(dirname)) == NULL)
1799 			continue;
1800 
1801 		while ((dir = readdir(dirp)) != NULL) {
1802 			char nbuf[MAXPATHLEN];
1803 
1804 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1805 				continue;
1806 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1807 			    dir->d_namlen == 2)
1808 				continue;
1809 
1810 			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
1811 
1812 			/*
1813 			 * We have to do a stat to insure it's
1814 			 * not a directory or special file.
1815 			 */
1816 			if (simple || (stat(nbuf, &st) == 0 &&
1817 			    S_ISREG(st.st_mode))) {
1818 				if (dout == NULL) {
1819 					dout = dataconn("file list", (off_t)-1,
1820 						"w");
1821 					if (dout == NULL)
1822 						goto out;
1823 					transflag++;
1824 				}
1825 				if (nbuf[0] == '.' && nbuf[1] == '/')
1826 					fprintf(dout, "%s%s\n", &nbuf[2],
1827 						type == TYPE_A ? "\r" : "");
1828 				else
1829 					fprintf(dout, "%s%s\n", nbuf,
1830 						type == TYPE_A ? "\r" : "");
1831 				byte_count += strlen(nbuf) + 1;
1832 			}
1833 		}
1834 		(void) closedir(dirp);
1835 	}
1836 
1837 	if (dout == NULL)
1838 		reply(550, "No files found.");
1839 	else if (ferror(dout) != 0)
1840 		perror_reply(550, "Data connection");
1841 	else
1842 		reply(226, "Transfer complete.");
1843 
1844 	transflag = 0;
1845 	if (dout != NULL)
1846 		(void) fclose(dout);
1847 	data = -1;
1848 	pdata = -1;
1849 out:
1850 	if (freeglob) {
1851 		freeglob = 0;
1852 		globfree(&gl);
1853 	}
1854 }
1855 
1856 void
1857 reapchild(signo)
1858 	int signo;
1859 {
1860 	while (wait3(NULL, WNOHANG, NULL) > 0);
1861 }
1862 
1863 #ifdef OLD_SETPROCTITLE
1864 /*
1865  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
1866  * Warning, since this is usually started from inetd.conf, it often doesn't
1867  * have much of an environment or arglist to overwrite.
1868  */
1869 void
1870 #if __STDC__
1871 setproctitle(const char *fmt, ...)
1872 #else
1873 setproctitle(fmt, va_alist)
1874 	char *fmt;
1875         va_dcl
1876 #endif
1877 {
1878 	int i;
1879 	va_list ap;
1880 	char *p, *bp, ch;
1881 	char buf[LINE_MAX];
1882 
1883 #if __STDC__
1884 	va_start(ap, fmt);
1885 #else
1886 	va_start(ap);
1887 #endif
1888 	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
1889 
1890 	/* make ps print our process name */
1891 	p = Argv[0];
1892 	*p++ = '-';
1893 
1894 	i = strlen(buf);
1895 	if (i > LastArgv - p - 2) {
1896 		i = LastArgv - p - 2;
1897 		buf[i] = '\0';
1898 	}
1899 	bp = buf;
1900 	while (ch = *bp++)
1901 		if (ch != '\n' && ch != '\r')
1902 			*p++ = ch;
1903 	while (p < LastArgv)
1904 		*p++ = ' ';
1905 }
1906 #endif /* OLD_SETPROCTITLE */
1907 
1908 #ifdef STATS
1909 logxfer(name, size, start)
1910 	char *name;
1911 	long size;
1912 	long start;
1913 {
1914 	char buf[1024];
1915 	char path[MAXPATHLEN + 1];
1916 	long now;
1917 
1918 	if (statfd >= 0 && getwd(path) != NULL) {
1919 		time(&now);
1920 		sprintf(buf, "%.20s!%s!%s!%s/%s!%ld!%ld\n",
1921 			ctime(&now)+4, ident, remotehost,
1922 			path, name, size, now - start + (now == start));
1923 		write(statfd, buf, strlen(buf));
1924 	}
1925 }
1926 
1927 char *
1928 copy(s)
1929 	char *s;
1930 {
1931 	char *p;
1932 
1933 	p = malloc((unsigned) strlen(s) + 1);
1934 	if (p == NULL)
1935 		fatal("Ran out of memory.");
1936 	(void) strcpy(p, s);
1937 	return (p);
1938 }
1939 #endif
1940