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