ftpd.c revision 1.126
1/*	$OpenBSD: ftpd.c,v 1.126 2002/05/26 09:32:07 deraadt Exp $	*/
2/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * 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. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 *    must display the following acknowledgement:
47 *	This product includes software developed by the University of
48 *	California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66#ifndef lint
67static char copyright[] =
68"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
69	The Regents of the University of California.  All rights reserved.\n";
70#endif /* not lint */
71
72#ifndef lint
73#if 0
74static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
75#else
76static char rcsid[] = "$OpenBSD: ftpd.c,v 1.126 2002/05/26 09:32:07 deraadt Exp $";
77#endif
78#endif /* not lint */
79
80/*
81 * FTP server.
82 */
83#include <sys/param.h>
84#include <sys/stat.h>
85#include <sys/ioctl.h>
86#include <sys/socket.h>
87#include <sys/wait.h>
88#include <sys/mman.h>
89
90#include <netinet/in.h>
91#include <netinet/in_systm.h>
92#include <netinet/ip.h>
93#include <netinet/tcp.h>
94
95#define	FTP_NAMES
96#include <arpa/ftp.h>
97#include <arpa/inet.h>
98#include <arpa/telnet.h>
99
100#include <bsd_auth.h>
101#include <ctype.h>
102#include <dirent.h>
103#include <err.h>
104#include <errno.h>
105#include <fcntl.h>
106#include <glob.h>
107#include <limits.h>
108#include <login_cap.h>
109#include <netdb.h>
110#include <pwd.h>
111#include <signal.h>
112#include <stdarg.h>
113#include <stdio.h>
114#include <stdlib.h>
115#include <string.h>
116#include <syslog.h>
117#include <time.h>
118#include <vis.h>
119#include <unistd.h>
120#include <util.h>
121#include <utmp.h>
122
123#if defined(TCPWRAPPERS)
124#include <tcpd.h>
125#endif	/* TCPWRAPPERS */
126
127#include "pathnames.h"
128#include "extern.h"
129
130static char version[] = "Version 6.5/OpenBSD";
131
132extern	off_t restart_point;
133extern	char cbuf[];
134
135union sockunion server_addr;
136union sockunion ctrl_addr;
137union sockunion data_source;
138union sockunion data_dest;
139union sockunion his_addr;
140union sockunion pasv_addr;
141
142sigset_t allsigs;
143
144int	daemon_mode = 0;
145int	data;
146int	logged_in;
147struct	passwd *pw;
148int	debug = 0;
149int	timeout = 900;    /* timeout after 15 minutes of inactivity */
150int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
151int	logging;
152int	high_data_ports = 0;
153int	anon_only = 0;
154int	multihome = 0;
155int	guest;
156int	stats;
157int	statfd = -1;
158int	portcheck = 1;
159int	dochroot;
160int	type;
161int	form;
162int	stru;			/* avoid C keyword */
163int	mode;
164int	doutmp = 0;		/* update utmp file */
165int	usedefault = 1;		/* for data transfers */
166int	pdata = -1;		/* for passive mode */
167int	family = AF_INET;
168volatile sig_atomic_t transflag;
169off_t	file_size;
170off_t	byte_count;
171#if !defined(CMASK) || CMASK == 0
172#undef CMASK
173#define CMASK 022
174#endif
175int	defumask = CMASK;		/* default umask value */
176int	umaskchange = 1;		/* allow user to change umask value. */
177char	tmpline[7];
178char	hostname[MAXHOSTNAMELEN];
179char	remotehost[MAXHOSTNAMELEN];
180char	dhostname[MAXHOSTNAMELEN];
181char	*guestpw;
182static char ttyline[20];
183char	*tty = ttyline;		/* for klogin */
184static struct utmp utmp;	/* for utmp */
185static	login_cap_t *lc;
186static	auth_session_t *as;
187static	volatile sig_atomic_t recvurg;
188
189#if defined(TCPWRAPPERS)
190int	allow_severity = LOG_INFO;
191int	deny_severity = LOG_NOTICE;
192#endif	/* TCPWRAPPERS */
193
194char	*ident = NULL;
195
196
197int epsvall = 0;
198
199/*
200 * Timeout intervals for retrying connections
201 * to hosts that don't accept PORT cmds.  This
202 * is a kludge, but given the problems with TCP...
203 */
204#define	SWAITMAX	90	/* wait at most 90 seconds */
205#define	SWAITINT	5	/* interval between retries */
206
207int	swaitmax = SWAITMAX;
208int	swaitint = SWAITINT;
209
210#ifdef HASSETPROCTITLE
211char	proctitle[BUFSIZ];	/* initial part of title */
212#endif /* HASSETPROCTITLE */
213
214#define LOGCMD(cmd, file) \
215	if (logging > 1) \
216	    syslog(LOG_INFO,"%s %s%s", cmd, \
217		*(file) == '/' ? "" : curdir(), file);
218#define LOGCMD2(cmd, file1, file2) \
219	 if (logging > 1) \
220	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
221		*(file1) == '/' ? "" : curdir(), file1, \
222		*(file2) == '/' ? "" : curdir(), file2);
223#define LOGBYTES(cmd, file, cnt) \
224	if (logging > 1) { \
225		if (cnt == (off_t)-1) \
226		    syslog(LOG_INFO,"%s %s%s", cmd, \
227			*(file) == '/' ? "" : curdir(), file); \
228		else \
229		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
230			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
231	}
232
233static void	 ack(char *);
234static void	 sigurg(int);
235static void	 myoob(void);
236static int	 checkuser(char *, char *);
237static FILE	*dataconn(char *, off_t, char *);
238static void	 dolog(struct sockaddr *);
239static char	*copy_dir(char *, struct passwd *);
240static char	*curdir(void);
241static void	 end_login(void);
242static FILE	*getdatasock(char *);
243static int	guniquefd(char *, char **);
244static void	 lostconn(int);
245static void	 sigquit(int);
246static int	 receive_data(FILE *, FILE *);
247static void	 replydirname(const char *, const char *);
248static int	 send_data(FILE *, FILE *, off_t, off_t, int);
249static struct passwd *
250		 sgetpwnam(char *);
251static void	 reapchild(int);
252static int	 check_host(struct sockaddr *);
253static void	 usage(void);
254
255void	 logxfer(char *, off_t, time_t);
256
257static char *
258curdir()
259{
260	static char path[MAXPATHLEN+1];	/* path + '/' */
261
262	if (getcwd(path, sizeof(path)-1) == NULL)
263		return ("");
264	if (path[1] != '\0')		/* special case for root dir. */
265		strcat(path, "/");
266	/* For guest account, skip / since it's chrooted */
267	return (guest ? path+1 : path);
268}
269
270char *argstr = "AdDhlMSt:T:u:UvP46";
271
272static void
273usage()
274{
275	syslog(LOG_ERR,
276	    "usage: ftpd [-AdDhlMPSU46] [-t timeout] [-T maxtimeout] [-u mask]");
277	exit(2);
278}
279
280int
281main(argc, argv, envp)
282	int argc;
283	char *argv[];
284	char **envp;
285{
286	int addrlen, ch, on = 1, tos;
287	char *cp, line[LINE_MAX];
288	FILE *fp;
289	struct hostent *hp;
290	struct sigaction sa;
291
292	tzset();		/* in case no timezone database in ~ftp */
293	sigfillset(&allsigs);	/* used to block signals while root */
294	sigemptyset(&sa.sa_mask);
295	sa.sa_flags = SA_RESTART;
296
297	while ((ch = getopt(argc, argv, argstr)) != -1) {
298		switch (ch) {
299		case 'A':
300			anon_only = 1;
301			break;
302
303		case 'd':
304		case 'v':		/* deprecated */
305			debug = 1;
306			break;
307
308		case 'D':
309			daemon_mode = 1;
310			break;
311
312		case 'P':
313			portcheck = 0;
314			break;
315
316		case 'h':
317			high_data_ports = 1;
318			break;
319
320		case 'l':
321			logging++;	/* > 1 == extra logging */
322			break;
323
324		case 'M':
325			multihome = 1;
326			break;
327
328		case 'S':
329			stats = 1;
330			break;
331
332		case 't':
333			timeout = atoi(optarg);
334			if (maxtimeout < timeout)
335				maxtimeout = timeout;
336			break;
337
338		case 'T':
339			maxtimeout = atoi(optarg);
340			if (timeout > maxtimeout)
341				timeout = maxtimeout;
342			break;
343
344		case 'u':
345		    {
346			long val = 0;
347			char *p;
348			umaskchange = 0;
349
350			val = strtol(optarg, &p, 8);
351			if (*p != '\0' || val < 0 || (val & ~ACCESSPERMS)) {
352				syslog(LOG_ERR,
353				    "ftpd: %s is a bad value for -u, aborting..",
354				    optarg);
355				exit(2);
356			} else
357				defumask = val;
358			break;
359		    }
360
361		case 'U':
362			doutmp = 1;
363			break;
364
365		case '4':
366			family = AF_INET;
367			break;
368
369		case '6':
370			family = AF_INET6;
371			break;
372
373		default:
374			usage();
375			break;
376		}
377	}
378
379	(void) freopen(_PATH_DEVNULL, "w", stderr);
380
381	/*
382	 * LOG_NDELAY sets up the logging connection immediately,
383	 * necessary for anonymous ftp's that chroot and can't do it later.
384	 */
385	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
386
387	if (daemon_mode) {
388		int ctl_sock, fd;
389		struct servent *sv;
390
391		/*
392		 * Detach from parent.
393		 */
394		if (daemon(1, 1) < 0) {
395			syslog(LOG_ERR, "failed to become a daemon");
396			exit(1);
397		}
398		sa.sa_handler = reapchild;
399		(void) sigaction(SIGCHLD, &sa, NULL);
400		/*
401		 * Get port number for ftp/tcp.
402		 */
403		sv = getservbyname("ftp", "tcp");
404		if (sv == NULL) {
405			syslog(LOG_ERR, "getservbyname for ftp failed");
406			exit(1);
407		}
408		/*
409		 * Open a socket, bind it to the FTP port, and start
410		 * listening.
411		 */
412		ctl_sock = socket(family, SOCK_STREAM, 0);
413		if (ctl_sock < 0) {
414			syslog(LOG_ERR, "control socket: %m");
415			exit(1);
416		}
417		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
418		    (char *)&on, sizeof(on)) < 0)
419			syslog(LOG_ERR, "control setsockopt: %m");
420		memset(&server_addr, 0, sizeof(server_addr));
421		server_addr.su_sin.sin_family = family;
422		switch (family) {
423		case AF_INET:
424			server_addr.su_len = sizeof(struct sockaddr_in);
425			server_addr.su_sin.sin_port = sv->s_port;
426			break;
427		case AF_INET6:
428			server_addr.su_len = sizeof(struct sockaddr_in6);
429			server_addr.su_sin6.sin6_port = sv->s_port;
430			break;
431		}
432		if (bind(ctl_sock, (struct sockaddr *)&server_addr,
433			 server_addr.su_len)) {
434			syslog(LOG_ERR, "control bind: %m");
435			exit(1);
436		}
437		if (listen(ctl_sock, 32) < 0) {
438			syslog(LOG_ERR, "control listen: %m");
439			exit(1);
440		}
441		/* Stash pid in pidfile */
442		if (pidfile(NULL))
443			syslog(LOG_ERR, "can't open pidfile: %m");
444		/*
445		 * Loop forever accepting connection requests and forking off
446		 * children to handle them.
447		 */
448		while (1) {
449			addrlen = sizeof(his_addr);
450			fd = accept(ctl_sock, (struct sockaddr *)&his_addr,
451				    &addrlen);
452			if (fork() == 0) {
453				/* child */
454				(void) dup2(fd, 0);
455				(void) dup2(fd, 1);
456				close(ctl_sock);
457				break;
458			}
459			close(fd);
460		}
461
462#if defined(TCPWRAPPERS)
463		/* ..in the child. */
464		if (!check_host((struct sockaddr *)&his_addr))
465			exit(1);
466#endif	/* TCPWRAPPERS */
467	} else {
468		addrlen = sizeof(his_addr);
469		if (getpeername(0, (struct sockaddr *)&his_addr,
470				&addrlen) < 0) {
471			/* syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); */
472			exit(1);
473		}
474	}
475
476	/* set this here so klogin can use it... */
477	(void)snprintf(ttyline, sizeof(ttyline), "ftp%ld", (long)getpid());
478
479	sa.sa_handler = SIG_DFL;
480	(void) sigaction(SIGCHLD, &sa, NULL);
481
482	sa.sa_handler = sigurg;
483	sa.sa_flags = 0;		/* don't restart syscalls for SIGURG */
484	(void) sigaction(SIGURG, &sa, NULL);
485
486	sigfillset(&sa.sa_mask);	/* block all signals in handler */
487	sa.sa_flags = SA_RESTART;
488	sa.sa_handler = sigquit;
489	(void) sigaction(SIGHUP, &sa, NULL);
490	(void) sigaction(SIGINT, &sa, NULL);
491	(void) sigaction(SIGQUIT, &sa, NULL);
492	(void) sigaction(SIGTERM, &sa, NULL);
493
494	sa.sa_handler = lostconn;
495	(void) sigaction(SIGPIPE, &sa, NULL);
496
497	addrlen = sizeof(ctrl_addr);
498	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
499		syslog(LOG_ERR, "getsockname: %m");
500		exit(1);
501	}
502	if (his_addr.su_family == AF_INET6
503	 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
504#if 1
505		/*
506		 * IPv4 control connection arrived to AF_INET6 socket.
507		 * I hate to do this, but this is the easiest solution.
508		 */
509		union sockunion tmp_addr;
510		const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
511
512		tmp_addr = his_addr;
513		memset(&his_addr, 0, sizeof(his_addr));
514		his_addr.su_sin.sin_family = AF_INET;
515		his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
516		memcpy(&his_addr.su_sin.sin_addr,
517		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
518		    sizeof(his_addr.su_sin.sin_addr));
519		his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
520
521		tmp_addr = ctrl_addr;
522		memset(&ctrl_addr, 0, sizeof(ctrl_addr));
523		ctrl_addr.su_sin.sin_family = AF_INET;
524		ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
525		memcpy(&ctrl_addr.su_sin.sin_addr,
526		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
527		    sizeof(ctrl_addr.su_sin.sin_addr));
528		ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
529#else
530		while (fgets(line, sizeof(line), fd) != NULL) {
531			if ((cp = strchr(line, '\n')) != NULL)
532				*cp = '\0';
533			lreply(530, "%s", line);
534		}
535		(void) fflush(stdout);
536		(void) fclose(fd);
537		reply(530,
538			"Connection from IPv4 mapped address is not supported.");
539		exit(0);
540#endif
541	}
542#ifdef IP_TOS
543	if (his_addr.su_family == AF_INET) {
544		tos = IPTOS_LOWDELAY;
545		if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
546		    sizeof(int)) < 0)
547			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
548	}
549#endif
550	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
551
552	/* Try to handle urgent data inline */
553#ifdef SO_OOBINLINE
554	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
555		syslog(LOG_ERR, "setsockopt: %m");
556#endif
557
558#ifdef	F_SETOWN
559	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
560		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
561#endif
562	dolog((struct sockaddr *)&his_addr);
563	/*
564	 * Set up default state
565	 */
566	data = -1;
567	type = TYPE_A;
568	form = FORM_N;
569	stru = STRU_F;
570	mode = MODE_S;
571	tmpline[0] = '\0';
572
573	/* If logins are disabled, print out the message. */
574	if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
575		while (fgets(line, sizeof(line), fp) != NULL) {
576			if ((cp = strchr(line, '\n')) != NULL)
577				*cp = '\0';
578			lreply(530, "%s", line);
579		}
580		(void) fflush(stdout);
581		(void) fclose(fp);
582		reply(530, "System not available.");
583		exit(0);
584	}
585	if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
586		while (fgets(line, sizeof(line), fp) != NULL) {
587			if ((cp = strchr(line, '\n')) != NULL)
588				*cp = '\0';
589			lreply(220, "%s", line);
590		}
591		(void) fflush(stdout);
592		(void) fclose(fp);
593		/* reply(220,) must follow */
594	}
595	(void) gethostname(hostname, sizeof(hostname));
596
597	/* Make sure hostname is fully qualified. */
598	hp = gethostbyname(hostname);
599	if (hp != NULL)
600		strlcpy(hostname, hp->h_name, sizeof(hostname));
601
602	if (multihome) {
603		getnameinfo((struct sockaddr *)&ctrl_addr, ctrl_addr.su_len,
604		    dhostname, sizeof(dhostname), NULL, 0, 0);
605	}
606
607	reply(220, "%s FTP server (%s) ready.",
608	    (multihome ? dhostname : hostname), version);
609	for (;;)
610		(void) yyparse();
611	/* NOTREACHED */
612}
613
614/*
615 * Signal handlers.
616 */
617
618static void
619lostconn(signo)
620	int signo;
621{
622	struct syslog_data sdata = SYSLOG_DATA_INIT;
623
624	if (debug)
625		syslog_r(LOG_DEBUG, &sdata, "lost connection");
626	dologout(1);
627}
628
629static void
630sigquit(signo)
631	int signo;
632{
633	struct syslog_data sdata = SYSLOG_DATA_INIT;
634
635	syslog_r(LOG_ERR, &sdata, "got signal %s", sys_signame[signo]);
636	dologout(1);
637}
638
639/*
640 * Save the result of a getpwnam.  Used for USER command, since
641 * the data returned must not be clobbered by any other command
642 * (e.g., globbing).
643 */
644static struct passwd *
645sgetpwnam(name)
646	char *name;
647{
648	static struct passwd *save;
649	struct passwd *pw;
650
651	if ((pw = getpwnam(name)) == NULL)
652		return (NULL);
653	if (save) {
654		memset(save->pw_passwd, 0, strlen(save->pw_passwd));
655		free(save);
656	}
657	save = pw_dup(pw);
658	if (save == NULL) {
659		perror_reply(421, "Local resource failure: malloc");
660		dologout(1);
661		/* NOTREACHED */
662	}
663	return (save);
664}
665
666static int login_attempts;	/* number of failed login attempts */
667static int askpasswd;		/* had user command, ask for passwd */
668static char curname[MAXLOGNAME];	/* current USER name */
669
670/*
671 * USER command.
672 * Sets global passwd pointer pw if named account exists and is acceptable;
673 * sets askpasswd if a PASS command is expected.  If logged in previously,
674 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
675 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
676 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
677 * requesting login privileges.  Disallow anyone who does not have a standard
678 * shell as returned by getusershell().  Disallow anyone mentioned in the file
679 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
680 */
681void
682user(name)
683	char *name;
684{
685	char *cp, *shell, *style, *host;
686	char *class = NULL;
687
688	if (logged_in) {
689		if (guest) {
690			reply(530, "Can't change user from guest login.");
691			return;
692		} else if (dochroot) {
693			reply(530, "Can't change user from chroot user.");
694			return;
695		}
696		end_login();
697	}
698
699	/* Close session from previous user if there was one. */
700	if (as) {
701		auth_close(as);
702		as = NULL;
703	}
704	if (lc) {
705		login_close(lc);
706		lc = NULL;
707	}
708
709	if ((style = strchr(name, ':')) != NULL)
710		*style++ = 0;
711
712	guest = 0;
713	host = multihome ? dhostname : hostname;
714	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
715		if (checkuser(_PATH_FTPUSERS, "ftp") ||
716		    checkuser(_PATH_FTPUSERS, "anonymous"))
717			reply(530, "User %s access denied.", name);
718		else if ((pw = sgetpwnam("ftp")) != NULL) {
719			guest = 1;
720			askpasswd = 1;
721			lc = login_getclass(pw->pw_class);
722			if ((as = auth_open()) == NULL ||
723			    auth_setpwd(as, pw) != 0 ||
724			    auth_setoption(as, "FTPD_HOST", host) < 0) {
725				if (as) {
726					auth_close(as);
727					as = NULL;
728				}
729				login_close(lc);
730				lc = NULL;
731				reply(421, "Local resource failure");
732				return;
733			}
734			reply(331,
735			"Guest login ok, send your email address as password.");
736		} else
737			reply(530, "User %s unknown.", name);
738		if (!askpasswd && logging)
739			syslog(LOG_NOTICE,
740			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
741		return;
742	}
743
744	shell = _PATH_BSHELL;
745	if ((pw = sgetpwnam(name))) {
746		class = pw->pw_class;
747		if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
748			shell = pw->pw_shell;
749		while ((cp = getusershell()) != NULL)
750			if (strcmp(cp, shell) == 0)
751				break;
752		shell = cp;
753		endusershell();
754	}
755
756	/* Get login class; if invalid style treat like unknown user. */
757	lc = login_getclass(class);
758	if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
759		login_close(lc);
760		lc = NULL;
761		pw = NULL;
762	}
763
764	/* Do pre-authentication setup. */
765	if (lc && ((as = auth_open()) == NULL ||
766	    (pw != NULL && auth_setpwd(as, pw) != 0) ||
767	    auth_setitem(as, AUTHV_STYLE, style) < 0 ||
768	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
769	    auth_setitem(as, AUTHV_CLASS, class) < 0 ||
770	    auth_setoption(as, "login", "yes") < 0 ||
771	    auth_setoption(as, "notickets", "yes") < 0 ||
772	    auth_setoption(as, "FTPD_HOST", host) < 0)) {
773		if (as) {
774			auth_close(as);
775			as = NULL;
776		}
777		login_close(lc);
778		lc = NULL;
779		reply(421, "Local resource failure");
780		return;
781	}
782	if (logging)
783		strlcpy(curname, name, sizeof(curname));
784
785	dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
786	    checkuser(_PATH_FTPCHROOT, name);
787	if (anon_only && !dochroot) {
788		reply(530, "Sorry, only anonymous ftp allowed.");
789		return;
790	}
791	if (pw) {
792		if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
793			reply(530, "User %s access denied.", name);
794			if (logging)
795				syslog(LOG_NOTICE,
796				    "FTP LOGIN REFUSED FROM %s, %s",
797				    remotehost, name);
798			pw = NULL;
799			return;
800		}
801	}
802
803	if (as != NULL && (cp = auth_challenge(as)) != NULL)
804		reply(331, cp);
805	else
806		reply(331, "Password required for %s.", name);
807
808	askpasswd = 1;
809	/*
810	 * Delay before reading passwd after first failed
811	 * attempt to slow down passwd-guessing programs.
812	 */
813	if (login_attempts)
814		sleep((unsigned) login_attempts);
815}
816
817/*
818 * Check if a user is in the file "fname"
819 */
820static int
821checkuser(fname, name)
822	char *fname;
823	char *name;
824{
825	FILE *fp;
826	int found = 0;
827	char *p, line[BUFSIZ];
828
829	if ((fp = fopen(fname, "r")) != NULL) {
830		while (fgets(line, sizeof(line), fp) != NULL)
831			if ((p = strchr(line, '\n')) != NULL) {
832				*p = '\0';
833				if (line[0] == '#')
834					continue;
835				if (strcmp(line, name) == 0) {
836					found = 1;
837					break;
838				}
839			}
840		(void) fclose(fp);
841	}
842	return (found);
843}
844
845/*
846 * Terminate login as previous user, if any, resetting state;
847 * used when USER command is given or login fails.
848 */
849static void
850end_login()
851{
852
853	sigprocmask (SIG_BLOCK, &allsigs, NULL);
854	(void) seteuid((uid_t)0);
855	if (logged_in) {
856		ftpdlogwtmp(ttyline, "", "");
857		if (doutmp)
858			logout(utmp.ut_line);
859	}
860	pw = NULL;
861	/* umask is restored in ftpcmd.y */
862	setusercontext(NULL, getpwuid(0), (uid_t)0,
863	    LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
864	logged_in = 0;
865	guest = 0;
866	dochroot = 0;
867}
868
869void
870pass(passwd)
871	char *passwd;
872{
873	int authok, flags;
874	FILE *fp;
875	static char homedir[MAXPATHLEN];
876	char *motd, *dir, rootdir[MAXPATHLEN];
877
878	if (logged_in || askpasswd == 0) {
879		reply(503, "Login with USER first.");
880		return;
881	}
882	askpasswd = 0;
883	if (!guest) {		/* "ftp" is only account allowed no password */
884		authok = 0;
885		if (pw == NULL || pw->pw_passwd[0] == '\0') {
886			useconds_t us;
887
888			/* Sleep between 1 and 3 seconds to emulate a crypt. */
889			us = arc4random() % 3000000;
890			usleep(us);
891			if (as != NULL) {
892				auth_close(as);
893				as = NULL;
894			}
895		} else {
896			authok = auth_userresponse(as, passwd, 0);
897			as = NULL;
898		}
899		if (authok == 0) {
900			reply(530, "Login incorrect.");
901			if (logging)
902				syslog(LOG_NOTICE,
903				    "FTP LOGIN FAILED FROM %s, %s",
904				    remotehost, curname);
905			pw = NULL;
906			if (login_attempts++ >= 5) {
907				syslog(LOG_NOTICE,
908				    "repeated login failures from %s",
909				    remotehost);
910				exit(0);
911			}
912			return;
913		}
914	} else if (lc != NULL) {
915		/* Save anonymous' password. */
916		if (guestpw != NULL)
917			free(guestpw);
918		guestpw = strdup(passwd);
919		if (guestpw == NULL)
920			fatal("Out of memory.");
921
922		authok = auth_approval(as, lc, pw->pw_name, "ftp");
923		auth_close(as);
924		as = NULL;
925		if (authok == 0) {
926			syslog(LOG_INFO|LOG_AUTH,
927			    "FTP LOGIN FAILED (HOST) as %s: approval failure.",
928			    pw->pw_name);
929			reply(530, "Approval failure.");
930			exit(0);
931		}
932	} else {
933		syslog(LOG_INFO|LOG_AUTH,
934		    "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
935		    pw->pw_class, pw->pw_name);
936		reply(530, "Permission denied.");
937		exit(0);
938	}
939	login_attempts = 0;		/* this time successful */
940	if (setegid((gid_t)pw->pw_gid) < 0) {
941		reply(550, "Can't set gid.");
942		return;
943	}
944	/* set umask via setusercontext() unless -u flag was given. */
945	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
946	if (umaskchange)
947		flags |= LOGIN_SETUMASK;
948	else
949		(void) umask(defumask);
950	setusercontext(lc, pw, (uid_t)0, flags);
951
952	/* open wtmp before chroot */
953	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
954
955	/* open utmp before chroot */
956	if (doutmp) {
957		memset((void *)&utmp, 0, sizeof(utmp));
958		(void)time(&utmp.ut_time);
959		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
960		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
961		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
962		login(&utmp);
963	}
964
965	/* open stats file before chroot */
966	if (guest && (stats == 1) && (statfd < 0))
967		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
968			stats = 0;
969
970	logged_in = 1;
971
972	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
973		char *newdir;
974
975		newdir = copy_dir(dir, pw);
976		if (newdir == NULL) {
977			perror_reply(421, "Local resource failure: malloc");
978			dologout(1);
979			/* NOTREACHED */
980		}
981		free(dir);
982		free(pw->pw_dir);
983		pw->pw_dir = newdir;
984	}
985
986	/* make sure pw->pw_dir is big enough to hold "/" */
987	if (strlen(pw->pw_dir) < 1) {
988		char *newdir;
989
990		newdir = malloc(2);
991		if (newdir == NULL) {
992			perror_reply(421, "Local resource failure: malloc");
993			dologout(1);
994			/* NOTREACHED */
995		}
996		strlcpy(newdir, pw->pw_dir, 2);
997		free(pw->pw_dir);
998		pw->pw_dir = newdir;
999	}
1000
1001	if (guest || dochroot) {
1002		if (multihome && guest) {
1003			struct stat ts;
1004
1005			/* Compute root directory. */
1006			snprintf(rootdir, sizeof(rootdir), "%s/%s",
1007				  pw->pw_dir, dhostname);
1008			if (stat(rootdir, &ts) < 0) {
1009				snprintf(rootdir, sizeof(rootdir), "%s/%s",
1010					  pw->pw_dir, hostname);
1011			}
1012		} else
1013			strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1014	}
1015	if (guest) {
1016		/*
1017		 * We MUST do a chdir() after the chroot. Otherwise
1018		 * the old current directory will be accessible as "."
1019		 * outside the new root!
1020		 */
1021		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1022			reply(550, "Can't set guest privileges.");
1023			goto bad;
1024		}
1025		strcpy(pw->pw_dir, "/");
1026		if (setenv("HOME", "/", 1) == -1) {
1027			reply(550, "Can't setup environment.");
1028			goto bad;
1029		}
1030	} else if (dochroot) {
1031		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1032			reply(550, "Can't change root.");
1033			goto bad;
1034		}
1035		strcpy(pw->pw_dir, "/");
1036		if (setenv("HOME", "/", 1) == -1) {
1037			reply(550, "Can't setup environment.");
1038			goto bad;
1039		}
1040	} else if (chdir(pw->pw_dir) < 0) {
1041		if (chdir("/") < 0) {
1042			reply(530, "User %s: can't change directory to %s.",
1043			    pw->pw_name, pw->pw_dir);
1044			goto bad;
1045		} else
1046			lreply(230, "No directory! Logging in with home=/");
1047	}
1048	if (seteuid((uid_t)pw->pw_uid) < 0) {
1049		reply(550, "Can't set uid.");
1050		goto bad;
1051	}
1052	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1053
1054	/*
1055	 * Set home directory so that use of ~ (tilde) works correctly.
1056	 */
1057	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1058		if (setenv("HOME", homedir, 1) == -1) {
1059			reply(550, "Can't setup environment.");
1060			goto bad;
1061		}
1062	}
1063
1064	/*
1065	 * Display a login message, if it exists.
1066	 * N.B. reply(230,) must follow the message.
1067	 */
1068	motd = login_getcapstr(lc, "welcome", NULL, NULL);
1069	if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1070		char *cp, line[LINE_MAX];
1071
1072		while (fgets(line, sizeof(line), fp) != NULL) {
1073			if ((cp = strchr(line, '\n')) != NULL)
1074				*cp = '\0';
1075			lreply(230, "%s", line);
1076		}
1077		(void) fflush(stdout);
1078		(void) fclose(fp);
1079	}
1080	if (motd != NULL)
1081		free(motd);
1082	if (guest) {
1083		if (ident != NULL)
1084			free(ident);
1085		ident = strdup(passwd);
1086		if (ident == NULL)
1087			fatal("Ran out of memory.");
1088		reply(230, "Guest login ok, access restrictions apply.");
1089#ifdef HASSETPROCTITLE
1090		snprintf(proctitle, sizeof(proctitle),
1091		    "%s: anonymous/%.*s", remotehost,
1092		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1093		    sizeof(": anonymous/")), passwd);
1094		setproctitle("%s", proctitle);
1095#endif /* HASSETPROCTITLE */
1096		if (logging)
1097			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1098			    remotehost, passwd);
1099	} else {
1100		reply(230, "User %s logged in.", pw->pw_name);
1101#ifdef HASSETPROCTITLE
1102		snprintf(proctitle, sizeof(proctitle),
1103		    "%s: %s", remotehost, pw->pw_name);
1104		setproctitle("%s", proctitle);
1105#endif /* HASSETPROCTITLE */
1106		if (logging)
1107			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1108			    remotehost, pw->pw_name);
1109	}
1110	login_close(lc);
1111	lc = NULL;
1112	return;
1113bad:
1114	/* Forget all about it... */
1115	login_close(lc);
1116	lc = NULL;
1117	end_login();
1118}
1119
1120void
1121retrieve(cmd, name)
1122	char *cmd, *name;
1123{
1124	FILE *fin, *dout;
1125	struct stat st;
1126	int (*closefunc)(FILE *);
1127	time_t start;
1128
1129	if (cmd == 0) {
1130		fin = fopen(name, "r"), closefunc = fclose;
1131		st.st_size = 0;
1132	} else {
1133		char line[BUFSIZ];
1134
1135		(void) snprintf(line, sizeof(line), cmd, name);
1136		name = line;
1137		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1138		st.st_size = -1;
1139		st.st_blksize = BUFSIZ;
1140	}
1141	if (fin == NULL) {
1142		if (errno != 0) {
1143			perror_reply(550, name);
1144			if (cmd == 0) {
1145				LOGCMD("get", name);
1146			}
1147		}
1148		return;
1149	}
1150	byte_count = -1;
1151	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1152		reply(550, "%s: not a plain file.", name);
1153		goto done;
1154	}
1155	if (restart_point) {
1156		if (type == TYPE_A) {
1157			off_t i, n;
1158			int c;
1159
1160			n = restart_point;
1161			i = 0;
1162			while (i++ < n) {
1163				if ((c=getc(fin)) == EOF) {
1164					perror_reply(550, name);
1165					goto done;
1166				}
1167				if (c == '\n')
1168					i++;
1169			}
1170		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1171			perror_reply(550, name);
1172			goto done;
1173		}
1174	}
1175	dout = dataconn(name, st.st_size, "w");
1176	if (dout == NULL)
1177		goto done;
1178	time(&start);
1179	send_data(fin, dout, st.st_blksize, st.st_size,
1180		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1181	if ((cmd == 0) && stats)
1182		logxfer(name, byte_count, start);
1183	(void) fclose(dout);
1184	data = -1;
1185done:
1186	if (pdata >= 0)
1187		(void) close(pdata);
1188	pdata = -1;
1189	if (cmd == 0)
1190		LOGBYTES("get", name, byte_count);
1191	(*closefunc)(fin);
1192}
1193
1194void
1195store(name, mode, unique)
1196	char *name, *mode;
1197	int unique;
1198{
1199	FILE *fout, *din;
1200	int (*closefunc)(FILE *);
1201	struct stat st;
1202	int fd;
1203
1204	if (restart_point && *mode != 'a')
1205		mode = "r+";
1206
1207	if (unique && stat(name, &st) == 0) {
1208		char *nam;
1209
1210		fd = guniquefd(name, &nam);
1211		if (fd == -1) {
1212			LOGCMD(*mode == 'w' ? "put" : "append", name);
1213			return;
1214		}
1215		name = nam;
1216		fout = fdopen(fd, mode);
1217	} else
1218		fout = fopen(name, mode);
1219
1220	closefunc = fclose;
1221	if (fout == NULL) {
1222		perror_reply(553, name);
1223		LOGCMD(*mode == 'w' ? "put" : "append", name);
1224		return;
1225	}
1226	byte_count = -1;
1227	if (restart_point) {
1228		if (type == TYPE_A) {
1229			off_t i, n;
1230			int c;
1231
1232			n = restart_point;
1233			i = 0;
1234			while (i++ < n) {
1235				if ((c=getc(fout)) == EOF) {
1236					perror_reply(550, name);
1237					goto done;
1238				}
1239				if (c == '\n')
1240					i++;
1241			}
1242			/*
1243			 * We must do this seek to "current" position
1244			 * because we are changing from reading to
1245			 * writing.
1246			 */
1247			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1248				perror_reply(550, name);
1249				goto done;
1250			}
1251		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1252			perror_reply(550, name);
1253			goto done;
1254		}
1255	}
1256	din = dataconn(name, (off_t)-1, "r");
1257	if (din == NULL)
1258		goto done;
1259	if (receive_data(din, fout) == 0) {
1260		if (unique)
1261			reply(226, "Transfer complete (unique file name:%s).",
1262			    name);
1263		else
1264			reply(226, "Transfer complete.");
1265	}
1266	(void) fclose(din);
1267	data = -1;
1268	pdata = -1;
1269done:
1270	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1271	(*closefunc)(fout);
1272}
1273
1274static FILE *
1275getdatasock(mode)
1276	char *mode;
1277{
1278	int on = 1, s, t, tries;
1279
1280	if (data >= 0)
1281		return (fdopen(data, mode));
1282	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1283	(void) seteuid((uid_t)0);
1284	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1285	if (s < 0)
1286		goto bad;
1287	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1288	    (char *) &on, sizeof(on)) < 0)
1289		goto bad;
1290	/* anchor socket to avoid multi-homing problems */
1291	data_source = ctrl_addr;
1292	data_source.su_port = htons(20); /* ftp-data port */
1293	for (tries = 1; ; tries++) {
1294		if (bind(s, (struct sockaddr *)&data_source,
1295		    data_source.su_len) >= 0)
1296			break;
1297		if (errno != EADDRINUSE || tries > 10)
1298			goto bad;
1299		sleep(tries);
1300	}
1301	(void) seteuid((uid_t)pw->pw_uid);
1302	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1303
1304#ifdef IP_TOS
1305	if (ctrl_addr.su_family == AF_INET) {
1306		on = IPTOS_THROUGHPUT;
1307		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1308		    sizeof(int)) < 0)
1309			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1310	}
1311#endif
1312#ifdef TCP_NOPUSH
1313	/*
1314	 * Turn off push flag to keep sender TCP from sending short packets
1315	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1316	 * to set the send buffer size as well, but that may not be desirable
1317	 * in heavy-load situations.
1318	 */
1319	on = 1;
1320	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof(on)) < 0)
1321		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1322#endif
1323#ifdef SO_SNDBUF
1324	on = 65536;
1325	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof(on)) < 0)
1326		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1327#endif
1328
1329	return (fdopen(s, mode));
1330bad:
1331	/* Return the real value of errno (close may change it) */
1332	t = errno;
1333	(void) seteuid((uid_t)pw->pw_uid);
1334	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1335	(void) close(s);
1336	errno = t;
1337	return (NULL);
1338}
1339
1340static FILE *
1341dataconn(name, size, mode)
1342	char *name;
1343	off_t size;
1344	char *mode;
1345{
1346	char sizebuf[32];
1347	FILE *file;
1348	int retry = 0;
1349	in_port_t *p;
1350	char *fa, *ha;
1351	int alen;
1352
1353	file_size = size;
1354	byte_count = 0;
1355	if (size != (off_t) -1) {
1356		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1357				size);
1358	} else
1359		sizebuf[0] = '\0';
1360	if (pdata >= 0) {
1361		union sockunion from;
1362		int s, fromlen = sizeof(from);
1363
1364		signal (SIGALRM, toolong);
1365		(void) alarm ((unsigned) timeout);
1366		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1367		(void) alarm (0);
1368		if (s < 0) {
1369			reply(425, "Can't open data connection.");
1370			(void) close(pdata);
1371			pdata = -1;
1372			return (NULL);
1373		}
1374		switch (from.su_family) {
1375		case AF_INET:
1376			p = (in_port_t *)&from.su_sin.sin_port;
1377			fa = (u_char *)&from.su_sin.sin_addr;
1378			ha = (u_char *)&his_addr.su_sin.sin_addr;
1379			alen = sizeof(struct in_addr);
1380			break;
1381		case AF_INET6:
1382			p = (in_port_t *)&from.su_sin6.sin6_port;
1383			fa = (u_char *)&from.su_sin6.sin6_addr;
1384			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1385			alen = sizeof(struct in6_addr);
1386			break;
1387		default:
1388			perror_reply(425, "Can't build data connection");
1389			(void) close(pdata);
1390			(void) close(s);
1391			pdata = -1;
1392			return (NULL);
1393		}
1394		if (from.su_family != his_addr.su_family ||
1395		    ntohs(*p) < IPPORT_RESERVED) {
1396			perror_reply(425, "Can't build data connection");
1397			(void) close(pdata);
1398			(void) close(s);
1399			pdata = -1;
1400			return (NULL);
1401		}
1402		if (portcheck && memcmp(fa, ha, alen) != 0) {
1403			perror_reply(435, "Can't build data connection");
1404			(void) close(pdata);
1405			(void) close(s);
1406			pdata = -1;
1407			return (NULL);
1408		}
1409		(void) close(pdata);
1410		pdata = s;
1411		reply(150, "Opening %s mode data connection for '%s'%s.",
1412		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1413		return (fdopen(pdata, mode));
1414	}
1415	if (data >= 0) {
1416		reply(125, "Using existing data connection for '%s'%s.",
1417		    name, sizebuf);
1418		usedefault = 1;
1419		return (fdopen(data, mode));
1420	}
1421	if (usedefault)
1422		data_dest = his_addr;
1423	usedefault = 1;
1424	file = getdatasock(mode);
1425	if (file == NULL) {
1426		char hbuf[MAXHOSTNAMELEN], pbuf[10];
1427
1428		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1429		    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1430		    NI_NUMERICHOST | NI_NUMERICSERV);
1431		reply(425, "Can't create data socket (%s,%s): %s.",
1432		    hbuf, pbuf, strerror(errno));
1433		return (NULL);
1434	}
1435	data = fileno(file);
1436
1437	/*
1438	 * attempt to connect to reserved port on client machine;
1439	 * this looks like an attack
1440	 */
1441	switch (data_dest.su_family) {
1442	case AF_INET:
1443		p = (in_port_t *)&data_dest.su_sin.sin_port;
1444		fa = (u_char *)&data_dest.su_sin.sin_addr;
1445		ha = (u_char *)&his_addr.su_sin.sin_addr;
1446		alen = sizeof(struct in_addr);
1447		break;
1448	case AF_INET6:
1449		p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1450		fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1451		ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1452		alen = sizeof(struct in6_addr);
1453		break;
1454	default:
1455		perror_reply(425, "Can't build data connection");
1456		(void) fclose(file);
1457		pdata = -1;
1458		return (NULL);
1459	}
1460	if (data_dest.su_family != his_addr.su_family ||
1461	    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) {	/* XXX */
1462		perror_reply(425, "Can't build data connection");
1463		(void) fclose(file);
1464		data = -1;
1465		return NULL;
1466	}
1467	if (portcheck && memcmp(fa, ha, alen) != 0) {
1468		perror_reply(435, "Can't build data connection");
1469		(void) fclose(file);
1470		data = -1;
1471		return NULL;
1472	}
1473	while (connect(data, (struct sockaddr *)&data_dest,
1474	    data_dest.su_len) < 0) {
1475		if (errno == EADDRINUSE && retry < swaitmax) {
1476			sleep((unsigned) swaitint);
1477			retry += swaitint;
1478			continue;
1479		}
1480		perror_reply(425, "Can't build data connection");
1481		(void) fclose(file);
1482		data = -1;
1483		return (NULL);
1484	}
1485	reply(150, "Opening %s mode data connection for '%s'%s.",
1486	    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1487	return (file);
1488}
1489
1490/*
1491 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1492 * encapsulation of the data subject to Mode, Structure, and Type.
1493 *
1494 * NB: Form isn't handled.
1495 */
1496static int
1497send_data(instr, outstr, blksize, filesize, isreg)
1498	FILE *instr, *outstr;
1499	off_t blksize;
1500	off_t filesize;
1501	int isreg;
1502{
1503	int c, cnt, filefd, netfd;
1504	char *buf, *bp;
1505	size_t len;
1506
1507	transflag++;
1508	switch (type) {
1509
1510	case TYPE_A:
1511		while ((c = getc(instr)) != EOF) {
1512			if (recvurg)
1513				goto got_oob;
1514			byte_count++;
1515			if (c == '\n') {
1516				if (ferror(outstr))
1517					goto data_err;
1518				(void) putc('\r', outstr);
1519			}
1520			(void) putc(c, outstr);
1521		}
1522		fflush(outstr);
1523		transflag = 0;
1524		if (ferror(instr))
1525			goto file_err;
1526		if (ferror(outstr))
1527			goto data_err;
1528		reply(226, "Transfer complete.");
1529		return(0);
1530
1531	case TYPE_I:
1532	case TYPE_L:
1533		/*
1534		 * isreg is only set if we are not doing restart and we
1535		 * are sending a regular file
1536		 */
1537		netfd = fileno(outstr);
1538		filefd = fileno(instr);
1539
1540		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1541			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1542				   (off_t)0);
1543			if (buf == MAP_FAILED) {
1544				syslog(LOG_WARNING, "mmap(%lu): %m",
1545				    (unsigned long)filesize);
1546				goto oldway;
1547			}
1548			bp = buf;
1549			len = filesize;
1550			do {
1551				cnt = write(netfd, bp, len);
1552				if (recvurg) {
1553					munmap(buf, (size_t)filesize);
1554					goto got_oob;
1555				}
1556				len -= cnt;
1557				bp += cnt;
1558				if (cnt > 0) byte_count += cnt;
1559			} while(cnt > 0 && len > 0);
1560
1561			transflag = 0;
1562			munmap(buf, (size_t)filesize);
1563			if (cnt < 0)
1564				goto data_err;
1565			reply(226, "Transfer complete.");
1566			return(0);
1567		}
1568
1569oldway:
1570		if ((buf = malloc((u_int)blksize)) == NULL) {
1571			transflag = 0;
1572			perror_reply(451, "Local resource failure: malloc");
1573			return(-1);
1574		}
1575
1576		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1577		    write(netfd, buf, cnt) == cnt)
1578			byte_count += cnt;
1579		transflag = 0;
1580		(void)free(buf);
1581		if (cnt != 0) {
1582			if (cnt < 0)
1583				goto file_err;
1584			goto data_err;
1585		}
1586		reply(226, "Transfer complete.");
1587		return(0);
1588	default:
1589		transflag = 0;
1590		reply(550, "Unimplemented TYPE %d in send_data", type);
1591		return(-1);
1592	}
1593
1594data_err:
1595	transflag = 0;
1596	perror_reply(426, "Data connection");
1597	return(-1);
1598
1599file_err:
1600	transflag = 0;
1601	perror_reply(551, "Error on input file");
1602	return(-1);
1603
1604got_oob:
1605	myoob();
1606	recvurg = 0;
1607	transflag = 0;
1608	return(-1);
1609}
1610
1611/*
1612 * Transfer data from peer to "outstr" using the appropriate encapulation of
1613 * the data subject to Mode, Structure, and Type.
1614 *
1615 * N.B.: Form isn't handled.
1616 */
1617static int
1618receive_data(instr, outstr)
1619	FILE *instr, *outstr;
1620{
1621	int c;
1622	int cnt;
1623	char buf[BUFSIZ];
1624	struct sigaction sa;
1625	volatile int bare_lfs = 0;
1626
1627	transflag++;
1628	switch (type) {
1629
1630	case TYPE_I:
1631	case TYPE_L:
1632		sigfillset(&sa.sa_mask);
1633		sa.sa_flags = SA_RESTART;
1634		sigaction(SIGALRM, &sa, NULL);
1635
1636		do {
1637			(void) alarm ((unsigned) timeout);
1638			cnt = read(fileno(instr), buf, sizeof(buf));
1639			(void) alarm (0);
1640			if (recvurg)
1641				goto got_oob;
1642
1643			if (cnt > 0) {
1644				if (write(fileno(outstr), buf, cnt) != cnt)
1645					goto file_err;
1646				byte_count += cnt;
1647			}
1648		} while (cnt > 0);
1649		if (cnt < 0)
1650			goto data_err;
1651		transflag = 0;
1652		return (0);
1653
1654	case TYPE_E:
1655		reply(553, "TYPE E not implemented.");
1656		transflag = 0;
1657		return (-1);
1658
1659	case TYPE_A:
1660		while ((c = getc(instr)) != EOF) {
1661			if (recvurg)
1662				goto got_oob;
1663			byte_count++;
1664			if (c == '\n')
1665				bare_lfs++;
1666			while (c == '\r') {
1667				if (ferror(outstr))
1668					goto data_err;
1669				if ((c = getc(instr)) != '\n') {
1670					(void) putc ('\r', outstr);
1671					if (c == '\0' || c == EOF)
1672						goto contin2;
1673				}
1674			}
1675			(void) putc(c, outstr);
1676	contin2:	;
1677		}
1678		fflush(outstr);
1679		if (ferror(instr))
1680			goto data_err;
1681		if (ferror(outstr))
1682			goto file_err;
1683		transflag = 0;
1684		if (bare_lfs) {
1685			lreply(226,
1686			    "WARNING! %d bare linefeeds received in ASCII mode",
1687			    bare_lfs);
1688			printf("   File may not have transferred correctly.\r\n");
1689		}
1690		return (0);
1691	default:
1692		reply(550, "Unimplemented TYPE %d in receive_data", type);
1693		transflag = 0;
1694		return (-1);
1695	}
1696
1697data_err:
1698	transflag = 0;
1699	perror_reply(426, "Data Connection");
1700	return (-1);
1701
1702file_err:
1703	transflag = 0;
1704	perror_reply(452, "Error writing file");
1705	return (-1);
1706
1707got_oob:
1708	myoob();
1709	recvurg = 0;
1710	transflag = 0;
1711	return (-1);
1712}
1713
1714void
1715statfilecmd(filename)
1716	char *filename;
1717{
1718	FILE *fin;
1719	int c;
1720	int atstart;
1721	char line[LINE_MAX];
1722
1723	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1724	fin = ftpd_popen(line, "r");
1725	lreply(211, "status of %s:", filename);
1726	atstart = 1;
1727	while ((c = getc(fin)) != EOF) {
1728		if (c == '\n') {
1729			if (ferror(stdout)){
1730				perror_reply(421, "control connection");
1731				(void) ftpd_pclose(fin);
1732				dologout(1);
1733				/* NOTREACHED */
1734			}
1735			if (ferror(fin)) {
1736				perror_reply(551, filename);
1737				(void) ftpd_pclose(fin);
1738				return;
1739			}
1740			(void) putc('\r', stdout);
1741		}
1742		if (atstart && isdigit(c))
1743			(void) putc(' ', stdout);
1744		(void) putc(c, stdout);
1745		atstart = (c == '\n');
1746	}
1747	(void) ftpd_pclose(fin);
1748	reply(211, "End of Status");
1749}
1750
1751void
1752statcmd()
1753{
1754	union sockunion *su;
1755	u_char *a, *p;
1756	char hbuf[MAXHOSTNAMELEN];
1757	int ispassive;
1758
1759	lreply(211, "%s FTP server status:", hostname, version);
1760	printf("     %s\r\n", version);
1761	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1762	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1763	printf("     Connected to %s", remotehost);
1764	if (strcmp(remotehost, hbuf) != 0)
1765		printf(" (%s)", hbuf);
1766	printf("\r\n");
1767	if (logged_in) {
1768		if (guest)
1769			printf("     Logged in anonymously\r\n");
1770		else
1771			printf("     Logged in as %s\r\n", pw->pw_name);
1772	} else if (askpasswd)
1773		printf("     Waiting for password\r\n");
1774	else
1775		printf("     Waiting for user name\r\n");
1776	printf("     TYPE: %s", typenames[type]);
1777	if (type == TYPE_A || type == TYPE_E)
1778		printf(", FORM: %s", formnames[form]);
1779	if (type == TYPE_L)
1780#if NBBY == 8
1781		printf(" %d", NBBY);
1782#else
1783		printf(" %d", bytesize);	/* need definition! */
1784#endif
1785	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1786	    strunames[stru], modenames[mode]);
1787	ispassive = 0;
1788	if (data != -1)
1789		printf("     Data connection open\r\n");
1790	else if (pdata != -1) {
1791		printf("     in Passive mode\r\n");
1792		su = (union sockunion *)&pasv_addr;
1793		ispassive++;
1794		goto printaddr;
1795	} else if (usedefault == 0) {
1796		su = (union sockunion *)&data_dest;
1797printaddr:
1798		/* PASV/PORT */
1799		if (su->su_family == AF_INET) {
1800			if (ispassive)
1801				printf("211- PASV ");
1802			else
1803				printf("211- PORT ");
1804			a = (u_char *) &su->su_sin.sin_addr;
1805			p = (u_char *) &su->su_sin.sin_port;
1806			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1807			    a[0], a[1], a[2], a[3],
1808			    p[0], p[1]);
1809		}
1810
1811		/* LPSV/LPRT */
1812	    {
1813		int alen, af, i;
1814
1815		alen = 0;
1816		switch (su->su_family) {
1817		case AF_INET:
1818			a = (u_char *) &su->su_sin.sin_addr;
1819			p = (u_char *) &su->su_sin.sin_port;
1820			alen = sizeof(su->su_sin.sin_addr);
1821			af = 4;
1822			break;
1823		case AF_INET6:
1824			a = (u_char *) &su->su_sin6.sin6_addr;
1825			p = (u_char *) &su->su_sin6.sin6_port;
1826			alen = sizeof(su->su_sin6.sin6_addr);
1827			af = 6;
1828			break;
1829		default:
1830			af = 0;
1831			break;
1832		}
1833		if (af) {
1834			if (ispassive)
1835				printf("211- LPSV ");
1836			else
1837				printf("211- LPRT ");
1838			printf("(%u,%u", af, alen);
1839			for (i = 0; i < alen; i++)
1840				printf(",%u", a[i]);
1841			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1842		}
1843	    }
1844
1845		/* EPRT/EPSV */
1846	    {
1847		u_char af;
1848
1849		switch (su->su_family) {
1850		case AF_INET:
1851			af = 1;
1852			break;
1853		case AF_INET6:
1854			af = 2;
1855			break;
1856		default:
1857			af = 0;
1858			break;
1859		}
1860		if (af) {
1861			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1862			if (getnameinfo((struct sockaddr *)su, su->su_len,
1863			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1864			    NI_NUMERICHOST) == 0) {
1865				if (ispassive)
1866					printf("211- EPSV ");
1867				else
1868					printf("211- EPRT ");
1869				printf("(|%u|%s|%s|)\r\n",
1870					af, hbuf, pbuf);
1871			}
1872		}
1873	    }
1874	} else
1875		printf("     No data connection\r\n");
1876	reply(211, "End of status");
1877}
1878
1879void
1880fatal(s)
1881	char *s;
1882{
1883
1884	reply(451, "Error in server: %s", s);
1885	reply(221, "Closing connection due to server error.");
1886	dologout(0);
1887	/* NOTREACHED */
1888}
1889
1890void
1891reply(int n, const char *fmt, ...)
1892{
1893	char *buf, *p, *next;
1894	va_list ap;
1895
1896	va_start(ap, fmt);
1897	if (vasprintf(&buf, fmt, ap) == -1 || buf == NULL) {
1898		printf("412 Local resource failure: malloc\r\n");
1899		fflush(stdout);
1900		dologout(1);
1901	}
1902	next = buf;
1903	while ((p = strsep(&next, "\n\r"))) {
1904		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1905		if (debug)
1906			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1907			    (next != '\0') ? "-" : "", p);
1908	}
1909	(void)fflush(stdout);
1910	free(buf);
1911	va_end(ap);
1912}
1913
1914void
1915lreply(int n, const char *fmt, ...)
1916{
1917	va_list ap;
1918
1919	va_start(ap, fmt);
1920	(void)printf("%d- ", n);
1921	(void)vprintf(fmt, ap);
1922	va_end(ap);
1923	(void)printf("\r\n");
1924	(void)fflush(stdout);
1925	if (debug) {
1926		va_start(ap, fmt);
1927		syslog(LOG_DEBUG, "<--- %d- ", n);
1928		vsyslog(LOG_DEBUG, fmt, ap);
1929		va_end(ap);
1930	}
1931}
1932
1933static void
1934ack(s)
1935	char *s;
1936{
1937
1938	reply(250, "%s command successful.", s);
1939}
1940
1941void
1942nack(s)
1943	char *s;
1944{
1945
1946	reply(502, "%s command not implemented.", s);
1947}
1948
1949/* ARGSUSED */
1950void
1951yyerror(s)
1952	char *s;
1953{
1954	char *cp;
1955
1956	if ((cp = strchr(cbuf,'\n')))
1957		*cp = '\0';
1958	reply(500, "'%s': command not understood.", cbuf);
1959}
1960
1961void
1962delete(name)
1963	char *name;
1964{
1965	struct stat st;
1966
1967	LOGCMD("delete", name);
1968	if (stat(name, &st) < 0) {
1969		perror_reply(550, name);
1970		return;
1971	}
1972	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1973		if (rmdir(name) < 0) {
1974			perror_reply(550, name);
1975			return;
1976		}
1977		goto done;
1978	}
1979	if (unlink(name) < 0) {
1980		perror_reply(550, name);
1981		return;
1982	}
1983done:
1984	ack("DELE");
1985}
1986
1987void
1988cwd(path)
1989	char *path;
1990{
1991	FILE *message;
1992
1993	if (chdir(path) < 0)
1994		perror_reply(550, path);
1995	else {
1996		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
1997			char *cp, line[LINE_MAX];
1998
1999			while (fgets(line, sizeof(line), message) != NULL) {
2000				if ((cp = strchr(line, '\n')) != NULL)
2001					*cp = '\0';
2002				lreply(250, "%s", line);
2003			}
2004			(void) fflush(stdout);
2005			(void) fclose(message);
2006		}
2007		ack("CWD");
2008	}
2009}
2010
2011void
2012replydirname(name, message)
2013	const char *name, *message;
2014{
2015	char *p, *ep;
2016	char npath[MAXPATHLEN * 2];
2017
2018	p = npath;
2019	ep = &npath[sizeof(npath) - 1];
2020	while (*name) {
2021		if (*name == '"') {
2022			if (ep - p < 2)
2023				break;
2024			*p++ = *name++;
2025			*p++ = '"';
2026		} else {
2027			if (ep - p < 1)
2028				break;
2029			*p++ = *name++;
2030		}
2031	}
2032	*p = '\0';
2033	reply(257, "\"%s\" %s", npath, message);
2034}
2035
2036void
2037makedir(name)
2038	char *name;
2039{
2040
2041	LOGCMD("mkdir", name);
2042	if (mkdir(name, 0777) < 0)
2043		perror_reply(550, name);
2044	else
2045		replydirname(name, "directory created.");
2046}
2047
2048void
2049removedir(name)
2050	char *name;
2051{
2052
2053	LOGCMD("rmdir", name);
2054	if (rmdir(name) < 0)
2055		perror_reply(550, name);
2056	else
2057		ack("RMD");
2058}
2059
2060void
2061pwd()
2062{
2063	char path[MAXPATHLEN];
2064
2065	if (getcwd(path, sizeof(path)) == NULL)
2066		reply(550, "Can't get current directory: %s.", strerror(errno));
2067	else
2068		replydirname(path, "is current directory.");
2069}
2070
2071char *
2072renamefrom(name)
2073	char *name;
2074{
2075	struct stat st;
2076
2077	if (stat(name, &st) < 0) {
2078		perror_reply(550, name);
2079		return ((char *)0);
2080	}
2081	reply(350, "File exists, ready for destination name");
2082	return (name);
2083}
2084
2085void
2086renamecmd(from, to)
2087	char *from, *to;
2088{
2089
2090	LOGCMD2("rename", from, to);
2091	if (rename(from, to) < 0)
2092		perror_reply(550, "rename");
2093	else
2094		ack("RNTO");
2095}
2096
2097static void
2098dolog(sa)
2099	struct sockaddr *sa;
2100{
2101	char hbuf[sizeof(remotehost)];
2102
2103	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2104	(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2105
2106#ifdef HASSETPROCTITLE
2107	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2108	setproctitle("%s", proctitle);
2109#endif /* HASSETPROCTITLE */
2110
2111	if (logging)
2112		syslog(LOG_INFO, "connection from %s", remotehost);
2113}
2114
2115/*
2116 * Record logout in wtmp file and exit with supplied status.
2117 * NOTE: because this is called from signal handlers it cannot
2118 *       use stdio (or call other functions that use stdio).
2119 */
2120void
2121dologout(status)
2122	int status;
2123{
2124
2125	transflag = 0;
2126
2127	if (logged_in) {
2128		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2129		(void) seteuid((uid_t)0);
2130		ftpdlogwtmp(ttyline, "", "");
2131		if (doutmp)
2132			logout(utmp.ut_line);
2133	}
2134	/* beware of flushing buffers after a SIGPIPE */
2135	_exit(status);
2136}
2137
2138static void
2139sigurg(signo)
2140	int signo;
2141{
2142
2143	recvurg = 1;
2144}
2145
2146static void
2147myoob()
2148{
2149	char *cp;
2150
2151	/* only process if transfer occurring */
2152	if (!transflag)
2153		return;
2154	cp = tmpline;
2155	if (getline(cp, 7, stdin) == NULL) {
2156		reply(221, "You could at least say goodbye.");
2157		dologout(0);
2158	}
2159	upper(cp);
2160	if (strcmp(cp, "ABOR\r\n") == 0) {
2161		tmpline[0] = '\0';
2162		reply(426, "Transfer aborted. Data connection closed.");
2163		reply(226, "Abort successful");
2164	}
2165	if (strcmp(cp, "STAT\r\n") == 0) {
2166		tmpline[0] = '\0';
2167		if (file_size != (off_t) -1)
2168			reply(213, "Status: %qd of %qd bytes transferred",
2169			    byte_count, file_size);
2170		else
2171			reply(213, "Status: %qd bytes transferred", byte_count);
2172	}
2173}
2174
2175/*
2176 * Note: a response of 425 is not mentioned as a possible response to
2177 *	the PASV command in RFC959. However, it has been blessed as
2178 *	a legitimate response by Jon Postel in a telephone conversation
2179 *	with Rick Adams on 25 Jan 89.
2180 */
2181void
2182passive()
2183{
2184	int len, on;
2185	u_char *p, *a;
2186
2187	if (pw == NULL) {
2188		reply(530, "Please login with USER and PASS");
2189		return;
2190	}
2191	if (pdata >= 0)
2192		close(pdata);
2193	/*
2194	 * XXX
2195	 * At this point, it would be nice to have an algorithm that
2196	 * inserted a growing delay in an attack scenario.  Such a thing
2197	 * would look like continual passive sockets being opened, but
2198	 * nothing serious being done with them.  They're not used to
2199	 * move data; the entire attempt is just to use tcp FIN_WAIT
2200	 * resources.
2201	 */
2202	pdata = socket(AF_INET, SOCK_STREAM, 0);
2203	if (pdata < 0) {
2204		perror_reply(425, "Can't open passive connection");
2205		return;
2206	}
2207
2208#ifdef IP_PORTRANGE
2209	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2210	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2211	    (char *)&on, sizeof(on)) < 0)
2212		goto pasv_error;
2213#endif
2214
2215	pasv_addr = ctrl_addr;
2216	pasv_addr.su_sin.sin_port = 0;
2217	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2218		 pasv_addr.su_len) < 0)
2219		goto pasv_error;
2220
2221	len = sizeof(pasv_addr);
2222	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2223		goto pasv_error;
2224	if (listen(pdata, 1) < 0)
2225		goto pasv_error;
2226	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2227	p = (u_char *) &pasv_addr.su_sin.sin_port;
2228
2229	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2230	    a[1], a[2], a[3], p[0], p[1]);
2231	return;
2232
2233pasv_error:
2234	(void) seteuid((uid_t)pw->pw_uid);
2235	(void) close(pdata);
2236	pdata = -1;
2237	perror_reply(425, "Can't open passive connection");
2238	return;
2239}
2240
2241/*
2242 * convert protocol identifier to/from AF
2243 */
2244int
2245lpsvproto2af(int proto)
2246{
2247
2248	switch (proto) {
2249	case 4:	return AF_INET;
2250#ifdef INET6
2251	case 6:	return AF_INET6;
2252#endif
2253	default: return -1;
2254	}
2255}
2256
2257int
2258af2lpsvproto(int af)
2259{
2260
2261	switch (af) {
2262	case AF_INET:	return 4;
2263#ifdef INET6
2264	case AF_INET6:	return 6;
2265#endif
2266	default:	return -1;
2267	}
2268}
2269
2270int
2271epsvproto2af(int proto)
2272{
2273
2274	switch (proto) {
2275	case 1:	return AF_INET;
2276#ifdef INET6
2277	case 2:	return AF_INET6;
2278#endif
2279	default: return -1;
2280	}
2281}
2282
2283int
2284af2epsvproto(int af)
2285{
2286
2287	switch (af) {
2288	case AF_INET:	return 1;
2289#ifdef INET6
2290	case AF_INET6:	return 2;
2291#endif
2292	default:	return -1;
2293	}
2294}
2295
2296/*
2297 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2298 * 229 Entering Extended Passive Mode (|||port|)
2299 */
2300void
2301long_passive(char *cmd, int pf)
2302{
2303	int len, on;
2304	u_char *p, *a;
2305
2306	if (!logged_in) {
2307		syslog(LOG_NOTICE, "long passive but not logged in");
2308		reply(503, "Login with USER first.");
2309		return;
2310	}
2311
2312	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2313		/*
2314		 * XXX
2315		 * only EPRT/EPSV ready clients will understand this
2316		 */
2317		if (strcmp(cmd, "EPSV") != 0)
2318			reply(501, "Network protocol mismatch"); /*XXX*/
2319		else
2320			epsv_protounsupp("Network protocol mismatch");
2321
2322		return;
2323	}
2324
2325	if (pdata >= 0)
2326		close(pdata);
2327	/*
2328	 * XXX
2329	 * At this point, it would be nice to have an algorithm that
2330	 * inserted a growing delay in an attack scenario.  Such a thing
2331	 * would look like continual passive sockets being opened, but
2332	 * nothing serious being done with them.  They not used to move
2333	 * data; the entire attempt is just to use tcp FIN_WAIT
2334	 * resources.
2335	 */
2336	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2337	if (pdata < 0) {
2338		perror_reply(425, "Can't open passive connection");
2339		return;
2340	}
2341
2342	switch (ctrl_addr.su_family) {
2343	case AF_INET:
2344#ifdef IP_PORTRANGE
2345		on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2346		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2347		    (char *)&on, sizeof(on)) < 0)
2348			goto pasv_error;
2349#endif
2350		break;
2351	case AF_INET6:
2352#ifdef IPV6_PORTRANGE
2353		on = high_data_ports ? IPV6_PORTRANGE_HIGH
2354				     : IPV6_PORTRANGE_DEFAULT;
2355		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2356		    (char *)&on, sizeof(on)) < 0)
2357			goto pasv_error;
2358#endif
2359		break;
2360	}
2361
2362	pasv_addr = ctrl_addr;
2363	pasv_addr.su_port = 0;
2364	(void) seteuid((uid_t) 0);
2365	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2366		(void) seteuid((uid_t) pw->pw_uid);
2367		goto pasv_error;
2368	}
2369	(void) seteuid((uid_t) pw->pw_uid);
2370	len = pasv_addr.su_len;
2371	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2372		goto pasv_error;
2373	if (listen(pdata, 1) < 0)
2374		goto pasv_error;
2375	p = (u_char *) &pasv_addr.su_port;
2376
2377	if (strcmp(cmd, "LPSV") == 0) {
2378		switch (pasv_addr.su_family) {
2379		case AF_INET:
2380			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2381			reply(228,
2382			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2383			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2384			return;
2385		case AF_INET6:
2386			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2387			reply(228,
2388			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2389			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2390				6, 16, a[0], a[1], a[2], a[3], a[4],
2391				a[5], a[6], a[7], a[8], a[9], a[10],
2392				a[11], a[12], a[13], a[14], a[15],
2393				2, p[0], p[1]);
2394			return;
2395		}
2396	} else if (strcmp(cmd, "EPSV") == 0) {
2397		switch (pasv_addr.su_family) {
2398		case AF_INET:
2399		case AF_INET6:
2400			reply(229, "Entering Extended Passive Mode (|||%u|)",
2401			    ntohs(pasv_addr.su_port));
2402			return;
2403		}
2404	} else {
2405		/* more proper error code? */
2406	}
2407
2408  pasv_error:
2409	(void) close(pdata);
2410	pdata = -1;
2411	perror_reply(425, "Can't open passive connection");
2412	return;
2413}
2414
2415/*
2416 * EPRT |proto|addr|port|
2417 */
2418int
2419extended_port(const char *arg)
2420{
2421	char *tmp = NULL;
2422	char *result[3];
2423	char *p, *q;
2424	char delim;
2425	struct addrinfo hints;
2426	struct addrinfo *res = NULL;
2427	int i;
2428	unsigned long proto;
2429
2430	if (epsvall) {
2431		reply(501, "EPRT disallowed after EPSV ALL");
2432		return -1;
2433	}
2434
2435	usedefault = 0;
2436	if (pdata >= 0) {
2437		(void) close(pdata);
2438		pdata = -1;
2439	}
2440
2441	tmp = strdup(arg);
2442	if (!tmp) {
2443		fatal("not enough core.");
2444		/*NOTREACHED*/
2445	}
2446	p = tmp;
2447	delim = p[0];
2448	p++;
2449	memset(result, 0, sizeof(result));
2450	for (i = 0; i < 3; i++) {
2451		q = strchr(p, delim);
2452		if (!q || *q != delim)
2453			goto parsefail;
2454		*q++ = '\0';
2455		result[i] = p;
2456		p = q;
2457	}
2458
2459	/* some more sanity check */
2460	p = NULL;
2461	(void)strtoul(result[2], &p, 10);
2462	if (!*result[2] || *p)
2463		goto protounsupp;
2464	p = NULL;
2465	proto = strtoul(result[0], &p, 10);
2466	if (!*result[0] || *p)
2467		goto protounsupp;
2468
2469	memset(&hints, 0, sizeof(hints));
2470	hints.ai_family = epsvproto2af((int)proto);
2471	if (hints.ai_family < 0)
2472		goto protounsupp;
2473	hints.ai_socktype = SOCK_STREAM;
2474	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2475	if (getaddrinfo(result[1], result[2], &hints, &res))
2476		goto parsefail;
2477	if (res->ai_next)
2478		goto parsefail;
2479	if (sizeof(data_dest) < res->ai_addrlen)
2480		goto parsefail;
2481	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2482	if (his_addr.su_family == AF_INET6 &&
2483	    data_dest.su_family == AF_INET6) {
2484		/* XXX more sanity checks! */
2485		data_dest.su_sin6.sin6_scope_id =
2486		    his_addr.su_sin6.sin6_scope_id;
2487	}
2488	if (pdata >= 0) {
2489		(void) close(pdata);
2490		pdata = -1;
2491	}
2492	reply(200, "EPRT command successful.");
2493
2494	if (tmp)
2495		free(tmp);
2496	if (res)
2497		freeaddrinfo(res);
2498	return 0;
2499
2500parsefail:
2501	reply(500, "Invalid argument, rejected.");
2502	usedefault = 1;
2503	if (tmp)
2504		free(tmp);
2505	if (res)
2506		freeaddrinfo(res);
2507	return -1;
2508
2509protounsupp:
2510	epsv_protounsupp("Protocol not supported");
2511	usedefault = 1;
2512	if (tmp)
2513		free(tmp);
2514	if (res)
2515		freeaddrinfo(res);
2516	return -1;
2517}
2518
2519/*
2520 * 522 Protocol not supported (proto,...)
2521 * as we assume address family for control and data connections are the same,
2522 * we do not return the list of address families we support - instead, we
2523 * return the address family of the control connection.
2524 */
2525void
2526epsv_protounsupp(const char *message)
2527{
2528	int proto;
2529
2530	proto = af2epsvproto(ctrl_addr.su_family);
2531	if (proto < 0)
2532		reply(501, "%s", message);	/*XXX*/
2533	else
2534		reply(522, "%s, use (%d)", message, proto);
2535}
2536
2537/*
2538 * Generate unique name for file with basename "local".
2539 * The file named "local" is already known to exist.
2540 * Generates failure reply on error.
2541 */
2542static int
2543guniquefd(local, nam)
2544	char *local;
2545	char **nam;
2546{
2547	static char new[MAXPATHLEN];
2548	struct stat st;
2549	int count, len, fd;
2550	char *cp;
2551
2552	cp = strrchr(local, '/');
2553	if (cp)
2554		*cp = '\0';
2555	if (stat(cp ? local : ".", &st) < 0) {
2556		perror_reply(553, cp ? local : ".");
2557		return (-1);
2558	}
2559	if (cp)
2560		*cp = '/';
2561	len = strlcpy(new, local, sizeof(new));
2562	if (len+2+1 >= sizeof(new)-1)
2563		return (-1);
2564	cp = new + len;
2565	*cp++ = '.';
2566	for (count = 1; count < 100; count++) {
2567		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2568		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2569		if (fd == -1)
2570			continue;
2571		if (nam)
2572			*nam = new;
2573		return (fd);
2574	}
2575	reply(452, "Unique file name cannot be created.");
2576	return (-1);
2577}
2578
2579/*
2580 * Format and send reply containing system error number.
2581 */
2582void
2583perror_reply(code, string)
2584	int code;
2585	char *string;
2586{
2587
2588	reply(code, "%s: %s.", string, strerror(errno));
2589}
2590
2591static char *onefile[] = {
2592	"",
2593	0
2594};
2595
2596void
2597send_file_list(whichf)
2598	char *whichf;
2599{
2600	struct stat st;
2601	DIR *dirp = NULL;
2602	struct dirent *dir;
2603	FILE *dout = NULL;
2604	char **dirlist;
2605	char *dirname;
2606	int simple = 0;
2607	volatile int freeglob = 0;
2608	glob_t gl;
2609
2610	if (strpbrk(whichf, "~{[*?") != NULL) {
2611		memset(&gl, 0, sizeof(gl));
2612		freeglob = 1;
2613		if (glob(whichf,
2614		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2615		    0, &gl)) {
2616			reply(550, "not found");
2617			goto out;
2618		} else if (gl.gl_pathc == 0) {
2619			errno = ENOENT;
2620			perror_reply(550, whichf);
2621			goto out;
2622		}
2623		dirlist = gl.gl_pathv;
2624	} else {
2625		onefile[0] = whichf;
2626		dirlist = onefile;
2627		simple = 1;
2628	}
2629
2630	while ((dirname = *dirlist++)) {
2631		if (stat(dirname, &st) < 0) {
2632			/*
2633			 * If user typed "ls -l", etc, and the client
2634			 * used NLST, do what the user meant.
2635			 */
2636			if (dirname[0] == '-' && *dirlist == NULL &&
2637			    transflag == 0) {
2638				retrieve("/bin/ls %s", dirname);
2639				goto out;
2640			}
2641			perror_reply(550, whichf);
2642			if (dout != NULL) {
2643				(void) fclose(dout);
2644				transflag = 0;
2645				data = -1;
2646				pdata = -1;
2647			}
2648			goto out;
2649		}
2650
2651		if (S_ISREG(st.st_mode)) {
2652			if (dout == NULL) {
2653				dout = dataconn("file list", (off_t)-1, "w");
2654				if (dout == NULL)
2655					goto out;
2656				transflag++;
2657			}
2658			fprintf(dout, "%s%s\n", dirname,
2659				type == TYPE_A ? "\r" : "");
2660			byte_count += strlen(dirname) + 1;
2661			continue;
2662		} else if (!S_ISDIR(st.st_mode))
2663			continue;
2664
2665		if ((dirp = opendir(dirname)) == NULL)
2666			continue;
2667
2668		while ((dir = readdir(dirp)) != NULL) {
2669			char nbuf[MAXPATHLEN];
2670
2671			if (recvurg) {
2672				myoob();
2673				recvurg = 0;
2674				transflag = 0;
2675				goto out;
2676			}
2677
2678			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2679				continue;
2680			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2681			    dir->d_namlen == 2)
2682				continue;
2683
2684			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2685				 dir->d_name);
2686
2687			/*
2688			 * We have to do a stat to insure it's
2689			 * not a directory or special file.
2690			 */
2691			if (simple || (stat(nbuf, &st) == 0 &&
2692			    S_ISREG(st.st_mode))) {
2693				if (dout == NULL) {
2694					dout = dataconn("file list", (off_t)-1,
2695						"w");
2696					if (dout == NULL)
2697						goto out;
2698					transflag++;
2699				}
2700				if (nbuf[0] == '.' && nbuf[1] == '/')
2701					fprintf(dout, "%s%s\n", &nbuf[2],
2702						type == TYPE_A ? "\r" : "");
2703				else
2704					fprintf(dout, "%s%s\n", nbuf,
2705						type == TYPE_A ? "\r" : "");
2706				byte_count += strlen(nbuf) + 1;
2707			}
2708		}
2709		(void) closedir(dirp);
2710	}
2711
2712	if (dout == NULL)
2713		reply(550, "No files found.");
2714	else if (ferror(dout) != 0)
2715		perror_reply(550, "Data connection");
2716	else
2717		reply(226, "Transfer complete.");
2718
2719	transflag = 0;
2720	if (dout != NULL)
2721		(void) fclose(dout);
2722	else {
2723		if (pdata >= 0)
2724			close(pdata);
2725	}
2726	data = -1;
2727	pdata = -1;
2728out:
2729	if (freeglob) {
2730		freeglob = 0;
2731		globfree(&gl);
2732	}
2733}
2734
2735static void
2736reapchild(signo)
2737	int signo;
2738{
2739	int save_errno = errno;
2740	int rval;
2741
2742	do {
2743		rval = waitpid(-1, NULL, WNOHANG);
2744	} while (rval > 0 || (rval == -1 && errno == EINTR));
2745	errno = save_errno;
2746}
2747
2748void
2749logxfer(name, size, start)
2750	char *name;
2751	off_t size;
2752	time_t start;
2753{
2754	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2755	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2756	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2757	char *vpw;
2758	time_t now;
2759	int len;
2760
2761	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2762		time(&now);
2763
2764		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2765		if (vpw == NULL)
2766			return;
2767
2768		snprintf(path, sizeof(path), "%s/%s", dir, name);
2769		if (realpath(path, rpath) == NULL)
2770			strlcpy(rpath, path, sizeof(rpath));
2771		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2772
2773		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2774		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2775
2776		len = snprintf(buf, sizeof(buf),
2777		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2778		    ctime(&now), now - start + (now == start),
2779		    vremotehost, (long long) size, vpath,
2780		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2781		    'o', ((guest) ? 'a' : 'r'),
2782		    vpw, 0 /* none yet */,
2783		    ((guest) ? "*" : pw->pw_name), dhostname);
2784		if (len >= sizeof(buf)) {
2785			len = sizeof(buf);
2786			buf[sizeof(buf) - 1] = '\n';
2787		}
2788		write(statfd, buf, len);
2789		free(vpw);
2790	}
2791}
2792
2793#if defined(TCPWRAPPERS)
2794static int
2795check_host(sa)
2796	struct sockaddr *sa;
2797{
2798	struct sockaddr_in *sin;
2799	struct hostent *hp;
2800	char *addr;
2801
2802	if (sa->sa_family != AF_INET)
2803		return 1;	/*XXX*/
2804
2805	sin = (struct sockaddr_in *)sa;
2806	hp = gethostbyaddr((char *)&sin->sin_addr,
2807	    sizeof(struct in_addr), AF_INET);
2808	addr = inet_ntoa(sin->sin_addr);
2809	if (hp) {
2810		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2811			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2812			    hp->h_name, addr);
2813			return (0);
2814		}
2815	} else {
2816		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2817			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2818			return (0);
2819		}
2820	}
2821	return (1);
2822}
2823#endif	/* TCPWRAPPERS */
2824
2825/*
2826 * Allocate space and return a copy of the specified dir.
2827 * If 'dir' begins with a tilde (~), expand it.
2828 */
2829char *
2830copy_dir(dir, pw)
2831	char *dir;
2832	struct passwd *pw;
2833{
2834	char *cp;
2835	char *newdir;
2836	char *user = NULL;
2837	size_t dirsiz;
2838
2839	/* Nothing to expand */
2840	if (dir[0] !=  '~')
2841		return (strdup(dir));
2842
2843	/* "dir" is of form ~user/some/dir, lookup user. */
2844	if (dir[1] != '/' && dir[1] != '\0') {
2845		if ((cp = strchr(dir + 1, '/')) == NULL)
2846		    cp = dir + strlen(dir);
2847		if ((user = malloc(cp - dir)) == NULL)
2848			return (NULL);
2849		strlcpy(user, dir + 1, cp - dir);
2850
2851		/* Only do lookup if it is a different user. */
2852		if (strcmp(user, pw->pw_name) != 0) {
2853			if ((pw = getpwnam(user)) == NULL) {
2854				/* No such user, interpret literally */
2855				free(user);
2856				return(strdup(dir));
2857			}
2858		}
2859	}
2860
2861	/*
2862	 * If there is no directory separator (/) then it is just pw_dir.
2863	 * Otherwise, replace ~foo with  pw_dir.
2864	 */
2865	if ((cp = strchr(dir + 1, '/')) == NULL) {
2866		newdir = strdup(pw->pw_dir);
2867	} else {
2868		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2869		if ((newdir = malloc(dirsiz)) == NULL) {
2870			free(user);
2871			return (NULL);
2872		}
2873		strlcpy(newdir, pw->pw_dir, dirsiz);
2874		strlcat(newdir, cp, dirsiz);
2875	}
2876
2877	if (user)
2878		free(user);
2879	return(newdir);
2880}
2881