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