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