ftpd.c revision 1.122
1/*	$OpenBSD: ftpd.c,v 1.122 2002/03/12 02:15:39 millert 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.122 2002/03/12 02:15:39 millert 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%d", 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_setoption(as, "FTPD_HOST", host) < 0) {
724				if (as) {
725					auth_close(as);
726					as = NULL;
727				}
728				login_close(lc);
729				lc = NULL;
730				reply(421, "Local resource failure");
731				return;
732			}
733			reply(331,
734			"Guest login ok, send your email address as password.");
735		} else
736			reply(530, "User %s unknown.", name);
737		if (!askpasswd && logging)
738			syslog(LOG_NOTICE,
739			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
740		return;
741	}
742
743	shell = _PATH_BSHELL;
744	if ((pw = sgetpwnam(name))) {
745		class = pw->pw_class;
746		if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
747			shell = pw->pw_shell;
748		while ((cp = getusershell()) != NULL)
749			if (strcmp(cp, shell) == 0)
750				break;
751		shell = cp;
752		endusershell();
753	}
754
755	/* Get login class; if invalid style treat like unknown user. */
756	lc = login_getclass(class);
757	if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
758		login_close(lc);
759		lc = NULL;
760		pw = NULL;
761	}
762
763	/* Do pre-authentication setup. */
764	if (lc && ((as = auth_open()) == NULL ||
765	    auth_setitem(as, AUTHV_STYLE, style) < 0 ||
766	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
767	    auth_setitem(as, AUTHV_CLASS, class) < 0 ||
768	    auth_setoption(as, "login", "yes") < 0 ||
769	    auth_setoption(as, "notickets", "yes") < 0 ||
770	    auth_setoption(as, "FTPD_HOST", host) < 0)) {
771		if (as) {
772			auth_close(as);
773			as = NULL;
774		}
775		login_close(lc);
776		lc = NULL;
777		reply(421, "Local resource failure");
778		return;
779	}
780	if (logging)
781		strlcpy(curname, name, sizeof(curname));
782
783	dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
784	    checkuser(_PATH_FTPCHROOT, name);
785	if (anon_only && !dochroot) {
786		reply(530, "Sorry, only anonymous ftp allowed.");
787		return;
788	}
789	if (pw) {
790		if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
791			reply(530, "User %s access denied.", name);
792			if (logging)
793				syslog(LOG_NOTICE,
794				    "FTP LOGIN REFUSED FROM %s, %s",
795				    remotehost, name);
796			pw = NULL;
797			return;
798		}
799	}
800
801	if (as != NULL && (cp = auth_challenge(as)) != NULL)
802		reply(331, cp);
803	else
804		reply(331, "Password required for %s.", name);
805
806	askpasswd = 1;
807	/*
808	 * Delay before reading passwd after first failed
809	 * attempt to slow down passwd-guessing programs.
810	 */
811	if (login_attempts)
812		sleep((unsigned) login_attempts);
813}
814
815/*
816 * Check if a user is in the file "fname"
817 */
818static int
819checkuser(fname, name)
820	char *fname;
821	char *name;
822{
823	FILE *fp;
824	int found = 0;
825	char *p, line[BUFSIZ];
826
827	if ((fp = fopen(fname, "r")) != NULL) {
828		while (fgets(line, sizeof(line), fp) != NULL)
829			if ((p = strchr(line, '\n')) != NULL) {
830				*p = '\0';
831				if (line[0] == '#')
832					continue;
833				if (strcmp(line, name) == 0) {
834					found = 1;
835					break;
836				}
837			}
838		(void) fclose(fp);
839	}
840	return (found);
841}
842
843/*
844 * Terminate login as previous user, if any, resetting state;
845 * used when USER command is given or login fails.
846 */
847static void
848end_login()
849{
850
851	sigprocmask (SIG_BLOCK, &allsigs, NULL);
852	(void) seteuid((uid_t)0);
853	if (logged_in) {
854		ftpdlogwtmp(ttyline, "", "");
855		if (doutmp)
856			logout(utmp.ut_line);
857	}
858	pw = NULL;
859	/* umask is restored in ftpcmd.y */
860	setusercontext(NULL, getpwuid(0), (uid_t)0,
861	    LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
862	logged_in = 0;
863	guest = 0;
864	dochroot = 0;
865}
866
867void
868pass(passwd)
869	char *passwd;
870{
871	int authok, flags;
872	FILE *fp;
873	static char homedir[MAXPATHLEN];
874	char *motd, *dir, rootdir[MAXPATHLEN];
875
876	if (logged_in || askpasswd == 0) {
877		reply(503, "Login with USER first.");
878		return;
879	}
880	askpasswd = 0;
881	if (!guest) {		/* "ftp" is only account allowed no password */
882		authok = 0;
883		if (pw == NULL) {
884			useconds_t us;
885
886			/* Sleep between 1 and 3 seconds to emulate a crypt. */
887			us = arc4random() % 3000000;
888			usleep(us);
889		} else {
890			authok = auth_userresponse(as, passwd, 0);
891			as = NULL;
892		}
893		if (authok == 0) {
894			reply(530, "Login incorrect.");
895			if (logging)
896				syslog(LOG_NOTICE,
897				    "FTP LOGIN FAILED FROM %s, %s",
898				    remotehost, curname);
899			pw = NULL;
900			if (login_attempts++ >= 5) {
901				syslog(LOG_NOTICE,
902				    "repeated login failures from %s",
903				    remotehost);
904				exit(0);
905			}
906			return;
907		}
908	} else if (lc != NULL) {
909		/* Save anonymous' password. */
910		if (guestpw != NULL)
911			free(guestpw);
912		guestpw = strdup(passwd);
913		if (guestpw == NULL)
914			fatal("Out of memory.");
915
916		authok = auth_approval(as, lc, pw->pw_name, "ftp");
917		auth_close(as);
918		as = NULL;
919		if (authok == 0) {
920			syslog(LOG_INFO|LOG_AUTH,
921			    "FTP LOGIN FAILED (HOST) as %s: approval failure.",
922			    pw->pw_name);
923			reply(530, "Approval failure.");
924			exit(0);
925		}
926	} else {
927		syslog(LOG_INFO|LOG_AUTH,
928		    "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
929		    pw->pw_class, pw->pw_name);
930		reply(530, "Permission denied.");
931		exit(0);
932	}
933	login_attempts = 0;		/* this time successful */
934	if (setegid((gid_t)pw->pw_gid) < 0) {
935		reply(550, "Can't set gid.");
936		return;
937	}
938	/* set umask via setusercontext() unless -u flag was given. */
939	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
940	if (umaskchange)
941		flags |= LOGIN_SETUMASK;
942	else
943		(void) umask(defumask);
944	setusercontext(lc, pw, (uid_t)0, flags);
945
946	/* open wtmp before chroot */
947	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
948
949	/* open utmp before chroot */
950	if (doutmp) {
951		memset((void *)&utmp, 0, sizeof(utmp));
952		(void)time(&utmp.ut_time);
953		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
954		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
955		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
956		login(&utmp);
957	}
958
959	/* open stats file before chroot */
960	if (guest && (stats == 1) && (statfd < 0))
961		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
962			stats = 0;
963
964	logged_in = 1;
965
966	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
967		char *newdir;
968
969		newdir = copy_dir(dir, pw);
970		if (newdir == NULL) {
971			perror_reply(421, "Local resource failure: malloc");
972			dologout(1);
973			/* NOTREACHED */
974		}
975		free(dir);
976		free(pw->pw_dir);
977		pw->pw_dir = newdir;
978	}
979
980	/* make sure pw->pw_dir is big enough to hold "/" */
981	if (strlen(pw->pw_dir) < 1) {
982		char *newdir;
983
984		newdir = malloc(2);
985		if (newdir == NULL) {
986			perror_reply(421, "Local resource failure: malloc");
987			dologout(1);
988			/* NOTREACHED */
989		}
990		strlcpy(newdir, pw->pw_dir, 2);
991		free(pw->pw_dir);
992		pw->pw_dir = newdir;
993	}
994
995	if (guest || dochroot) {
996		if (multihome && guest) {
997			struct stat ts;
998
999			/* Compute root directory. */
1000			snprintf(rootdir, sizeof(rootdir), "%s/%s",
1001				  pw->pw_dir, dhostname);
1002			if (stat(rootdir, &ts) < 0) {
1003				snprintf(rootdir, sizeof(rootdir), "%s/%s",
1004					  pw->pw_dir, hostname);
1005			}
1006		} else
1007			strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1008	}
1009	if (guest) {
1010		/*
1011		 * We MUST do a chdir() after the chroot. Otherwise
1012		 * the old current directory will be accessible as "."
1013		 * outside the new root!
1014		 */
1015		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1016			reply(550, "Can't set guest privileges.");
1017			goto bad;
1018		}
1019		strcpy(pw->pw_dir, "/");
1020		if (setenv("HOME", "/", 1) == -1) {
1021			reply(550, "Can't setup environment.");
1022			goto bad;
1023		}
1024	} else if (dochroot) {
1025		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1026			reply(550, "Can't change root.");
1027			goto bad;
1028		}
1029		strcpy(pw->pw_dir, "/");
1030		if (setenv("HOME", "/", 1) == -1) {
1031			reply(550, "Can't setup environment.");
1032			goto bad;
1033		}
1034	} else if (chdir(pw->pw_dir) < 0) {
1035		if (chdir("/") < 0) {
1036			reply(530, "User %s: can't change directory to %s.",
1037			    pw->pw_name, pw->pw_dir);
1038			goto bad;
1039		} else
1040			lreply(230, "No directory! Logging in with home=/");
1041	}
1042	if (seteuid((uid_t)pw->pw_uid) < 0) {
1043		reply(550, "Can't set uid.");
1044		goto bad;
1045	}
1046	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1047
1048	/*
1049	 * Set home directory so that use of ~ (tilde) works correctly.
1050	 */
1051	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1052		if (setenv("HOME", homedir, 1) == -1) {
1053			reply(550, "Can't setup environment.");
1054			goto bad;
1055		}
1056	}
1057
1058	/*
1059	 * Display a login message, if it exists.
1060	 * N.B. reply(230,) must follow the message.
1061	 */
1062	motd = login_getcapstr(lc, "welcome", NULL, NULL);
1063	if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1064		char *cp, line[LINE_MAX];
1065
1066		while (fgets(line, sizeof(line), fp) != NULL) {
1067			if ((cp = strchr(line, '\n')) != NULL)
1068				*cp = '\0';
1069			lreply(230, "%s", line);
1070		}
1071		(void) fflush(stdout);
1072		(void) fclose(fp);
1073	}
1074	if (motd != NULL)
1075		free(motd);
1076	if (guest) {
1077		if (ident != NULL)
1078			free(ident);
1079		ident = strdup(passwd);
1080		if (ident == NULL)
1081			fatal("Ran out of memory.");
1082		reply(230, "Guest login ok, access restrictions apply.");
1083#ifdef HASSETPROCTITLE
1084		snprintf(proctitle, sizeof(proctitle),
1085		    "%s: anonymous/%.*s", remotehost,
1086		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1087		    sizeof(": anonymous/")), passwd);
1088		setproctitle("%s", proctitle);
1089#endif /* HASSETPROCTITLE */
1090		if (logging)
1091			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1092			    remotehost, passwd);
1093	} else {
1094		reply(230, "User %s logged in.", pw->pw_name);
1095#ifdef HASSETPROCTITLE
1096		snprintf(proctitle, sizeof(proctitle),
1097		    "%s: %s", remotehost, pw->pw_name);
1098		setproctitle("%s", proctitle);
1099#endif /* HASSETPROCTITLE */
1100		if (logging)
1101			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1102			    remotehost, pw->pw_name);
1103	}
1104	login_close(lc);
1105	lc = NULL;
1106	return;
1107bad:
1108	/* Forget all about it... */
1109	login_close(lc);
1110	lc = NULL;
1111	end_login();
1112}
1113
1114void
1115retrieve(cmd, name)
1116	char *cmd, *name;
1117{
1118	FILE *fin, *dout;
1119	struct stat st;
1120	int (*closefunc)(FILE *);
1121	time_t start;
1122
1123	if (cmd == 0) {
1124		fin = fopen(name, "r"), closefunc = fclose;
1125		st.st_size = 0;
1126	} else {
1127		char line[BUFSIZ];
1128
1129		(void) snprintf(line, sizeof(line), cmd, name);
1130		name = line;
1131		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1132		st.st_size = -1;
1133		st.st_blksize = BUFSIZ;
1134	}
1135	if (fin == NULL) {
1136		if (errno != 0) {
1137			perror_reply(550, name);
1138			if (cmd == 0) {
1139				LOGCMD("get", name);
1140			}
1141		}
1142		return;
1143	}
1144	byte_count = -1;
1145	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1146		reply(550, "%s: not a plain file.", name);
1147		goto done;
1148	}
1149	if (restart_point) {
1150		if (type == TYPE_A) {
1151			off_t i, n;
1152			int c;
1153
1154			n = restart_point;
1155			i = 0;
1156			while (i++ < n) {
1157				if ((c=getc(fin)) == EOF) {
1158					perror_reply(550, name);
1159					goto done;
1160				}
1161				if (c == '\n')
1162					i++;
1163			}
1164		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1165			perror_reply(550, name);
1166			goto done;
1167		}
1168	}
1169	dout = dataconn(name, st.st_size, "w");
1170	if (dout == NULL)
1171		goto done;
1172	time(&start);
1173	send_data(fin, dout, st.st_blksize, st.st_size,
1174		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1175	if ((cmd == 0) && stats)
1176		logxfer(name, byte_count, start);
1177	(void) fclose(dout);
1178	data = -1;
1179done:
1180	if (pdata >= 0)
1181		(void) close(pdata);
1182	pdata = -1;
1183	if (cmd == 0)
1184		LOGBYTES("get", name, byte_count);
1185	(*closefunc)(fin);
1186}
1187
1188void
1189store(name, mode, unique)
1190	char *name, *mode;
1191	int unique;
1192{
1193	FILE *fout, *din;
1194	int (*closefunc)(FILE *);
1195	struct stat st;
1196	int fd;
1197
1198	if (restart_point && *mode != 'a')
1199		mode = "r+";
1200
1201	if (unique && stat(name, &st) == 0) {
1202		char *nam;
1203
1204		fd = guniquefd(name, &nam);
1205		if (fd == -1) {
1206			LOGCMD(*mode == 'w' ? "put" : "append", name);
1207			return;
1208		}
1209		name = nam;
1210		fout = fdopen(fd, mode);
1211	} else
1212		fout = fopen(name, mode);
1213
1214	closefunc = fclose;
1215	if (fout == NULL) {
1216		perror_reply(553, name);
1217		LOGCMD(*mode == 'w' ? "put" : "append", name);
1218		return;
1219	}
1220	byte_count = -1;
1221	if (restart_point) {
1222		if (type == TYPE_A) {
1223			off_t i, n;
1224			int c;
1225
1226			n = restart_point;
1227			i = 0;
1228			while (i++ < n) {
1229				if ((c=getc(fout)) == EOF) {
1230					perror_reply(550, name);
1231					goto done;
1232				}
1233				if (c == '\n')
1234					i++;
1235			}
1236			/*
1237			 * We must do this seek to "current" position
1238			 * because we are changing from reading to
1239			 * writing.
1240			 */
1241			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1242				perror_reply(550, name);
1243				goto done;
1244			}
1245		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1246			perror_reply(550, name);
1247			goto done;
1248		}
1249	}
1250	din = dataconn(name, (off_t)-1, "r");
1251	if (din == NULL)
1252		goto done;
1253	if (receive_data(din, fout) == 0) {
1254		if (unique)
1255			reply(226, "Transfer complete (unique file name:%s).",
1256			    name);
1257		else
1258			reply(226, "Transfer complete.");
1259	}
1260	(void) fclose(din);
1261	data = -1;
1262	pdata = -1;
1263done:
1264	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1265	(*closefunc)(fout);
1266}
1267
1268static FILE *
1269getdatasock(mode)
1270	char *mode;
1271{
1272	int on = 1, s, t, tries;
1273
1274	if (data >= 0)
1275		return (fdopen(data, mode));
1276	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1277	(void) seteuid((uid_t)0);
1278	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1279	if (s < 0)
1280		goto bad;
1281	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1282	    (char *) &on, sizeof(on)) < 0)
1283		goto bad;
1284	/* anchor socket to avoid multi-homing problems */
1285	data_source = ctrl_addr;
1286	data_source.su_port = htons(20); /* ftp-data port */
1287	for (tries = 1; ; tries++) {
1288		if (bind(s, (struct sockaddr *)&data_source,
1289		    data_source.su_len) >= 0)
1290			break;
1291		if (errno != EADDRINUSE || tries > 10)
1292			goto bad;
1293		sleep(tries);
1294	}
1295	(void) seteuid((uid_t)pw->pw_uid);
1296	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1297
1298#ifdef IP_TOS
1299	if (ctrl_addr.su_family == AF_INET) {
1300		on = IPTOS_THROUGHPUT;
1301		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1302		    sizeof(int)) < 0)
1303			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1304	}
1305#endif
1306#ifdef TCP_NOPUSH
1307	/*
1308	 * Turn off push flag to keep sender TCP from sending short packets
1309	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1310	 * to set the send buffer size as well, but that may not be desirable
1311	 * in heavy-load situations.
1312	 */
1313	on = 1;
1314	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof(on)) < 0)
1315		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1316#endif
1317#ifdef SO_SNDBUF
1318	on = 65536;
1319	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof(on)) < 0)
1320		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1321#endif
1322
1323	return (fdopen(s, mode));
1324bad:
1325	/* Return the real value of errno (close may change it) */
1326	t = errno;
1327	(void) seteuid((uid_t)pw->pw_uid);
1328	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1329	(void) close(s);
1330	errno = t;
1331	return (NULL);
1332}
1333
1334static FILE *
1335dataconn(name, size, mode)
1336	char *name;
1337	off_t size;
1338	char *mode;
1339{
1340	char sizebuf[32];
1341	FILE *file;
1342	int retry = 0;
1343	in_port_t *p;
1344	char *fa, *ha;
1345	int alen;
1346
1347	file_size = size;
1348	byte_count = 0;
1349	if (size != (off_t) -1) {
1350		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1351				size);
1352	} else
1353		sizebuf[0] = '\0';
1354	if (pdata >= 0) {
1355		union sockunion from;
1356		int s, fromlen = sizeof(from);
1357
1358		signal (SIGALRM, toolong);
1359		(void) alarm ((unsigned) timeout);
1360		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1361		(void) alarm (0);
1362		if (s < 0) {
1363			reply(425, "Can't open data connection.");
1364			(void) close(pdata);
1365			pdata = -1;
1366			return (NULL);
1367		}
1368		switch (from.su_family) {
1369		case AF_INET:
1370			p = (in_port_t *)&from.su_sin.sin_port;
1371			fa = (u_char *)&from.su_sin.sin_addr;
1372			ha = (u_char *)&his_addr.su_sin.sin_addr;
1373			alen = sizeof(struct in_addr);
1374			break;
1375		case AF_INET6:
1376			p = (in_port_t *)&from.su_sin6.sin6_port;
1377			fa = (u_char *)&from.su_sin6.sin6_addr;
1378			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1379			alen = sizeof(struct in6_addr);
1380			break;
1381		default:
1382			perror_reply(425, "Can't build data connection");
1383			(void) close(pdata);
1384			(void) close(s);
1385			pdata = -1;
1386			return (NULL);
1387		}
1388		if (from.su_family != his_addr.su_family ||
1389		    ntohs(*p) < IPPORT_RESERVED) {
1390			perror_reply(425, "Can't build data connection");
1391			(void) close(pdata);
1392			(void) close(s);
1393			pdata = -1;
1394			return (NULL);
1395		}
1396		if (portcheck && memcmp(fa, ha, alen) != 0) {
1397			perror_reply(435, "Can't build data connection");
1398			(void) close(pdata);
1399			(void) close(s);
1400			pdata = -1;
1401			return (NULL);
1402		}
1403		(void) close(pdata);
1404		pdata = s;
1405		reply(150, "Opening %s mode data connection for '%s'%s.",
1406		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1407		return (fdopen(pdata, mode));
1408	}
1409	if (data >= 0) {
1410		reply(125, "Using existing data connection for '%s'%s.",
1411		    name, sizebuf);
1412		usedefault = 1;
1413		return (fdopen(data, mode));
1414	}
1415	if (usedefault)
1416		data_dest = his_addr;
1417	usedefault = 1;
1418	file = getdatasock(mode);
1419	if (file == NULL) {
1420		char hbuf[MAXHOSTNAMELEN], pbuf[10];
1421
1422		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1423		    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1424		    NI_NUMERICHOST | NI_NUMERICSERV);
1425		reply(425, "Can't create data socket (%s,%s): %s.",
1426		    hbuf, pbuf, strerror(errno));
1427		return (NULL);
1428	}
1429	data = fileno(file);
1430
1431	/*
1432	 * attempt to connect to reserved port on client machine;
1433	 * this looks like an attack
1434	 */
1435	switch (data_dest.su_family) {
1436	case AF_INET:
1437		p = (in_port_t *)&data_dest.su_sin.sin_port;
1438		fa = (u_char *)&data_dest.su_sin.sin_addr;
1439		ha = (u_char *)&his_addr.su_sin.sin_addr;
1440		alen = sizeof(struct in_addr);
1441		break;
1442	case AF_INET6:
1443		p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1444		fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1445		ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1446		alen = sizeof(struct in6_addr);
1447		break;
1448	default:
1449		perror_reply(425, "Can't build data connection");
1450		(void) fclose(file);
1451		pdata = -1;
1452		return (NULL);
1453	}
1454	if (data_dest.su_family != his_addr.su_family ||
1455	    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) {	/* XXX */
1456		perror_reply(425, "Can't build data connection");
1457		(void) fclose(file);
1458		data = -1;
1459		return NULL;
1460	}
1461	if (portcheck && memcmp(fa, ha, alen) != 0) {
1462		perror_reply(435, "Can't build data connection");
1463		(void) fclose(file);
1464		data = -1;
1465		return NULL;
1466	}
1467	while (connect(data, (struct sockaddr *)&data_dest,
1468	    data_dest.su_len) < 0) {
1469		if (errno == EADDRINUSE && retry < swaitmax) {
1470			sleep((unsigned) swaitint);
1471			retry += swaitint;
1472			continue;
1473		}
1474		perror_reply(425, "Can't build data connection");
1475		(void) fclose(file);
1476		data = -1;
1477		return (NULL);
1478	}
1479	reply(150, "Opening %s mode data connection for '%s'%s.",
1480	    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1481	return (file);
1482}
1483
1484/*
1485 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1486 * encapsulation of the data subject to Mode, Structure, and Type.
1487 *
1488 * NB: Form isn't handled.
1489 */
1490static int
1491send_data(instr, outstr, blksize, filesize, isreg)
1492	FILE *instr, *outstr;
1493	off_t blksize;
1494	off_t filesize;
1495	int isreg;
1496{
1497	int c, cnt, filefd, netfd;
1498	char *buf, *bp;
1499	size_t len;
1500
1501	transflag++;
1502	switch (type) {
1503
1504	case TYPE_A:
1505		while ((c = getc(instr)) != EOF) {
1506			if (recvurg)
1507				goto got_oob;
1508			byte_count++;
1509			if (c == '\n') {
1510				if (ferror(outstr))
1511					goto data_err;
1512				(void) putc('\r', outstr);
1513			}
1514			(void) putc(c, outstr);
1515		}
1516		fflush(outstr);
1517		transflag = 0;
1518		if (ferror(instr))
1519			goto file_err;
1520		if (ferror(outstr))
1521			goto data_err;
1522		reply(226, "Transfer complete.");
1523		return(0);
1524
1525	case TYPE_I:
1526	case TYPE_L:
1527		/*
1528		 * isreg is only set if we are not doing restart and we
1529		 * are sending a regular file
1530		 */
1531		netfd = fileno(outstr);
1532		filefd = fileno(instr);
1533
1534		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1535			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1536				   (off_t)0);
1537			if (buf == MAP_FAILED) {
1538				syslog(LOG_WARNING, "mmap(%lu): %m",
1539				    (unsigned long)filesize);
1540				goto oldway;
1541			}
1542			bp = buf;
1543			len = filesize;
1544			do {
1545				cnt = write(netfd, bp, len);
1546				if (recvurg) {
1547					munmap(buf, (size_t)filesize);
1548					goto got_oob;
1549				}
1550				len -= cnt;
1551				bp += cnt;
1552				if (cnt > 0) byte_count += cnt;
1553			} while(cnt > 0 && len > 0);
1554
1555			transflag = 0;
1556			munmap(buf, (size_t)filesize);
1557			if (cnt < 0)
1558				goto data_err;
1559			reply(226, "Transfer complete.");
1560			return(0);
1561		}
1562
1563oldway:
1564		if ((buf = malloc((u_int)blksize)) == NULL) {
1565			transflag = 0;
1566			perror_reply(451, "Local resource failure: malloc");
1567			return(-1);
1568		}
1569
1570		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1571		    write(netfd, buf, cnt) == cnt)
1572			byte_count += cnt;
1573		transflag = 0;
1574		(void)free(buf);
1575		if (cnt != 0) {
1576			if (cnt < 0)
1577				goto file_err;
1578			goto data_err;
1579		}
1580		reply(226, "Transfer complete.");
1581		return(0);
1582	default:
1583		transflag = 0;
1584		reply(550, "Unimplemented TYPE %d in send_data", type);
1585		return(-1);
1586	}
1587
1588data_err:
1589	transflag = 0;
1590	perror_reply(426, "Data connection");
1591	return(-1);
1592
1593file_err:
1594	transflag = 0;
1595	perror_reply(551, "Error on input file");
1596	return(-1);
1597
1598got_oob:
1599	myoob();
1600	recvurg = 0;
1601	transflag = 0;
1602	return(-1);
1603}
1604
1605/*
1606 * Transfer data from peer to "outstr" using the appropriate encapulation of
1607 * the data subject to Mode, Structure, and Type.
1608 *
1609 * N.B.: Form isn't handled.
1610 */
1611static int
1612receive_data(instr, outstr)
1613	FILE *instr, *outstr;
1614{
1615	int c;
1616	int cnt;
1617	char buf[BUFSIZ];
1618	struct sigaction sa;
1619	volatile int bare_lfs = 0;
1620
1621	transflag++;
1622	switch (type) {
1623
1624	case TYPE_I:
1625	case TYPE_L:
1626		sigfillset(&sa.sa_mask);
1627		sa.sa_flags = SA_RESTART;
1628		sigaction(SIGALRM, &sa, NULL);
1629
1630		do {
1631			(void) alarm ((unsigned) timeout);
1632			cnt = read(fileno(instr), buf, sizeof(buf));
1633			(void) alarm (0);
1634			if (recvurg)
1635				goto got_oob;
1636
1637			if (cnt > 0) {
1638				if (write(fileno(outstr), buf, cnt) != cnt)
1639					goto file_err;
1640				byte_count += cnt;
1641			}
1642		} while (cnt > 0);
1643		if (cnt < 0)
1644			goto data_err;
1645		transflag = 0;
1646		return (0);
1647
1648	case TYPE_E:
1649		reply(553, "TYPE E not implemented.");
1650		transflag = 0;
1651		return (-1);
1652
1653	case TYPE_A:
1654		while ((c = getc(instr)) != EOF) {
1655			if (recvurg)
1656				goto got_oob;
1657			byte_count++;
1658			if (c == '\n')
1659				bare_lfs++;
1660			while (c == '\r') {
1661				if (ferror(outstr))
1662					goto data_err;
1663				if ((c = getc(instr)) != '\n') {
1664					(void) putc ('\r', outstr);
1665					if (c == '\0' || c == EOF)
1666						goto contin2;
1667				}
1668			}
1669			(void) putc(c, outstr);
1670	contin2:	;
1671		}
1672		fflush(outstr);
1673		if (ferror(instr))
1674			goto data_err;
1675		if (ferror(outstr))
1676			goto file_err;
1677		transflag = 0;
1678		if (bare_lfs) {
1679			lreply(226,
1680			    "WARNING! %d bare linefeeds received in ASCII mode",
1681			    bare_lfs);
1682			printf("   File may not have transferred correctly.\r\n");
1683		}
1684		return (0);
1685	default:
1686		reply(550, "Unimplemented TYPE %d in receive_data", type);
1687		transflag = 0;
1688		return (-1);
1689	}
1690
1691data_err:
1692	transflag = 0;
1693	perror_reply(426, "Data Connection");
1694	return (-1);
1695
1696file_err:
1697	transflag = 0;
1698	perror_reply(452, "Error writing file");
1699	return (-1);
1700
1701got_oob:
1702	myoob();
1703	recvurg = 0;
1704	transflag = 0;
1705	return (-1);
1706}
1707
1708void
1709statfilecmd(filename)
1710	char *filename;
1711{
1712	FILE *fin;
1713	int c;
1714	int atstart;
1715	char line[LINE_MAX];
1716
1717	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1718	fin = ftpd_popen(line, "r");
1719	lreply(211, "status of %s:", filename);
1720	atstart = 1;
1721	while ((c = getc(fin)) != EOF) {
1722		if (c == '\n') {
1723			if (ferror(stdout)){
1724				perror_reply(421, "control connection");
1725				(void) ftpd_pclose(fin);
1726				dologout(1);
1727				/* NOTREACHED */
1728			}
1729			if (ferror(fin)) {
1730				perror_reply(551, filename);
1731				(void) ftpd_pclose(fin);
1732				return;
1733			}
1734			(void) putc('\r', stdout);
1735		}
1736		if (atstart && isdigit(c))
1737			(void) putc(' ', stdout);
1738		(void) putc(c, stdout);
1739		atstart = (c == '\n');
1740	}
1741	(void) ftpd_pclose(fin);
1742	reply(211, "End of Status");
1743}
1744
1745void
1746statcmd()
1747{
1748	union sockunion *su;
1749	u_char *a, *p;
1750	char hbuf[MAXHOSTNAMELEN];
1751	int ispassive;
1752
1753	lreply(211, "%s FTP server status:", hostname, version);
1754	printf("     %s\r\n", version);
1755	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1756	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1757	printf("     Connected to %s", remotehost);
1758	if (strcmp(remotehost, hbuf) != 0)
1759		printf(" (%s)", hbuf);
1760	printf("\r\n");
1761	if (logged_in) {
1762		if (guest)
1763			printf("     Logged in anonymously\r\n");
1764		else
1765			printf("     Logged in as %s\r\n", pw->pw_name);
1766	} else if (askpasswd)
1767		printf("     Waiting for password\r\n");
1768	else
1769		printf("     Waiting for user name\r\n");
1770	printf("     TYPE: %s", typenames[type]);
1771	if (type == TYPE_A || type == TYPE_E)
1772		printf(", FORM: %s", formnames[form]);
1773	if (type == TYPE_L)
1774#if NBBY == 8
1775		printf(" %d", NBBY);
1776#else
1777		printf(" %d", bytesize);	/* need definition! */
1778#endif
1779	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1780	    strunames[stru], modenames[mode]);
1781	ispassive = 0;
1782	if (data != -1)
1783		printf("     Data connection open\r\n");
1784	else if (pdata != -1) {
1785		printf("     in Passive mode\r\n");
1786		su = (union sockunion *)&pasv_addr;
1787		ispassive++;
1788		goto printaddr;
1789	} else if (usedefault == 0) {
1790		su = (union sockunion *)&data_dest;
1791printaddr:
1792		/* PASV/PORT */
1793		if (su->su_family == AF_INET) {
1794			if (ispassive)
1795				printf("211- PASV ");
1796			else
1797				printf("211- PORT ");
1798			a = (u_char *) &su->su_sin.sin_addr;
1799			p = (u_char *) &su->su_sin.sin_port;
1800			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1801			    a[0], a[1], a[2], a[3],
1802			    p[0], p[1]);
1803		}
1804
1805		/* LPSV/LPRT */
1806	    {
1807		int alen, af, i;
1808
1809		alen = 0;
1810		switch (su->su_family) {
1811		case AF_INET:
1812			a = (u_char *) &su->su_sin.sin_addr;
1813			p = (u_char *) &su->su_sin.sin_port;
1814			alen = sizeof(su->su_sin.sin_addr);
1815			af = 4;
1816			break;
1817		case AF_INET6:
1818			a = (u_char *) &su->su_sin6.sin6_addr;
1819			p = (u_char *) &su->su_sin6.sin6_port;
1820			alen = sizeof(su->su_sin6.sin6_addr);
1821			af = 6;
1822			break;
1823		default:
1824			af = 0;
1825			break;
1826		}
1827		if (af) {
1828			if (ispassive)
1829				printf("211- LPSV ");
1830			else
1831				printf("211- LPRT ");
1832			printf("(%u,%u", af, alen);
1833			for (i = 0; i < alen; i++)
1834				printf(",%u", a[i]);
1835			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1836		}
1837	    }
1838
1839		/* EPRT/EPSV */
1840	    {
1841		u_char af;
1842
1843		switch (su->su_family) {
1844		case AF_INET:
1845			af = 1;
1846			break;
1847		case AF_INET6:
1848			af = 2;
1849			break;
1850		default:
1851			af = 0;
1852			break;
1853		}
1854		if (af) {
1855			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1856			if (getnameinfo((struct sockaddr *)su, su->su_len,
1857			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1858			    NI_NUMERICHOST) == 0) {
1859				if (ispassive)
1860					printf("211- EPSV ");
1861				else
1862					printf("211- EPRT ");
1863				printf("(|%u|%s|%s|)\r\n",
1864					af, hbuf, pbuf);
1865			}
1866		}
1867	    }
1868	} else
1869		printf("     No data connection\r\n");
1870	reply(211, "End of status");
1871}
1872
1873void
1874fatal(s)
1875	char *s;
1876{
1877
1878	reply(451, "Error in server: %s", s);
1879	reply(221, "Closing connection due to server error.");
1880	dologout(0);
1881	/* NOTREACHED */
1882}
1883
1884void
1885reply(int n, const char *fmt, ...)
1886{
1887	char *buf, *p, *next;
1888	va_list ap;
1889
1890	va_start(ap, fmt);
1891	if (vasprintf(&buf, fmt, ap) == -1 || buf == NULL) {
1892		printf("412 Local resource failure: malloc\r\n");
1893		fflush(stdout);
1894		dologout(1);
1895	}
1896	next = buf;
1897	while ((p = strsep(&next, "\n\r"))) {
1898		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1899		if (debug)
1900			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1901			    (next != '\0') ? "-" : "", p);
1902	}
1903	(void)fflush(stdout);
1904	free(buf);
1905	va_end(ap);
1906}
1907
1908void
1909lreply(int n, const char *fmt, ...)
1910{
1911	va_list ap;
1912
1913	va_start(ap, fmt);
1914	(void)printf("%d- ", n);
1915	(void)vprintf(fmt, ap);
1916	va_end(ap);
1917	(void)printf("\r\n");
1918	(void)fflush(stdout);
1919	if (debug) {
1920		va_start(ap, fmt);
1921		syslog(LOG_DEBUG, "<--- %d- ", n);
1922		vsyslog(LOG_DEBUG, fmt, ap);
1923		va_end(ap);
1924	}
1925}
1926
1927static void
1928ack(s)
1929	char *s;
1930{
1931
1932	reply(250, "%s command successful.", s);
1933}
1934
1935void
1936nack(s)
1937	char *s;
1938{
1939
1940	reply(502, "%s command not implemented.", s);
1941}
1942
1943/* ARGSUSED */
1944void
1945yyerror(s)
1946	char *s;
1947{
1948	char *cp;
1949
1950	if ((cp = strchr(cbuf,'\n')))
1951		*cp = '\0';
1952	reply(500, "'%s': command not understood.", cbuf);
1953}
1954
1955void
1956delete(name)
1957	char *name;
1958{
1959	struct stat st;
1960
1961	LOGCMD("delete", name);
1962	if (stat(name, &st) < 0) {
1963		perror_reply(550, name);
1964		return;
1965	}
1966	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1967		if (rmdir(name) < 0) {
1968			perror_reply(550, name);
1969			return;
1970		}
1971		goto done;
1972	}
1973	if (unlink(name) < 0) {
1974		perror_reply(550, name);
1975		return;
1976	}
1977done:
1978	ack("DELE");
1979}
1980
1981void
1982cwd(path)
1983	char *path;
1984{
1985	FILE *message;
1986
1987	if (chdir(path) < 0)
1988		perror_reply(550, path);
1989	else {
1990		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
1991			char *cp, line[LINE_MAX];
1992
1993			while (fgets(line, sizeof(line), message) != NULL) {
1994				if ((cp = strchr(line, '\n')) != NULL)
1995					*cp = '\0';
1996				lreply(250, "%s", line);
1997			}
1998			(void) fflush(stdout);
1999			(void) fclose(message);
2000		}
2001		ack("CWD");
2002	}
2003}
2004
2005void
2006replydirname(name, message)
2007	const char *name, *message;
2008{
2009	char *p, *ep;
2010	char npath[MAXPATHLEN * 2];
2011
2012	p = npath;
2013	ep = &npath[sizeof(npath) - 1];
2014	while (*name) {
2015		if (*name == '"') {
2016			if (ep - p < 2)
2017				break;
2018			*p++ = *name++;
2019			*p++ = '"';
2020		} else {
2021			if (ep - p < 1)
2022				break;
2023			*p++ = *name++;
2024		}
2025	}
2026	*p = '\0';
2027	reply(257, "\"%s\" %s", npath, message);
2028}
2029
2030void
2031makedir(name)
2032	char *name;
2033{
2034
2035	LOGCMD("mkdir", name);
2036	if (mkdir(name, 0777) < 0)
2037		perror_reply(550, name);
2038	else
2039		replydirname(name, "directory created.");
2040}
2041
2042void
2043removedir(name)
2044	char *name;
2045{
2046
2047	LOGCMD("rmdir", name);
2048	if (rmdir(name) < 0)
2049		perror_reply(550, name);
2050	else
2051		ack("RMD");
2052}
2053
2054void
2055pwd()
2056{
2057	char path[MAXPATHLEN];
2058
2059	if (getcwd(path, sizeof(path)) == NULL)
2060		reply(550, "Can't get current directory: %s.", strerror(errno));
2061	else
2062		replydirname(path, "is current directory.");
2063}
2064
2065char *
2066renamefrom(name)
2067	char *name;
2068{
2069	struct stat st;
2070
2071	if (stat(name, &st) < 0) {
2072		perror_reply(550, name);
2073		return ((char *)0);
2074	}
2075	reply(350, "File exists, ready for destination name");
2076	return (name);
2077}
2078
2079void
2080renamecmd(from, to)
2081	char *from, *to;
2082{
2083
2084	LOGCMD2("rename", from, to);
2085	if (rename(from, to) < 0)
2086		perror_reply(550, "rename");
2087	else
2088		ack("RNTO");
2089}
2090
2091static void
2092dolog(sa)
2093	struct sockaddr *sa;
2094{
2095	char hbuf[sizeof(remotehost)];
2096
2097	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2098	(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2099
2100#ifdef HASSETPROCTITLE
2101	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2102	setproctitle("%s", proctitle);
2103#endif /* HASSETPROCTITLE */
2104
2105	if (logging)
2106		syslog(LOG_INFO, "connection from %s", remotehost);
2107}
2108
2109/*
2110 * Record logout in wtmp file and exit with supplied status.
2111 * NOTE: because this is called from signal handlers it cannot
2112 *       use stdio (or call other functions that use stdio).
2113 */
2114void
2115dologout(status)
2116	int status;
2117{
2118
2119	transflag = 0;
2120
2121	if (logged_in) {
2122		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2123		(void) seteuid((uid_t)0);
2124		ftpdlogwtmp(ttyline, "", "");
2125		if (doutmp)
2126			logout(utmp.ut_line);
2127	}
2128	/* beware of flushing buffers after a SIGPIPE */
2129	_exit(status);
2130}
2131
2132static void
2133sigurg(signo)
2134	int signo;
2135{
2136
2137	recvurg = 1;
2138}
2139
2140static void
2141myoob()
2142{
2143	char *cp;
2144
2145	/* only process if transfer occurring */
2146	if (!transflag)
2147		return;
2148	cp = tmpline;
2149	if (getline(cp, 7, stdin) == NULL) {
2150		reply(221, "You could at least say goodbye.");
2151		dologout(0);
2152	}
2153	upper(cp);
2154	if (strcmp(cp, "ABOR\r\n") == 0) {
2155		tmpline[0] = '\0';
2156		reply(426, "Transfer aborted. Data connection closed.");
2157		reply(226, "Abort successful");
2158	}
2159	if (strcmp(cp, "STAT\r\n") == 0) {
2160		tmpline[0] = '\0';
2161		if (file_size != (off_t) -1)
2162			reply(213, "Status: %qd of %qd bytes transferred",
2163			    byte_count, file_size);
2164		else
2165			reply(213, "Status: %qd bytes transferred", byte_count);
2166	}
2167}
2168
2169/*
2170 * Note: a response of 425 is not mentioned as a possible response to
2171 *	the PASV command in RFC959. However, it has been blessed as
2172 *	a legitimate response by Jon Postel in a telephone conversation
2173 *	with Rick Adams on 25 Jan 89.
2174 */
2175void
2176passive()
2177{
2178	int len, on;
2179	u_char *p, *a;
2180
2181	if (pw == NULL) {
2182		reply(530, "Please login with USER and PASS");
2183		return;
2184	}
2185	if (pdata >= 0)
2186		close(pdata);
2187	/*
2188	 * XXX
2189	 * At this point, it would be nice to have an algorithm that
2190	 * inserted a growing delay in an attack scenario.  Such a thing
2191	 * would look like continual passive sockets being opened, but
2192	 * nothing serious being done with them.  They're not used to
2193	 * move data; the entire attempt is just to use tcp FIN_WAIT
2194	 * resources.
2195	 */
2196	pdata = socket(AF_INET, SOCK_STREAM, 0);
2197	if (pdata < 0) {
2198		perror_reply(425, "Can't open passive connection");
2199		return;
2200	}
2201
2202#ifdef IP_PORTRANGE
2203	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2204	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2205	    (char *)&on, sizeof(on)) < 0)
2206		goto pasv_error;
2207#endif
2208
2209	pasv_addr = ctrl_addr;
2210	pasv_addr.su_sin.sin_port = 0;
2211	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2212		 pasv_addr.su_len) < 0)
2213		goto pasv_error;
2214
2215	len = sizeof(pasv_addr);
2216	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2217		goto pasv_error;
2218	if (listen(pdata, 1) < 0)
2219		goto pasv_error;
2220	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2221	p = (u_char *) &pasv_addr.su_sin.sin_port;
2222
2223	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2224	    a[1], a[2], a[3], p[0], p[1]);
2225	return;
2226
2227pasv_error:
2228	(void) seteuid((uid_t)pw->pw_uid);
2229	(void) close(pdata);
2230	pdata = -1;
2231	perror_reply(425, "Can't open passive connection");
2232	return;
2233}
2234
2235/*
2236 * convert protocol identifier to/from AF
2237 */
2238int
2239lpsvproto2af(int proto)
2240{
2241
2242	switch (proto) {
2243	case 4:	return AF_INET;
2244#ifdef INET6
2245	case 6:	return AF_INET6;
2246#endif
2247	default: return -1;
2248	}
2249}
2250
2251int
2252af2lpsvproto(int af)
2253{
2254
2255	switch (af) {
2256	case AF_INET:	return 4;
2257#ifdef INET6
2258	case AF_INET6:	return 6;
2259#endif
2260	default:	return -1;
2261	}
2262}
2263
2264int
2265epsvproto2af(int proto)
2266{
2267
2268	switch (proto) {
2269	case 1:	return AF_INET;
2270#ifdef INET6
2271	case 2:	return AF_INET6;
2272#endif
2273	default: return -1;
2274	}
2275}
2276
2277int
2278af2epsvproto(int af)
2279{
2280
2281	switch (af) {
2282	case AF_INET:	return 1;
2283#ifdef INET6
2284	case AF_INET6:	return 2;
2285#endif
2286	default:	return -1;
2287	}
2288}
2289
2290/*
2291 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2292 * 229 Entering Extended Passive Mode (|||port|)
2293 */
2294void
2295long_passive(char *cmd, int pf)
2296{
2297	int len, on;
2298	u_char *p, *a;
2299
2300	if (!logged_in) {
2301		syslog(LOG_NOTICE, "long passive but not logged in");
2302		reply(503, "Login with USER first.");
2303		return;
2304	}
2305
2306	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2307		/*
2308		 * XXX
2309		 * only EPRT/EPSV ready clients will understand this
2310		 */
2311		if (strcmp(cmd, "EPSV") != 0)
2312			reply(501, "Network protocol mismatch"); /*XXX*/
2313		else
2314			epsv_protounsupp("Network protocol mismatch");
2315
2316		return;
2317	}
2318
2319	if (pdata >= 0)
2320		close(pdata);
2321	/*
2322	 * XXX
2323	 * At this point, it would be nice to have an algorithm that
2324	 * inserted a growing delay in an attack scenario.  Such a thing
2325	 * would look like continual passive sockets being opened, but
2326	 * nothing serious being done with them.  They not used to move
2327	 * data; the entire attempt is just to use tcp FIN_WAIT
2328	 * resources.
2329	 */
2330	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2331	if (pdata < 0) {
2332		perror_reply(425, "Can't open passive connection");
2333		return;
2334	}
2335
2336	switch (ctrl_addr.su_family) {
2337	case AF_INET:
2338#ifdef IP_PORTRANGE
2339		on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2340		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2341		    (char *)&on, sizeof(on)) < 0)
2342			goto pasv_error;
2343#endif
2344		break;
2345	case AF_INET6:
2346#ifdef IPV6_PORTRANGE
2347		on = high_data_ports ? IPV6_PORTRANGE_HIGH
2348				     : IPV6_PORTRANGE_DEFAULT;
2349		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2350		    (char *)&on, sizeof(on)) < 0)
2351			goto pasv_error;
2352#endif
2353		break;
2354	}
2355
2356	pasv_addr = ctrl_addr;
2357	pasv_addr.su_port = 0;
2358	(void) seteuid((uid_t) 0);
2359	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2360		(void) seteuid((uid_t) pw->pw_uid);
2361		goto pasv_error;
2362	}
2363	(void) seteuid((uid_t) pw->pw_uid);
2364	len = pasv_addr.su_len;
2365	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2366		goto pasv_error;
2367	if (listen(pdata, 1) < 0)
2368		goto pasv_error;
2369	p = (u_char *) &pasv_addr.su_port;
2370
2371	if (strcmp(cmd, "LPSV") == 0) {
2372		switch (pasv_addr.su_family) {
2373		case AF_INET:
2374			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2375			reply(228,
2376			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2377			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2378			return;
2379		case AF_INET6:
2380			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2381			reply(228,
2382			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2383			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2384				6, 16, a[0], a[1], a[2], a[3], a[4],
2385				a[5], a[6], a[7], a[8], a[9], a[10],
2386				a[11], a[12], a[13], a[14], a[15],
2387				2, p[0], p[1]);
2388			return;
2389		}
2390	} else if (strcmp(cmd, "EPSV") == 0) {
2391		switch (pasv_addr.su_family) {
2392		case AF_INET:
2393		case AF_INET6:
2394			reply(229, "Entering Extended Passive Mode (|||%u|)",
2395			    ntohs(pasv_addr.su_port));
2396			return;
2397		}
2398	} else {
2399		/* more proper error code? */
2400	}
2401
2402  pasv_error:
2403	(void) close(pdata);
2404	pdata = -1;
2405	perror_reply(425, "Can't open passive connection");
2406	return;
2407}
2408
2409/*
2410 * EPRT |proto|addr|port|
2411 */
2412int
2413extended_port(const char *arg)
2414{
2415	char *tmp = NULL;
2416	char *result[3];
2417	char *p, *q;
2418	char delim;
2419	struct addrinfo hints;
2420	struct addrinfo *res = NULL;
2421	int i;
2422	unsigned long proto;
2423
2424	if (epsvall) {
2425		reply(501, "EPRT disallowed after EPSV ALL");
2426		return -1;
2427	}
2428
2429	usedefault = 0;
2430	if (pdata >= 0) {
2431		(void) close(pdata);
2432		pdata = -1;
2433	}
2434
2435	tmp = strdup(arg);
2436	if (!tmp) {
2437		fatal("not enough core.");
2438		/*NOTREACHED*/
2439	}
2440	p = tmp;
2441	delim = p[0];
2442	p++;
2443	memset(result, 0, sizeof(result));
2444	for (i = 0; i < 3; i++) {
2445		q = strchr(p, delim);
2446		if (!q || *q != delim)
2447			goto parsefail;
2448		*q++ = '\0';
2449		result[i] = p;
2450		p = q;
2451	}
2452
2453	/* some more sanity check */
2454	p = NULL;
2455	(void)strtoul(result[2], &p, 10);
2456	if (!*result[2] || *p)
2457		goto protounsupp;
2458	p = NULL;
2459	proto = strtoul(result[0], &p, 10);
2460	if (!*result[0] || *p)
2461		goto protounsupp;
2462
2463	memset(&hints, 0, sizeof(hints));
2464	hints.ai_family = epsvproto2af((int)proto);
2465	if (hints.ai_family < 0)
2466		goto protounsupp;
2467	hints.ai_socktype = SOCK_STREAM;
2468	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2469	if (getaddrinfo(result[1], result[2], &hints, &res))
2470		goto parsefail;
2471	if (res->ai_next)
2472		goto parsefail;
2473	if (sizeof(data_dest) < res->ai_addrlen)
2474		goto parsefail;
2475	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2476	if (his_addr.su_family == AF_INET6 &&
2477	    data_dest.su_family == AF_INET6) {
2478		/* XXX more sanity checks! */
2479		data_dest.su_sin6.sin6_scope_id =
2480		    his_addr.su_sin6.sin6_scope_id;
2481	}
2482	if (pdata >= 0) {
2483		(void) close(pdata);
2484		pdata = -1;
2485	}
2486	reply(200, "EPRT command successful.");
2487
2488	if (tmp)
2489		free(tmp);
2490	if (res)
2491		freeaddrinfo(res);
2492	return 0;
2493
2494parsefail:
2495	reply(500, "Invalid argument, rejected.");
2496	usedefault = 1;
2497	if (tmp)
2498		free(tmp);
2499	if (res)
2500		freeaddrinfo(res);
2501	return -1;
2502
2503protounsupp:
2504	epsv_protounsupp("Protocol not supported");
2505	usedefault = 1;
2506	if (tmp)
2507		free(tmp);
2508	if (res)
2509		freeaddrinfo(res);
2510	return -1;
2511}
2512
2513/*
2514 * 522 Protocol not supported (proto,...)
2515 * as we assume address family for control and data connections are the same,
2516 * we do not return the list of address families we support - instead, we
2517 * return the address family of the control connection.
2518 */
2519void
2520epsv_protounsupp(const char *message)
2521{
2522	int proto;
2523
2524	proto = af2epsvproto(ctrl_addr.su_family);
2525	if (proto < 0)
2526		reply(501, "%s", message);	/*XXX*/
2527	else
2528		reply(522, "%s, use (%d)", message, proto);
2529}
2530
2531/*
2532 * Generate unique name for file with basename "local".
2533 * The file named "local" is already known to exist.
2534 * Generates failure reply on error.
2535 */
2536static int
2537guniquefd(local, nam)
2538	char *local;
2539	char **nam;
2540{
2541	static char new[MAXPATHLEN];
2542	struct stat st;
2543	int count, len, fd;
2544	char *cp;
2545
2546	cp = strrchr(local, '/');
2547	if (cp)
2548		*cp = '\0';
2549	if (stat(cp ? local : ".", &st) < 0) {
2550		perror_reply(553, cp ? local : ".");
2551		return (-1);
2552	}
2553	if (cp)
2554		*cp = '/';
2555	len = strlcpy(new, local, sizeof(new));
2556	if (len+2+1 >= sizeof(new)-1)
2557		return (-1);
2558	cp = new + len;
2559	*cp++ = '.';
2560	for (count = 1; count < 100; count++) {
2561		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2562		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2563		if (fd == -1)
2564			continue;
2565		if (nam)
2566			*nam = new;
2567		return (fd);
2568	}
2569	reply(452, "Unique file name cannot be created.");
2570	return (-1);
2571}
2572
2573/*
2574 * Format and send reply containing system error number.
2575 */
2576void
2577perror_reply(code, string)
2578	int code;
2579	char *string;
2580{
2581
2582	reply(code, "%s: %s.", string, strerror(errno));
2583}
2584
2585static char *onefile[] = {
2586	"",
2587	0
2588};
2589
2590void
2591send_file_list(whichf)
2592	char *whichf;
2593{
2594	struct stat st;
2595	DIR *dirp = NULL;
2596	struct dirent *dir;
2597	FILE *dout = NULL;
2598	char **dirlist;
2599	char *dirname;
2600	int simple = 0;
2601	volatile int freeglob = 0;
2602	glob_t gl;
2603
2604	if (strpbrk(whichf, "~{[*?") != NULL) {
2605		memset(&gl, 0, sizeof(gl));
2606		freeglob = 1;
2607		if (glob(whichf,
2608		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2609		    0, &gl)) {
2610			reply(550, "not found");
2611			goto out;
2612		} else if (gl.gl_pathc == 0) {
2613			errno = ENOENT;
2614			perror_reply(550, whichf);
2615			goto out;
2616		}
2617		dirlist = gl.gl_pathv;
2618	} else {
2619		onefile[0] = whichf;
2620		dirlist = onefile;
2621		simple = 1;
2622	}
2623
2624	while ((dirname = *dirlist++)) {
2625		if (stat(dirname, &st) < 0) {
2626			/*
2627			 * If user typed "ls -l", etc, and the client
2628			 * used NLST, do what the user meant.
2629			 */
2630			if (dirname[0] == '-' && *dirlist == NULL &&
2631			    transflag == 0) {
2632				retrieve("/bin/ls %s", dirname);
2633				goto out;
2634			}
2635			perror_reply(550, whichf);
2636			if (dout != NULL) {
2637				(void) fclose(dout);
2638				transflag = 0;
2639				data = -1;
2640				pdata = -1;
2641			}
2642			goto out;
2643		}
2644
2645		if (S_ISREG(st.st_mode)) {
2646			if (dout == NULL) {
2647				dout = dataconn("file list", (off_t)-1, "w");
2648				if (dout == NULL)
2649					goto out;
2650				transflag++;
2651			}
2652			fprintf(dout, "%s%s\n", dirname,
2653				type == TYPE_A ? "\r" : "");
2654			byte_count += strlen(dirname) + 1;
2655			continue;
2656		} else if (!S_ISDIR(st.st_mode))
2657			continue;
2658
2659		if ((dirp = opendir(dirname)) == NULL)
2660			continue;
2661
2662		while ((dir = readdir(dirp)) != NULL) {
2663			char nbuf[MAXPATHLEN];
2664
2665			if (recvurg) {
2666				myoob();
2667				recvurg = 0;
2668				transflag = 0;
2669				goto out;
2670			}
2671
2672			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2673				continue;
2674			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2675			    dir->d_namlen == 2)
2676				continue;
2677
2678			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2679				 dir->d_name);
2680
2681			/*
2682			 * We have to do a stat to insure it's
2683			 * not a directory or special file.
2684			 */
2685			if (simple || (stat(nbuf, &st) == 0 &&
2686			    S_ISREG(st.st_mode))) {
2687				if (dout == NULL) {
2688					dout = dataconn("file list", (off_t)-1,
2689						"w");
2690					if (dout == NULL)
2691						goto out;
2692					transflag++;
2693				}
2694				if (nbuf[0] == '.' && nbuf[1] == '/')
2695					fprintf(dout, "%s%s\n", &nbuf[2],
2696						type == TYPE_A ? "\r" : "");
2697				else
2698					fprintf(dout, "%s%s\n", nbuf,
2699						type == TYPE_A ? "\r" : "");
2700				byte_count += strlen(nbuf) + 1;
2701			}
2702		}
2703		(void) closedir(dirp);
2704	}
2705
2706	if (dout == NULL)
2707		reply(550, "No files found.");
2708	else if (ferror(dout) != 0)
2709		perror_reply(550, "Data connection");
2710	else
2711		reply(226, "Transfer complete.");
2712
2713	transflag = 0;
2714	if (dout != NULL)
2715		(void) fclose(dout);
2716	else {
2717		if (pdata >= 0)
2718			close(pdata);
2719	}
2720	data = -1;
2721	pdata = -1;
2722out:
2723	if (freeglob) {
2724		freeglob = 0;
2725		globfree(&gl);
2726	}
2727}
2728
2729static void
2730reapchild(signo)
2731	int signo;
2732{
2733	int save_errno = errno;
2734	int rval;
2735
2736	do {
2737		rval = waitpid(-1, NULL, WNOHANG);
2738	} while (rval > 0 || (rval == -1 && errno == EINTR));
2739	errno = save_errno;
2740}
2741
2742void
2743logxfer(name, size, start)
2744	char *name;
2745	off_t size;
2746	time_t start;
2747{
2748	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2749	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2750	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2751	char *vpw;
2752	time_t now;
2753	int len;
2754
2755	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2756		time(&now);
2757
2758		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2759		if (vpw == NULL)
2760			return;
2761
2762		snprintf(path, sizeof(path), "%s/%s", dir, name);
2763		if (realpath(path, rpath) == NULL)
2764			strlcpy(rpath, path, sizeof(rpath));
2765		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2766
2767		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2768		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2769
2770		len = snprintf(buf, sizeof(buf),
2771		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2772		    ctime(&now), now - start + (now == start),
2773		    vremotehost, (long long) size, vpath,
2774		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2775		    'o', ((guest) ? 'a' : 'r'),
2776		    vpw, 0 /* none yet */,
2777		    ((guest) ? "*" : pw->pw_name), dhostname);
2778		if (len >= sizeof(buf)) {
2779			len = sizeof(buf);
2780			buf[sizeof(buf) - 1] = '\n';
2781		}
2782		write(statfd, buf, len);
2783		free(vpw);
2784	}
2785}
2786
2787#if defined(TCPWRAPPERS)
2788static int
2789check_host(sa)
2790	struct sockaddr *sa;
2791{
2792	struct sockaddr_in *sin;
2793	struct hostent *hp;
2794	char *addr;
2795
2796	if (sa->sa_family != AF_INET)
2797		return 1;	/*XXX*/
2798
2799	sin = (struct sockaddr_in *)sa;
2800	hp = gethostbyaddr((char *)&sin->sin_addr,
2801	    sizeof(struct in_addr), AF_INET);
2802	addr = inet_ntoa(sin->sin_addr);
2803	if (hp) {
2804		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2805			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2806			    hp->h_name, addr);
2807			return (0);
2808		}
2809	} else {
2810		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2811			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2812			return (0);
2813		}
2814	}
2815	return (1);
2816}
2817#endif	/* TCPWRAPPERS */
2818
2819/*
2820 * Allocate space and return a copy of the specified dir.
2821 * If 'dir' begins with a tilde (~), expand it.
2822 */
2823char *
2824copy_dir(dir, pw)
2825	char *dir;
2826	struct passwd *pw;
2827{
2828	char *cp;
2829	char *newdir;
2830	char *user = NULL;
2831	size_t dirsiz;
2832
2833	/* Nothing to expand */
2834	if (dir[0] !=  '~')
2835		return (strdup(dir));
2836
2837	/* "dir" is of form ~user/some/dir, lookup user. */
2838	if (dir[1] != '/' && dir[1] != '\0') {
2839		if ((cp = strchr(dir + 1, '/')) == NULL)
2840		    cp = dir + strlen(dir);
2841		if ((user = malloc(cp - dir)) == NULL)
2842			return (NULL);
2843		strlcpy(user, dir + 1, cp - dir);
2844
2845		/* Only do lookup if it is a different user. */
2846		if (strcmp(user, pw->pw_name) != 0) {
2847			if ((pw = getpwnam(user)) == NULL) {
2848				/* No such user, interpret literally */
2849				free(user);
2850				return(strdup(dir));
2851			}
2852		}
2853	}
2854
2855	/*
2856	 * If there is no directory separator (/) then it is just pw_dir.
2857	 * Otherwise, replace ~foo with  pw_dir.
2858	 */
2859	if ((cp = strchr(dir + 1, '/')) == NULL) {
2860		newdir = strdup(pw->pw_dir);
2861	} else {
2862		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2863		if ((newdir = malloc(dirsiz)) == NULL) {
2864			free(user);
2865			return (NULL);
2866		}
2867		strlcpy(newdir, pw->pw_dir, dirsiz);
2868		strlcat(newdir, cp, dirsiz);
2869	}
2870
2871	if (user)
2872		free(user);
2873	return(newdir);
2874}
2875