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