ftpd.c revision 1.175
121259Swollman/*	$OpenBSD: ftpd.c,v 1.175 2007/03/01 20:06:27 otto Exp $	*/
221259Swollman/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
321259Swollman
421259Swollman/*
521259Swollman * Copyright (C) 1997 and 1998 WIDE Project.
621259Swollman * All rights reserved.
721259Swollman *
821259Swollman * Redistribution and use in source and binary forms, with or without
921259Swollman * modification, are permitted provided that the following conditions
1021259Swollman * are met:
1121259Swollman * 1. Redistributions of source code must retain the above copyright
1221259Swollman *    notice, this list of conditions and the following disclaimer.
1321259Swollman * 2. Redistributions in binary form must reproduce the above copyright
1421259Swollman *    notice, this list of conditions and the following disclaimer in the
1521259Swollman *    documentation and/or other materials provided with the distribution.
1621259Swollman * 3. Neither the name of the project nor the names of its contributors
1721259Swollman *    may be used to endorse or promote products derived from this software
1821259Swollman *    without specific prior written permission.
1921259Swollman *
2021259Swollman * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2121259Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2221259Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2321259Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2421259Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2521259Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2621259Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2721259Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2821259Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2921259Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3021259Swollman * SUCH DAMAGE.
3121259Swollman */
3221259Swollman
3321259Swollman/*
3450477Speter * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
3521259Swollman *	The Regents of the University of California.  All rights reserved.
3621259Swollman *
3721259Swollman * Redistribution and use in source and binary forms, with or without
3821259Swollman * modification, are permitted provided that the following conditions
3921259Swollman * are met:
4021259Swollman * 1. Redistributions of source code must retain the above copyright
4121259Swollman *    notice, this list of conditions and the following disclaimer.
4221259Swollman * 2. Redistributions in binary form must reproduce the above copyright
4321259Swollman *    notice, this list of conditions and the following disclaimer in the
4421259Swollman *    documentation and/or other materials provided with the distribution.
4521259Swollman * 3. Neither the name of the University nor the names of its contributors
4621259Swollman *    may be used to endorse or promote products derived from this software
4721259Swollman *    without specific prior written permission.
4821259Swollman *
4921259Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5021259Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5121259Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5221259Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5321259Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5421259Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55108533Sschweikh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5621259Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5721259Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5821259Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5921259Swollman * SUCH DAMAGE.
60108533Sschweikh */
6121259Swollman
6221259Swollman#ifndef lint
6321259Swollmanstatic const char copyright[] =
6421259Swollman"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
6521259Swollman	The Regents of the University of California.  All rights reserved.\n";
6621259Swollman#endif /* not lint */
6721259Swollman
6821259Swollman#ifndef lint
6921259Swollman#if 0
7083366Sjulianstatic const char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
7121259Swollman#else
7285074Srustatic const char rcsid[] =
7321259Swollman    "$OpenBSD: ftpd.c,v 1.175 2007/03/01 20:06:27 otto Exp $";
7421259Swollman#endif
7521259Swollman#endif /* not lint */
7621259Swollman
77101849Srwatson/*
7821259Swollman * FTP server.
7921259Swollman */
8069224Sjlemon#include <sys/param.h>
8169152Sjlemon#include <sys/stat.h>
8269224Sjlemon#include <sys/ioctl.h>
8374914Sjhb#include <sys/socket.h>
8474914Sjhb#include <sys/wait.h>
8583130Sjlemon#include <sys/mman.h>
8669152Sjlemon
8760938Sjake#include <netinet/in.h>
8860938Sjake#include <netinet/in_systm.h>
8960938Sjake#include <netinet/ip.h>
9072084Sphk#include <netinet/tcp.h>
9121259Swollman
9221259Swollman#define	FTP_NAMES
9321259Swollman#include <arpa/ftp.h>
9421259Swollman#include <arpa/inet.h>
9521259Swollman#include <arpa/telnet.h>
9621259Swollman
9721259Swollman#include <bsd_auth.h>
9821259Swollman#include <ctype.h>
9921259Swollman#include <dirent.h>
10021259Swollman#include <errno.h>
10169152Sjlemon#include <fcntl.h>
10221259Swollman#include <glob.h>
10321259Swollman#include <limits.h>
10421259Swollman#include <login_cap.h>
10521259Swollman#include <netdb.h>
10621259Swollman#include <pwd.h>
10721259Swollman#include <signal.h>
10821259Swollman#include <stdarg.h>
10984380Smjacob#include <stdio.h>
11084380Smjacob#include <stdlib.h>
11184380Smjacob#include <string.h>
11284380Smjacob#include <syslog.h>
11386797Sluigi#include <time.h>
11486797Sluigi#include <vis.h>
11586797Sluigi#include <unistd.h>
11686797Sluigi#include <util.h>
11786797Sluigi#include <utmp.h>
11886797Sluigi#include <poll.h>
11986797Sluigi
12086797Sluigi#if defined(TCPWRAPPERS)
12186797Sluigi#include <tcpd.h>
12286797Sluigi#endif	/* TCPWRAPPERS */
12386797Sluigi
12486797Sluigi#include "pathnames.h"
12586797Sluigi#include "extern.h"
12686797Sluigi#include "monitor.h"
12786797Sluigi
12884380Smjacobstatic char version[] = "Version 6.6/OpenBSD";
12921259Swollman
13021259Swollmanextern	off_t restart_point;
13121259Swollmanextern	char cbuf[];
13260938Sjake
13321259Swollmanunion sockunion ctrl_addr;
13483130Sjlemonunion sockunion data_source;
13583130Sjlemonunion sockunion data_dest;
13621259Swollmanunion sockunion his_addr;
13721259Swollmanunion sockunion pasv_addr;
13821259Swollman
13921259Swollmansigset_t allsigs;
140106931Ssam
141102052Ssobomaxint	daemon_mode = 0;
14283624Sjlemonint	data;
14383624Sjlemonint	logged_in;
14421259Swollmanstruct	passwd *pw;
14521259Swollmanint	debug = 0;
14621259Swollmanint	timeout = 900;    /* timeout after 15 minutes of inactivity */
14721259Swollmanint	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
14821404Swollmanint	logging;
14921404Swollmanint	anon_ok = 1;
15021259Swollmanint	anon_only = 0;
15121259Swollmanint	multihome = 0;
15292725Salfredint	guest;
15392725Salfredint	stats;
154106931Ssamint	statfd = -1;
155106931Ssamint	portcheck = 1;
15621259Swollmanint	dochroot;
15792725Salfredint	type;
15821259Swollmanint	form;
15992725Salfredint	stru;			/* avoid C keyword */
16021259Swollmanint	mode;
16192725Salfredint	doutmp = 0;		/* update utmp file */
16221259Swollmanint	usedefault = 1;		/* for data transfers */
16392725Salfredint	pdata = -1;		/* for passive mode */
16421259Swollmanint	family = AF_UNSPEC;
16592725Salfredvolatile sig_atomic_t transflag;
16621259Swollmanoff_t	file_size;
16792725Salfredoff_t	byte_count;
16821259Swollman#if !defined(CMASK) || CMASK == 0
16992725Salfred#undef CMASK
17021259Swollman#define CMASK 022
17192725Salfred#endif
17221259Swollmanmode_t	defumask = CMASK;		/* default umask value */
17392725Salfredint	umaskchange = 1;		/* allow user to change umask value. */
17421404Swollmanchar	tmpline[7];
17592725Salfredchar	hostname[MAXHOSTNAMELEN];
17621259Swollmanchar	remotehost[MAXHOSTNAMELEN];
17721259Swollmanchar	dhostname[MAXHOSTNAMELEN];
17852904Sshinchar	*guestpw;
17984931Sfjoechar	ttyline[20];
180100992Srwatson#if 0
18121259Swollmanchar	*tty = ttyline;		/* for klogin */
18269152Sjlemon#endif
18392725Salfredstatic struct utmp utmp;	/* for utmp */
18421259Swollmanstatic	login_cap_t *lc;
18521259Swollmanstatic	auth_session_t *as;
18621259Swollmanstatic	volatile sig_atomic_t recvurg;
18721259Swollman
18821259Swollman#if defined(TCPWRAPPERS)
18921259Swollmanint	allow_severity = LOG_INFO;
19021259Swollmanint	deny_severity = LOG_NOTICE;
19121259Swollman#endif	/* TCPWRAPPERS */
19258698Sjlemon
19321259Swollmanchar	*ident = NULL;
19421259Swollman
19521259Swollman
19621259Swollmanint epsvall = 0;
19721259Swollman
19821259Swollman/*
19921259Swollman * Timeout intervals for retrying connections
20021259Swollman * to hosts that don't accept PORT cmds.  This
20121259Swollman * is a kludge, but given the problems with TCP...
20221259Swollman */
20321259Swollman#define	SWAITMAX	90	/* wait at most 90 seconds */
20421259Swollman#define	SWAITINT	5	/* interval between retries */
20521259Swollman
20621259Swollmanint	swaitmax = SWAITMAX;
20721259Swollmanint	swaitint = SWAITINT;
20821259Swollman
20953541Sshin#ifdef HASSETPROCTITLE
21053541Sshinchar	proctitle[BUFSIZ];	/* initial part of title */
21153541Sshin#endif /* HASSETPROCTITLE */
21253541Sshin
21321259Swollman#define LOGCMD(cmd, file) \
21421259Swollman	if (logging > 1) \
21521259Swollman	    syslog(LOG_INFO,"%s %s%s", cmd, \
21621259Swollman		*(file) == '/' ? "" : curdir(), file);
21721259Swollman#define LOGCMD2(cmd, file1, file2) \
21821259Swollman	 if (logging > 1) \
21921259Swollman	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
22021259Swollman		*(file1) == '/' ? "" : curdir(), file1, \
22121259Swollman		*(file2) == '/' ? "" : curdir(), file2);
22221259Swollman#define LOGBYTES(cmd, file, cnt) \
22321259Swollman	if (logging > 1) { \
22421259Swollman		if (cnt == (off_t)-1) \
22572200Sbmilekic		    syslog(LOG_INFO,"%s %s%s", cmd, \
22672200Sbmilekic			*(file) == '/' ? "" : curdir(), file); \
22769152Sjlemon		else \
22869152Sjlemon		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
22969152Sjlemon			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
23021259Swollman	}
23169152Sjlemon
23269152Sjlemonstatic void	 ack(char *);
23369152Sjlemonstatic void	 sigurg(int);
23469152Sjlemonstatic void	 myoob(void);
23569152Sjlemonstatic int	 checkuser(char *, char *);
23669152Sjlemonstatic FILE	*dataconn(char *, off_t, char *);
23769152Sjlemonstatic void	 dolog(struct sockaddr *);
23869152Sjlemonstatic char	*copy_dir(char *, struct passwd *);
23969152Sjlemonstatic char	*curdir(void);
24069152Sjlemonstatic void	 end_login(void);
24169152Sjlemonstatic FILE	*getdatasock(char *);
24269152Sjlemonstatic int	 guniquefd(char *, char **);
24369152Sjlemonstatic void	 lostconn(int);
24469152Sjlemonstatic void	 sigquit(int);
24569152Sjlemonstatic int	 receive_data(FILE *, FILE *);
24669152Sjlemonstatic void	 replydirname(const char *, const char *);
24769152Sjlemonstatic int	 send_data(FILE *, FILE *, off_t, off_t, int);
24869152Sjlemonstatic struct passwd *
24969152Sjlemon		 sgetpwnam(char *, struct passwd *);
25069152Sjlemonstatic void	 reapchild(int);
25169152Sjlemon#if defined(TCPWRAPPERS)
25269152Sjlemonstatic int	 check_host(struct sockaddr *);
25369152Sjlemon#endif /* TCPWRAPPERS */
25469152Sjlemonstatic void	 usage(void);
25569152Sjlemon
25669152Sjlemonvoid	 logxfer(char *, off_t, time_t);
25769152Sjlemonvoid	 set_slave_signals(void);
25869152Sjlemon
25969152Sjlemonstatic char *
26069152Sjlemoncurdir(void)
26169152Sjlemon{
26269152Sjlemon	static char path[MAXPATHLEN+1];	/* path + '/' */
26369152Sjlemon
26469152Sjlemon	if (getcwd(path, sizeof(path)-1) == NULL)
26569152Sjlemon		return ("");
26669152Sjlemon	if (path[1] != '\0')		/* special case for root dir. */
26769152Sjlemon		strlcat(path, "/", sizeof path);
26869152Sjlemon	/* For guest account, skip / since it's chrooted */
26969152Sjlemon	return (guest ? path+1 : path);
27069152Sjlemon}
27169152Sjlemon
27269152Sjlemonchar *argstr = "AdDhnlMSt:T:u:UvP46";
27369152Sjlemon
27469152Sjlemonstatic void
27569152Sjlemonusage(void)
27669152Sjlemon{
27769152Sjlemon	syslog(LOG_ERR,
27869152Sjlemon	    "usage: ftpd [-46ADdlMnPSU] [-T maxtimeout] [-t timeout] [-u mask]");
27969152Sjlemon	exit(2);
28069152Sjlemon}
28169152Sjlemon
28269152Sjlemonint
28369152Sjlemonmain(int argc, char *argv[])
28469152Sjlemon{
28569152Sjlemon	socklen_t addrlen;
28669152Sjlemon	int ch, on = 1, tos;
28769152Sjlemon	char *cp, line[LINE_MAX];
28869152Sjlemon	FILE *fp;
28955205Speter	struct hostent *hp;
29069152Sjlemon	struct sigaction sa;
29169152Sjlemon	int error = 0;
29221259Swollman
29335210Sbde	tzset();		/* in case no timezone database in ~ftp */
29469152Sjlemon	sigfillset(&allsigs);	/* used to block signals while root */
29521259Swollman	sigemptyset(&sa.sa_mask);
29669152Sjlemon	sa.sa_flags = SA_RESTART;
29721259Swollman
29869152Sjlemon	while ((ch = getopt(argc, argv, argstr)) != -1) {
29969152Sjlemon		switch (ch) {
30069152Sjlemon		case 'A':
30169152Sjlemon			anon_only = 1;
30269152Sjlemon			break;
30369152Sjlemon
30469152Sjlemon		case 'd':
30569152Sjlemon		case 'v':		/* deprecated */
30669152Sjlemon			debug = 1;
30769152Sjlemon			break;
30869152Sjlemon
30969152Sjlemon		case 'D':
31069152Sjlemon			daemon_mode = 1;
31169152Sjlemon			break;
31269152Sjlemon
31386364Sjhb		case 'P':
31496173Simp			portcheck = 0;
31569152Sjlemon			break;
31621259Swollman
31721259Swollman		case 'h':		/* deprecated */
31849459Sbrian			break;
31949459Sbrian
32049459Sbrian		case 'l':
32149459Sbrian			logging++;	/* > 1 == extra logging */
32249459Sbrian			break;
32349459Sbrian
32449459Sbrian		case 'M':
32555205Speter			multihome = 1;
32621259Swollman			break;
32721259Swollman
32821259Swollman		case 'n':
32921259Swollman			anon_ok = 0;
33021259Swollman			break;
33121259Swollman
33221259Swollman		case 'S':
33321259Swollman			stats = 1;
33421259Swollman			break;
33521259Swollman
33621259Swollman		case 't':
33721259Swollman			timeout = atoi(optarg);
33867334Sjoe			if (maxtimeout < timeout)
33921259Swollman				maxtimeout = timeout;
34060938Sjake			break;
34121259Swollman
34292725Salfred		case 'T':
34321259Swollman			maxtimeout = atoi(optarg);
34447254Spb			if (timeout > maxtimeout)
34521259Swollman				timeout = maxtimeout;
34621259Swollman			break;
34721259Swollman
34821259Swollman		case 'u':
34928845Sjulian		    {
35092725Salfred			long val = 0;
351108033Shsu			char *p;
35221259Swollman			umaskchange = 0;
35321259Swollman
35421259Swollman			val = strtol(optarg, &p, 8);
35553541Sshin			if (*p != '\0' || val < 0 || (val & ~ACCESSPERMS)) {
35653541Sshin				syslog(LOG_ERR,
35753541Sshin				    "%s is a bad value for -u, aborting..",
358108033Shsu				    optarg);
359108033Shsu				exit(2);
360108033Shsu			} else
361108033Shsu				defumask = val;
362108033Shsu			break;
363108033Shsu		    }
36421404Swollman
36552904Sshin		case 'U':
36652904Sshin			doutmp = 1;
367108470Sschweikh			break;
36853541Sshin
36952904Sshin		case '4':
37052904Sshin			family = AF_INET;
37152904Sshin			break;
37252904Sshin
37360938Sjake		case '6':
37452904Sshin			family = AF_INET6;
37552904Sshin			break;
37652904Sshin
37752904Sshin		default:
37852904Sshin			usage();
37921404Swollman			break;
38021404Swollman		}
38121404Swollman	}
38221404Swollman
38321404Swollman	(void) freopen(_PATH_DEVNULL, "w", stderr);
38421404Swollman
38572084Sphk	/*
38621434Swollman	 * LOG_NDELAY sets up the logging connection immediately,
38721434Swollman	 * necessary for anonymous ftp's that chroot and can't do it later.
38821434Swollman	 */
38921434Swollman	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
39021434Swollman
39121404Swollman	if (getpwnam(FTPD_PRIVSEP_USER) == NULL) {
39221404Swollman		syslog(LOG_ERR, "privilege separation user %s not found",
39355205Speter		    FTPD_PRIVSEP_USER);
394108036Shsu		exit(1);
395108036Shsu	}
396108036Shsu	endpwent();
397108036Shsu
398108036Shsu	if (daemon_mode) {
399108036Shsu		int *fds, i, fd;
400108036Shsu		struct pollfd *pfds;
401108036Shsu		struct addrinfo hints, *res, *res0;
402108036Shsu		nfds_t n;
403108036Shsu
40446568Speter		/*
40521259Swollman		 * Detach from parent.
406108036Shsu		 */
407108036Shsu		if (daemon(1, 1) < 0) {
408108036Shsu			syslog(LOG_ERR, "failed to become a daemon");
409108036Shsu			exit(1);
410108036Shsu		}
411108033Shsu		sa.sa_handler = reapchild;
412108033Shsu		(void) sigaction(SIGCHLD, &sa, NULL);
413108172Shsu
414108298Shsu		memset(&hints, 0, sizeof(hints));
415108298Shsu		hints.ai_family = family;
416108172Shsu		hints.ai_socktype = SOCK_STREAM;
417108172Shsu		hints.ai_protocol = IPPROTO_TCP;
418108172Shsu		hints.ai_flags = AI_PASSIVE;
419108172Shsu		error = getaddrinfo(NULL, "ftp", &hints, &res0);
420108172Shsu		if (error) {
42183130Sjlemon			syslog(LOG_ERR, "%s", gai_strerror(error));
42287914Sjlemon			exit(1);
42383130Sjlemon		}
42483130Sjlemon
42583130Sjlemon		n = 0;
42683130Sjlemon		for (res = res0; res; res = res->ai_next)
42783130Sjlemon			n++;
42883130Sjlemon
42983130Sjlemon		fds = malloc(n * sizeof(int));
43083130Sjlemon		pfds = malloc(n * sizeof(struct pollfd));
43121259Swollman		if (!fds || !pfds) {
43283130Sjlemon			syslog(LOG_ERR, "%s", strerror(errno));
43321259Swollman			exit(1);
43471791Speter		}
43521259Swollman
43621259Swollman		/*
43792725Salfred		 * Open sockets, bind it to the FTP port, and start
43892725Salfred		 * listening.
43992725Salfred		 */
44092725Salfred		n = 0;
44192725Salfred		for (res = res0; res; res = res->ai_next) {
44292725Salfred			fds[n] = socket(res->ai_family, res->ai_socktype,
443103900Sbrooks			    res->ai_protocol);
44492725Salfred			if (fds[n] < 0)
44592725Salfred				continue;
44692725Salfred
44792725Salfred			if (setsockopt(fds[n], SOL_SOCKET, SO_REUSEADDR,
44892725Salfred			    &on, sizeof(on)) < 0) {
44992725Salfred				close(fds[n]);
45092725Salfred				fds[n] = -1;
45192725Salfred				continue;
45292725Salfred			}
45321259Swollman
45492725Salfred			if (bind(fds[n], res->ai_addr, res->ai_addrlen) < 0) {
45592725Salfred				close(fds[n]);
45692725Salfred				fds[n] = -1;
45792725Salfred				continue;
45892725Salfred			}
45992725Salfred			if (listen(fds[n], 32) < 0) {
46021259Swollman				close(fds[n]);
46192725Salfred				fds[n] = -1;
46292725Salfred				continue;
46392725Salfred			}
46492725Salfred
46592725Salfred			pfds[n].fd = fds[n];
46621259Swollman			pfds[n].events = POLLIN;
46792725Salfred			n++;
46892725Salfred		}
46921434Swollman		freeaddrinfo(res0);
47092725Salfred
47192725Salfred		if (n == 0) {
47279103Sbrooks			syslog(LOG_ERR, "could not open control socket");
47392725Salfred			exit(1);
47492725Salfred		}
47579103Sbrooks
47684931Sfjoe		/* Stash pid in pidfile */
47784931Sfjoe		if (pidfile(NULL))
47884931Sfjoe			syslog(LOG_ERR, "can't open pidfile: %m");
47987902Sluigi		/*
48087902Sluigi		 * Loop forever accepting connection requests and forking off
48187902Sluigi		 * children to handle them.
48292725Salfred		 */
48392725Salfred		while (1) {
48492725Salfred			if (poll(pfds, n, INFTIM) < 0) {
48587902Sluigi				if (errno == EINTR)
48687902Sluigi					continue;
48755205Speter				syslog(LOG_ERR, "poll: %m");
48821259Swollman				exit(1);
48921259Swollman			}
490			for (i = 0; i < n; i++)
491				if (pfds[i].revents & POLLIN) {
492					addrlen = sizeof(his_addr);
493					fd = accept(pfds[i].fd,
494					    (struct sockaddr *)&his_addr,
495					    &addrlen);
496					if (fd != -1) {
497						if (fork() == 0)
498							goto child;
499						close(fd);
500					}
501				}
502		}
503
504	child:
505		/* child */
506		(void)dup2(fd, STDIN_FILENO);
507		(void)dup2(fd, STDOUT_FILENO);
508		for (i = 0; i < n; i++)
509			close(fds[i]);
510#if defined(TCPWRAPPERS)
511		/* ..in the child. */
512		if (!check_host((struct sockaddr *)&his_addr))
513			exit(1);
514#endif	/* TCPWRAPPERS */
515	} else {
516		addrlen = sizeof(his_addr);
517		if (getpeername(0, (struct sockaddr *)&his_addr,
518		    &addrlen) < 0) {
519			/* syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); */
520			exit(1);
521		}
522	}
523
524	/* set this here so klogin can use it... */
525	(void)snprintf(ttyline, sizeof(ttyline), "ftp%ld", (long)getpid());
526
527	set_slave_signals();
528
529	addrlen = sizeof(ctrl_addr);
530	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
531		syslog(LOG_ERR, "getsockname: %m");
532		exit(1);
533	}
534	if (his_addr.su_family == AF_INET6 &&
535	    IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
536#if 1
537		/*
538		 * IPv4 control connection arrived to AF_INET6 socket.
539		 * I hate to do this, but this is the easiest solution.
540		 */
541		union sockunion tmp_addr;
542		const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
543
544		tmp_addr = his_addr;
545		memset(&his_addr, 0, sizeof(his_addr));
546		his_addr.su_sin.sin_family = AF_INET;
547		his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
548		memcpy(&his_addr.su_sin.sin_addr,
549		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
550		    sizeof(his_addr.su_sin.sin_addr));
551		his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
552
553		tmp_addr = ctrl_addr;
554		memset(&ctrl_addr, 0, sizeof(ctrl_addr));
555		ctrl_addr.su_sin.sin_family = AF_INET;
556		ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
557		memcpy(&ctrl_addr.su_sin.sin_addr,
558		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
559		    sizeof(ctrl_addr.su_sin.sin_addr));
560		ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
561#else
562		while (fgets(line, sizeof(line), fd) != NULL) {
563			if ((cp = strchr(line, '\n')) != NULL)
564				*cp = '\0';
565			lreply(530, "%s", line);
566		}
567		(void) fflush(stdout);
568		(void) close(fd);
569		reply(530,
570			"Connection from IPv4 mapped address is not supported.");
571		exit(0);
572#endif
573	}
574#ifdef IP_TOS
575	if (his_addr.su_family == AF_INET) {
576		tos = IPTOS_LOWDELAY;
577		if (setsockopt(0, IPPROTO_IP, IP_TOS, &tos,
578		    sizeof(int)) < 0)
579			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
580	}
581#endif
582	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
583
584	/* Try to handle urgent data inline */
585#ifdef SO_OOBINLINE
586	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) < 0)
587		syslog(LOG_ERR, "setsockopt: %m");
588#endif
589
590	dolog((struct sockaddr *)&his_addr);
591
592	/*
593	 * Set up default state
594	 */
595	data = -1;
596	type = TYPE_A;
597	form = FORM_N;
598	stru = STRU_F;
599	mode = MODE_S;
600	tmpline[0] = '\0';
601
602	/* If logins are disabled, print out the message. */
603	if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
604		while (fgets(line, sizeof(line), fp) != NULL) {
605			if ((cp = strchr(line, '\n')) != NULL)
606				*cp = '\0';
607			lreply(530, "%s", line);
608		}
609		(void) fflush(stdout);
610		(void) fclose(fp);
611		reply(530, "System not available.");
612		exit(0);
613	}
614	if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
615		while (fgets(line, sizeof(line), fp) != NULL) {
616			if ((cp = strchr(line, '\n')) != NULL)
617				*cp = '\0';
618			lreply(220, "%s", line);
619		}
620		(void) fflush(stdout);
621		(void) fclose(fp);
622		/* reply(220,) must follow */
623	}
624	(void) gethostname(hostname, sizeof(hostname));
625
626	/* Make sure hostname is fully qualified. */
627	hp = gethostbyname(hostname);
628	if (hp != NULL)
629		strlcpy(hostname, hp->h_name, sizeof(hostname));
630
631	if (multihome) {
632		error = getnameinfo((struct sockaddr *)&ctrl_addr,
633		    ctrl_addr.su_len, dhostname, sizeof(dhostname), NULL, 0, 0);
634	}
635
636	if (error != 0)
637		reply(220, "FTP server (%s) ready.", version);
638	else
639		reply(220, "%s FTP server (%s) ready.",
640		    (multihome ? dhostname : hostname), version);
641
642	monitor_init();
643
644	for (;;)
645		(void) yyparse();
646	/* NOTREACHED */
647}
648
649/*
650 * Signal handlers.
651 */
652/*ARGSUSED*/
653static void
654lostconn(int signo)
655{
656	struct syslog_data sdata = SYSLOG_DATA_INIT;
657
658	sdata.log_fac = LOG_FTP;
659	if (debug)
660		syslog_r(LOG_DEBUG, &sdata, "lost connection");
661	dologout(1);
662}
663
664static void
665sigquit(int signo)
666{
667	struct syslog_data sdata = SYSLOG_DATA_INIT;
668
669	sdata.log_fac = LOG_FTP;
670	syslog_r(LOG_DEBUG, &sdata, "got signal %s", sys_signame[signo]);
671	dologout(1);
672}
673
674/*
675 * Save the result of a getpwnam.  Used for USER command, since
676 * the data returned must not be clobbered by any other command
677 * (e.g., globbing).
678 */
679static struct passwd *
680sgetpwnam(char *name, struct passwd *pw)
681{
682	static struct passwd *save;
683	struct passwd *old;
684
685	if (pw == NULL && (pw = getpwnam(name)) == NULL)
686		return (NULL);
687	old = save;
688	save = pw_dup(pw);
689	if (save == NULL) {
690		perror_reply(421, "Local resource failure: malloc");
691		dologout(1);
692		/* NOTREACHED */
693	}
694	if (old) {
695		memset(old->pw_passwd, 0, strlen(old->pw_passwd));
696		free(old);
697	}
698	return (save);
699}
700
701static int login_attempts;	/* number of failed login attempts */
702static int askpasswd;		/* had user command, ask for passwd */
703static char curname[MAXLOGNAME];	/* current USER name */
704
705/*
706 * USER command.
707 * Sets global passwd pointer pw if named account exists and is acceptable;
708 * sets askpasswd if a PASS command is expected.  If logged in previously,
709 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
710 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
711 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
712 * requesting login privileges.  Disallow anyone who does not have a standard
713 * shell as returned by getusershell().  Disallow anyone mentioned in the file
714 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
715 */
716void
717user(char *name)
718{
719	char *cp, *shell, *style, *host;
720	char *class = NULL;
721
722	if (logged_in) {
723		kill_slave("user already logged in");
724		end_login();
725	}
726
727	/* Close session from previous user if there was one. */
728	if (as) {
729		auth_close(as);
730		as = NULL;
731	}
732	if (lc) {
733		login_close(lc);
734		lc = NULL;
735	}
736
737	if ((style = strchr(name, ':')) != NULL)
738		*style++ = 0;
739
740	guest = 0;
741	host = multihome ? dhostname : hostname;
742	if (anon_ok &&
743	    (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0)) {
744		if (checkuser(_PATH_FTPUSERS, "ftp") ||
745		    checkuser(_PATH_FTPUSERS, "anonymous"))
746			reply(530, "User %s access denied.", name);
747		else if ((pw = sgetpwnam("ftp", NULL)) != NULL) {
748			guest = 1;
749			askpasswd = 1;
750			lc = login_getclass(pw->pw_class);
751			if ((as = auth_open()) == NULL ||
752			    auth_setpwd(as, pw) != 0 ||
753			    auth_setoption(as, "FTPD_HOST", host) < 0) {
754				if (as) {
755					auth_close(as);
756					as = NULL;
757				}
758				login_close(lc);
759				lc = NULL;
760				reply(421, "Local resource failure");
761				return;
762			}
763			reply(331,
764			"Guest login ok, send your email address as password.");
765		} else
766			reply(530, "User %s unknown.", name);
767		if (!askpasswd && logging)
768			syslog(LOG_NOTICE,
769			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
770		return;
771	}
772
773	shell = _PATH_BSHELL;
774	if ((pw = sgetpwnam(name, NULL))) {
775		class = pw->pw_class;
776		if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
777			shell = pw->pw_shell;
778		while ((cp = getusershell()) != NULL)
779			if (strcmp(cp, shell) == 0)
780				break;
781		shell = cp;
782		endusershell();
783	}
784
785	/* Get login class; if invalid style treat like unknown user. */
786	lc = login_getclass(class);
787	if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
788		login_close(lc);
789		lc = NULL;
790		pw = NULL;
791	}
792
793	/* Do pre-authentication setup. */
794	if (lc && ((as = auth_open()) == NULL ||
795	    (pw != NULL && auth_setpwd(as, pw) != 0) ||
796	    auth_setitem(as, AUTHV_STYLE, style) < 0 ||
797	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
798	    auth_setitem(as, AUTHV_CLASS, class) < 0 ||
799	    auth_setoption(as, "login", "yes") < 0 ||
800	    auth_setoption(as, "notickets", "yes") < 0 ||
801	    auth_setoption(as, "FTPD_HOST", host) < 0)) {
802		if (as) {
803			auth_close(as);
804			as = NULL;
805		}
806		login_close(lc);
807		lc = NULL;
808		reply(421, "Local resource failure");
809		return;
810	}
811	if (logging)
812		strlcpy(curname, name, sizeof(curname));
813
814	dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
815	    checkuser(_PATH_FTPCHROOT, name);
816	if (anon_only && !dochroot) {
817		if (anon_ok)
818			reply(530, "Sorry, only anonymous ftp allowed.");
819		else
820			reply(530, "User %s access denied.", name);
821		return;
822	}
823	if (pw) {
824		if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
825			reply(530, "User %s access denied.", name);
826			if (logging)
827				syslog(LOG_NOTICE,
828				    "FTP LOGIN REFUSED FROM %s, %s",
829				    remotehost, name);
830			pw = NULL;
831			return;
832		}
833	}
834
835	if (as != NULL && (cp = auth_challenge(as)) != NULL)
836		reply(331, "%s", cp);
837	else
838		reply(331, "Password required for %s.", name);
839
840	askpasswd = 1;
841	/*
842	 * Delay before reading passwd after first failed
843	 * attempt to slow down passwd-guessing programs.
844	 */
845	if (login_attempts)
846		sleep((unsigned) login_attempts);
847}
848
849/*
850 * Check if a user is in the file "fname"
851 */
852static int
853checkuser(char *fname, char *name)
854{
855	FILE *fp;
856	int found = 0;
857	char *p, line[BUFSIZ];
858
859	if ((fp = fopen(fname, "r")) != NULL) {
860		while (fgets(line, sizeof(line), fp) != NULL)
861			if ((p = strchr(line, '\n')) != NULL) {
862				*p = '\0';
863				if (line[0] == '#')
864					continue;
865				if (strcmp(line, name) == 0) {
866					found = 1;
867					break;
868				}
869			}
870		(void) fclose(fp);
871	}
872	return (found);
873}
874
875/*
876 * Terminate login as previous user, if any, resetting state;
877 * used when USER command is given or login fails.
878 */
879static void
880end_login(void)
881{
882	sigprocmask (SIG_BLOCK, &allsigs, NULL);
883	if (logged_in) {
884		ftpdlogwtmp(ttyline, "", "");
885		if (doutmp)
886			ftpd_logout(utmp.ut_line);
887	}
888	reply(530, "Please reconnect to work as another user");
889	_exit(0);
890}
891
892enum auth_ret
893pass(char *passwd)
894{
895	int authok;
896	unsigned int flags;
897	FILE *fp;
898	static char homedir[MAXPATHLEN];
899	char *motd, *dir, rootdir[MAXPATHLEN];
900	size_t sz_pw_dir;
901
902	if (logged_in || askpasswd == 0) {
903		reply(503, "Login with USER first.");
904		return (AUTH_FAILED);
905	}
906	askpasswd = 0;
907	if (!guest) {		/* "ftp" is only account allowed no password */
908		authok = 0;
909		if (pw == NULL || pw->pw_passwd[0] == '\0') {
910			useconds_t us;
911
912			/* Sleep between 1 and 3 seconds to emulate a crypt. */
913			us = arc4random() % 3000000;
914			usleep(us);
915			if (as != NULL) {
916				auth_close(as);
917				as = NULL;
918			}
919		} else {
920			authok = auth_userresponse(as, passwd, 0);
921			as = NULL;
922		}
923		if (authok == 0) {
924			reply(530, "Login incorrect.");
925			if (logging)
926				syslog(LOG_NOTICE,
927				    "FTP LOGIN FAILED FROM %s, %s",
928				    remotehost, curname);
929			pw = NULL;
930			if (login_attempts++ >= 5) {
931				syslog(LOG_NOTICE,
932				    "repeated login failures from %s",
933				    remotehost);
934				kill_slave("repeated login failures");
935				_exit(0);
936			}
937			return (AUTH_FAILED);
938		}
939	} else if (lc != NULL) {
940		/* Save anonymous' password. */
941		if (guestpw != NULL)
942			free(guestpw);
943		guestpw = strdup(passwd);
944		if (guestpw == NULL) {
945			kill_slave("out of mem");
946			fatal("Out of memory.");
947		}
948
949		authok = auth_approval(as, lc, pw->pw_name, "ftp");
950		auth_close(as);
951		as = NULL;
952		if (authok == 0) {
953			syslog(LOG_INFO|LOG_AUTH,
954			    "FTP LOGIN FAILED (HOST) as %s: approval failure.",
955			    pw->pw_name);
956			reply(530, "Approval failure.");
957			kill_slave("approval failure");
958			_exit(0);
959		}
960	} else {
961		syslog(LOG_INFO|LOG_AUTH,
962		    "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
963		    pw->pw_class, pw->pw_name);
964		reply(530, "Permission denied.");
965		kill_slave("permission denied");
966		_exit(0);
967	}
968
969	if (monitor_post_auth() == 1) {
970		/* Post-auth monitor process */
971		logged_in = 1;
972		return (AUTH_MONITOR);
973	}
974
975	login_attempts = 0;		/* this time successful */
976	/* set umask via setusercontext() unless -u flag was given. */
977	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
978	if (umaskchange)
979		flags |= LOGIN_SETUMASK;
980	else
981		(void) umask(defumask);
982	if (setusercontext(lc, pw, (uid_t)0, flags) != 0) {
983		perror_reply(451, "Local resource failure: setusercontext");
984		syslog(LOG_NOTICE, "setusercontext: %m");
985		dologout(1);
986		/* NOTREACHED */
987	}
988
989	/* open wtmp before chroot */
990	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
991
992	/* open utmp before chroot */
993	if (doutmp) {
994		memset((void *)&utmp, 0, sizeof(utmp));
995		(void)time(&utmp.ut_time);
996		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
997		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
998		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
999		ftpd_login(&utmp);
1000	}
1001
1002	/* open stats file before chroot */
1003	if (guest && (stats == 1) && (statfd < 0))
1004		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
1005			stats = 0;
1006
1007	logged_in = 1;
1008
1009	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
1010		char *newdir;
1011
1012		newdir = copy_dir(dir, pw);
1013		if (newdir == NULL) {
1014			perror_reply(421, "Local resource failure: malloc");
1015			dologout(1);
1016			/* NOTREACHED */
1017		}
1018		pw->pw_dir = newdir;
1019		pw = sgetpwnam(NULL, pw);
1020		free(dir);
1021		free(newdir);
1022	}
1023
1024	/* make sure pw->pw_dir is big enough to hold "/" */
1025	sz_pw_dir = strlen(pw->pw_dir) + 1;
1026	if (sz_pw_dir < 2) {
1027		pw->pw_dir = "/";
1028		pw = sgetpwnam(NULL, pw);
1029		sz_pw_dir = 2;
1030	}
1031
1032	if (guest || dochroot) {
1033		if (multihome && guest) {
1034			struct stat ts;
1035
1036			/* Compute root directory. */
1037			snprintf(rootdir, sizeof(rootdir), "%s/%s",
1038			    pw->pw_dir, dhostname);
1039			if (stat(rootdir, &ts) < 0) {
1040				snprintf(rootdir, sizeof(rootdir), "%s/%s",
1041				    pw->pw_dir, hostname);
1042			}
1043		} else
1044			strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1045	}
1046	if (guest) {
1047		/*
1048		 * We MUST do a chdir() after the chroot. Otherwise
1049		 * the old current directory will be accessible as "."
1050		 * outside the new root!
1051		 */
1052		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1053			reply(550, "Can't set guest privileges.");
1054			goto bad;
1055		}
1056		strlcpy(pw->pw_dir, "/", sz_pw_dir);
1057		if (setenv("HOME", "/", 1) == -1) {
1058			reply(550, "Can't setup environment.");
1059			goto bad;
1060		}
1061	} else if (dochroot) {
1062		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1063			reply(550, "Can't change root.");
1064			goto bad;
1065		}
1066		strlcpy(pw->pw_dir, "/", sz_pw_dir);
1067		if (setenv("HOME", "/", 1) == -1) {
1068			reply(550, "Can't setup environment.");
1069			goto bad;
1070		}
1071	} else if (chdir(pw->pw_dir) < 0) {
1072		if (chdir("/") < 0) {
1073			reply(530, "User %s: can't change directory to %s.",
1074			    pw->pw_name, pw->pw_dir);
1075			goto bad;
1076		} else
1077			lreply(230, "No directory! Logging in with home=/");
1078	}
1079	if (setegid(pw->pw_gid) < 0 || setgid(pw->pw_gid) < 0) {
1080		reply(550, "Can't set gid.");
1081		goto bad;
1082	}
1083	if (seteuid(pw->pw_uid) < 0 || setuid(pw->pw_uid) < 0) {
1084		reply(550, "Can't set uid.");
1085		goto bad;
1086	}
1087	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1088
1089	/*
1090	 * Set home directory so that use of ~ (tilde) works correctly.
1091	 */
1092	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1093		if (setenv("HOME", homedir, 1) == -1) {
1094			reply(550, "Can't setup environment.");
1095			goto bad;
1096		}
1097	}
1098
1099	/*
1100	 * Display a login message, if it exists.
1101	 * N.B. reply(230,) must follow the message.
1102	 */
1103	motd = login_getcapstr(lc, "welcome", NULL, NULL);
1104	if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1105		char *cp, line[LINE_MAX];
1106
1107		while (fgets(line, sizeof(line), fp) != NULL) {
1108			if ((cp = strchr(line, '\n')) != NULL)
1109				*cp = '\0';
1110			lreply(230, "%s", line);
1111		}
1112		(void) fflush(stdout);
1113		(void) fclose(fp);
1114	}
1115	if (motd != NULL)
1116		free(motd);
1117	if (guest) {
1118		if (ident != NULL)
1119			free(ident);
1120		ident = strdup(passwd);
1121		if (ident == NULL)
1122			fatal("Ran out of memory.");
1123		reply(230, "Guest login ok, access restrictions apply.");
1124#ifdef HASSETPROCTITLE
1125		snprintf(proctitle, sizeof(proctitle),
1126		    "%s: anonymous/%.*s", remotehost,
1127		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1128		    sizeof(": anonymous/")), passwd);
1129		setproctitle("%s", proctitle);
1130#endif /* HASSETPROCTITLE */
1131		if (logging)
1132			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1133			    remotehost, passwd);
1134	} else {
1135		reply(230, "User %s logged in.", pw->pw_name);
1136#ifdef HASSETPROCTITLE
1137		snprintf(proctitle, sizeof(proctitle),
1138		    "%s: %s", remotehost, pw->pw_name);
1139		setproctitle("%s", proctitle);
1140#endif /* HASSETPROCTITLE */
1141		if (logging)
1142			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1143			    remotehost, pw->pw_name);
1144	}
1145	login_close(lc);
1146	lc = NULL;
1147	return (AUTH_SLAVE);
1148bad:
1149	/* Forget all about it... */
1150	login_close(lc);
1151	lc = NULL;
1152	end_login();
1153	return (AUTH_FAILED);
1154}
1155
1156void
1157retrieve(char *cmd, char *name)
1158{
1159	FILE *fin, *dout;
1160	struct stat st;
1161	int (*closefunc)(FILE *);
1162	time_t start;
1163
1164	if (cmd == 0) {
1165		fin = fopen(name, "r"), closefunc = fclose;
1166		st.st_size = 0;
1167	} else {
1168		char line[BUFSIZ];
1169
1170		(void) snprintf(line, sizeof(line), cmd, name);
1171		name = line;
1172		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1173		st.st_size = -1;
1174		st.st_blksize = BUFSIZ;
1175	}
1176	if (fin == NULL) {
1177		if (errno != 0) {
1178			perror_reply(550, name);
1179			if (cmd == 0) {
1180				LOGCMD("get", name);
1181			}
1182		}
1183		return;
1184	}
1185	byte_count = -1;
1186	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1187		reply(550, "%s: not a plain file.", name);
1188		goto done;
1189	}
1190	if (restart_point) {
1191		if (type == TYPE_A) {
1192			off_t i, n;
1193			int c;
1194
1195			n = restart_point;
1196			i = 0;
1197			while (i++ < n) {
1198				if ((c = getc(fin)) == EOF) {
1199					if (ferror(fin)) {
1200						perror_reply(550, name);
1201						goto done;
1202					} else
1203						break;
1204				}
1205				if (c == '\n')
1206					i++;
1207			}
1208		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1209			perror_reply(550, name);
1210			goto done;
1211		}
1212	}
1213	dout = dataconn(name, st.st_size, "w");
1214	if (dout == NULL)
1215		goto done;
1216	time(&start);
1217	send_data(fin, dout, (off_t)st.st_blksize, st.st_size,
1218	    (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1219	if ((cmd == 0) && stats)
1220		logxfer(name, byte_count, start);
1221	(void) fclose(dout);
1222	data = -1;
1223done:
1224	if (pdata >= 0)
1225		(void) close(pdata);
1226	pdata = -1;
1227	if (cmd == 0)
1228		LOGBYTES("get", name, byte_count);
1229	(*closefunc)(fin);
1230}
1231
1232void
1233store(char *name, char *mode, int unique)
1234{
1235	FILE *fout, *din;
1236	int (*closefunc)(FILE *);
1237	struct stat st;
1238	int fd;
1239
1240	if (restart_point && *mode != 'a')
1241		mode = "r+";
1242
1243	if (unique && stat(name, &st) == 0) {
1244		char *nam;
1245
1246		fd = guniquefd(name, &nam);
1247		if (fd == -1) {
1248			LOGCMD(*mode == 'w' ? "put" : "append", name);
1249			return;
1250		}
1251		name = nam;
1252		fout = fdopen(fd, mode);
1253	} else
1254		fout = fopen(name, mode);
1255
1256	closefunc = fclose;
1257	if (fout == NULL) {
1258		perror_reply(553, name);
1259		LOGCMD(*mode == 'w' ? "put" : "append", name);
1260		return;
1261	}
1262	byte_count = -1;
1263	if (restart_point) {
1264		if (type == TYPE_A) {
1265			off_t i, n;
1266			int c;
1267
1268			n = restart_point;
1269			i = 0;
1270			while (i++ < n) {
1271				if ((c = getc(fout)) == EOF) {
1272					if (ferror(fout)) {
1273						perror_reply(550, name);
1274						goto done;
1275					} else
1276						break;
1277				}
1278				if (c == '\n')
1279					i++;
1280			}
1281			/*
1282			 * We must do this seek to "current" position
1283			 * because we are changing from reading to
1284			 * writing.
1285			 */
1286			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1287				perror_reply(550, name);
1288				goto done;
1289			}
1290		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1291			perror_reply(550, name);
1292			goto done;
1293		}
1294	}
1295	din = dataconn(name, (off_t)-1, "r");
1296	if (din == NULL)
1297		goto done;
1298	if (receive_data(din, fout) == 0) {
1299		if (unique)
1300			reply(226, "Transfer complete (unique file name:%s).",
1301			    name);
1302		else
1303			reply(226, "Transfer complete.");
1304	}
1305	(void) fclose(din);
1306	data = -1;
1307	pdata = -1;
1308done:
1309	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1310	(*closefunc)(fout);
1311}
1312
1313static FILE *
1314getdatasock(char *mode)
1315{
1316	int on = 1, s, t, tries;
1317
1318	if (data >= 0)
1319		return (fdopen(data, mode));
1320	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1321	s = monitor_socket(ctrl_addr.su_family);
1322	if (s < 0)
1323		goto bad;
1324	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1325	    &on, sizeof(on)) < 0)
1326		goto bad;
1327	/* anchor socket to avoid multi-homing problems */
1328	data_source = ctrl_addr;
1329	data_source.su_port = htons(20); /* ftp-data port */
1330	for (tries = 1; ; tries++) {
1331		if (monitor_bind(s, (struct sockaddr *)&data_source,
1332		    data_source.su_len) >= 0)
1333			break;
1334		if (errno != EADDRINUSE || tries > 10)
1335			goto bad;
1336		sleep((unsigned int)tries);
1337	}
1338	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1339
1340#ifdef IP_TOS
1341	if (ctrl_addr.su_family == AF_INET) {
1342		on = IPTOS_THROUGHPUT;
1343		if (setsockopt(s, IPPROTO_IP, IP_TOS, &on,
1344		    sizeof(int)) < 0)
1345			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1346	}
1347#endif
1348#ifdef TCP_NOPUSH
1349	/*
1350	 * Turn off push flag to keep sender TCP from sending short packets
1351	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1352	 * to set the send buffer size as well, but that may not be desirable
1353	 * in heavy-load situations.
1354	 */
1355	on = 1;
1356	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on)) < 0)
1357		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1358#endif
1359#ifdef SO_SNDBUF
1360	on = 65536;
1361	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &on, sizeof(on)) < 0)
1362		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1363#endif
1364
1365	return (fdopen(s, mode));
1366bad:
1367	/* Return the real value of errno (close may change it) */
1368	t = errno;
1369	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1370	if (s >= 0)
1371		(void) close(s);
1372	errno = t;
1373	return (NULL);
1374}
1375
1376static FILE *
1377dataconn(char *name, off_t size, char *mode)
1378{
1379	char sizebuf[32];
1380	FILE *file = NULL;
1381	int retry = 0;
1382	in_port_t *p;
1383	u_char *fa, *ha;
1384	size_t alen;
1385	int error;
1386
1387	file_size = size;
1388	byte_count = 0;
1389	if (size != (off_t) -1) {
1390		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1391		    size);
1392	} else
1393		sizebuf[0] = '\0';
1394	if (pdata >= 0) {
1395		union sockunion from;
1396		int s;
1397		socklen_t fromlen = sizeof(from);
1398
1399		(void) alarm ((unsigned) timeout);
1400		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1401		(void) alarm (0);
1402		if (s < 0) {
1403			reply(425, "Can't open data connection.");
1404			(void) close(pdata);
1405			pdata = -1;
1406			return (NULL);
1407		}
1408		switch (from.su_family) {
1409		case AF_INET:
1410			p = (in_port_t *)&from.su_sin.sin_port;
1411			fa = (u_char *)&from.su_sin.sin_addr;
1412			ha = (u_char *)&his_addr.su_sin.sin_addr;
1413			alen = sizeof(struct in_addr);
1414			break;
1415		case AF_INET6:
1416			p = (in_port_t *)&from.su_sin6.sin6_port;
1417			fa = (u_char *)&from.su_sin6.sin6_addr;
1418			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1419			alen = sizeof(struct in6_addr);
1420			break;
1421		default:
1422			perror_reply(425, "Can't build data connection");
1423			(void) close(pdata);
1424			(void) close(s);
1425			pdata = -1;
1426			return (NULL);
1427		}
1428		if (from.su_family != his_addr.su_family ||
1429		    ntohs(*p) < IPPORT_RESERVED) {
1430			perror_reply(425, "Can't build data connection");
1431			(void) close(pdata);
1432			(void) close(s);
1433			pdata = -1;
1434			return (NULL);
1435		}
1436		if (portcheck && memcmp(fa, ha, alen) != 0) {
1437			perror_reply(435, "Can't build data connection");
1438			(void) close(pdata);
1439			(void) close(s);
1440			pdata = -1;
1441			return (NULL);
1442		}
1443		(void) close(pdata);
1444		pdata = s;
1445		reply(150, "Opening %s mode data connection for '%s'%s.",
1446		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1447		return (fdopen(pdata, mode));
1448	}
1449	if (data >= 0) {
1450		reply(125, "Using existing data connection for '%s'%s.",
1451		    name, sizebuf);
1452		usedefault = 1;
1453		return (fdopen(data, mode));
1454	}
1455	if (usedefault)
1456		data_dest = his_addr;
1457	usedefault = 1;
1458	do {
1459		if (file != NULL)
1460			(void) fclose(file);
1461		file = getdatasock(mode);
1462		if (file == NULL) {
1463			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1464
1465			error = getnameinfo((struct sockaddr *)&data_source,
1466			    data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1467			    sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1468			if (error != 0)
1469				reply(425, "Can't create data socket: %s.",
1470				    strerror(errno));
1471			else
1472				reply(425,
1473				    "Can't create data socket (%s,%s): %s.",
1474				    hbuf, pbuf, strerror(errno));
1475			return (NULL);
1476		}
1477
1478		/*
1479		 * attempt to connect to reserved port on client machine;
1480		 * this looks like an attack
1481		 */
1482		switch (data_dest.su_family) {
1483		case AF_INET:
1484			p = (in_port_t *)&data_dest.su_sin.sin_port;
1485			fa = (u_char *)&data_dest.su_sin.sin_addr;
1486			ha = (u_char *)&his_addr.su_sin.sin_addr;
1487			alen = sizeof(struct in_addr);
1488			break;
1489		case AF_INET6:
1490			p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1491			fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1492			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1493			alen = sizeof(struct in6_addr);
1494			break;
1495		default:
1496			perror_reply(425, "Can't build data connection");
1497			(void) fclose(file);
1498			pdata = -1;
1499			return (NULL);
1500		}
1501		if (data_dest.su_family != his_addr.su_family ||
1502		    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
1503			perror_reply(425, "Can't build data connection");
1504			(void) fclose(file);
1505			return NULL;
1506		}
1507		if (portcheck && memcmp(fa, ha, alen) != 0) {
1508			perror_reply(435, "Can't build data connection");
1509			(void) fclose(file);
1510			return NULL;
1511		}
1512
1513		if (connect(fileno(file), (struct sockaddr *)&data_dest,
1514		    data_dest.su_len) == 0) {
1515			reply(150, "Opening %s mode data connection for '%s'%s.",
1516			    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1517			data = fileno(file);
1518			return (file);
1519		}
1520		if (errno != EADDRINUSE)
1521			break;
1522		sleep((unsigned) swaitint);
1523		retry += swaitint;
1524	} while (retry <= swaitmax);
1525	perror_reply(425, "Can't build data connection");
1526	(void) fclose(file);
1527	return (NULL);
1528}
1529
1530/*
1531 * Transfer the contents of "instr" to "outstr" peer using the appropriate
1532 * encapsulation of the data subject to Mode, Structure, and Type.
1533 *
1534 * NB: Form isn't handled.
1535 */
1536static int
1537send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1538{
1539	int c, cnt, filefd, netfd;
1540	char *buf, *bp;
1541	size_t len;
1542
1543	transflag++;
1544	switch (type) {
1545
1546	case TYPE_A:
1547		while ((c = getc(instr)) != EOF) {
1548			if (recvurg)
1549				goto got_oob;
1550			byte_count++;
1551			if (c == '\n') {
1552				if (ferror(outstr))
1553					goto data_err;
1554				(void) putc('\r', outstr);
1555			}
1556			(void) putc(c, outstr);
1557		}
1558		fflush(outstr);
1559		transflag = 0;
1560		if (ferror(instr))
1561			goto file_err;
1562		if (ferror(outstr))
1563			goto data_err;
1564		reply(226, "Transfer complete.");
1565		return(0);
1566
1567	case TYPE_I:
1568	case TYPE_L:
1569		/*
1570		 * isreg is only set if we are not doing restart and we
1571		 * are sending a regular file
1572		 */
1573		netfd = fileno(outstr);
1574		filefd = fileno(instr);
1575
1576		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1577			size_t fsize = (size_t)filesize;
1578
1579			buf = mmap(0, fsize, PROT_READ, MAP_SHARED, filefd,
1580			    (off_t)0);
1581			if (buf == MAP_FAILED) {
1582				syslog(LOG_WARNING, "mmap(%llu): %m",
1583				    (unsigned long long)fsize);
1584				goto oldway;
1585			}
1586			bp = buf;
1587			len = fsize;
1588			do {
1589				cnt = write(netfd, bp, len);
1590				if (recvurg) {
1591					munmap(buf, fsize);
1592					goto got_oob;
1593				}
1594				len -= cnt;
1595				bp += cnt;
1596				if (cnt > 0)
1597					byte_count += cnt;
1598			} while(cnt > 0 && len > 0);
1599
1600			transflag = 0;
1601			munmap(buf, fsize);
1602			if (cnt < 0)
1603				goto data_err;
1604			reply(226, "Transfer complete.");
1605			return(0);
1606		}
1607
1608oldway:
1609		if ((buf = malloc((size_t)blksize)) == NULL) {
1610			transflag = 0;
1611			perror_reply(451, "Local resource failure: malloc");
1612			return(-1);
1613		}
1614
1615		while ((cnt = read(filefd, buf, (size_t)blksize)) > 0 &&
1616		    write(netfd, buf, cnt) == cnt)
1617			byte_count += cnt;
1618		transflag = 0;
1619		(void)free(buf);
1620		if (cnt != 0) {
1621			if (cnt < 0)
1622				goto file_err;
1623			goto data_err;
1624		}
1625		reply(226, "Transfer complete.");
1626		return(0);
1627	default:
1628		transflag = 0;
1629		reply(550, "Unimplemented TYPE %d in send_data", type);
1630		return(-1);
1631	}
1632
1633data_err:
1634	transflag = 0;
1635	perror_reply(426, "Data connection");
1636	return(-1);
1637
1638file_err:
1639	transflag = 0;
1640	perror_reply(551, "Error on input file");
1641	return(-1);
1642
1643got_oob:
1644	myoob();
1645	recvurg = 0;
1646	transflag = 0;
1647	return(-1);
1648}
1649
1650/*
1651 * Transfer data from peer to "outstr" using the appropriate encapulation of
1652 * the data subject to Mode, Structure, and Type.
1653 *
1654 * N.B.: Form isn't handled.
1655 */
1656static int
1657receive_data(FILE *instr, FILE *outstr)
1658{
1659	int c;
1660	int cnt;
1661	char buf[BUFSIZ];
1662	struct sigaction sa, sa_saved;
1663	volatile int bare_lfs = 0;
1664
1665	transflag++;
1666	switch (type) {
1667
1668	case TYPE_I:
1669	case TYPE_L:
1670		memset(&sa, 0, sizeof(sa));
1671		sigfillset(&sa.sa_mask);
1672		sa.sa_flags = SA_RESTART;
1673		sa.sa_handler = lostconn;
1674		(void) sigaction(SIGALRM, &sa, &sa_saved);
1675		do {
1676			(void) alarm ((unsigned) timeout);
1677			cnt = read(fileno(instr), buf, sizeof(buf));
1678			(void) alarm (0);
1679			if (recvurg)
1680				goto got_oob;
1681
1682			if (cnt > 0) {
1683				if (write(fileno(outstr), buf, cnt) != cnt)
1684					goto file_err;
1685				byte_count += cnt;
1686			}
1687		} while (cnt > 0);
1688		(void) sigaction(SIGALRM, &sa_saved, NULL);
1689		if (cnt < 0)
1690			goto data_err;
1691		transflag = 0;
1692		return (0);
1693
1694	case TYPE_E:
1695		reply(553, "TYPE E not implemented.");
1696		transflag = 0;
1697		return (-1);
1698
1699	case TYPE_A:
1700		while ((c = getc(instr)) != EOF) {
1701			if (recvurg)
1702				goto got_oob;
1703			byte_count++;
1704			if (c == '\n')
1705				bare_lfs++;
1706			while (c == '\r') {
1707				if (ferror(outstr))
1708					goto data_err;
1709				if ((c = getc(instr)) != '\n') {
1710					(void) putc ('\r', outstr);
1711					if (c == '\0' || c == EOF)
1712						goto contin2;
1713				}
1714			}
1715			(void) putc(c, outstr);
1716	contin2:	;
1717		}
1718		fflush(outstr);
1719		if (ferror(instr))
1720			goto data_err;
1721		if (ferror(outstr))
1722			goto file_err;
1723		transflag = 0;
1724		if (bare_lfs) {
1725			lreply(226,
1726			    "WARNING! %d bare linefeeds received in ASCII mode",
1727			    bare_lfs);
1728			printf("   File may not have transferred correctly.\r\n");
1729		}
1730		return (0);
1731	default:
1732		reply(550, "Unimplemented TYPE %d in receive_data", type);
1733		transflag = 0;
1734		return (-1);
1735	}
1736
1737data_err:
1738	transflag = 0;
1739	perror_reply(426, "Data Connection");
1740	return (-1);
1741
1742file_err:
1743	transflag = 0;
1744	perror_reply(452, "Error writing file");
1745	return (-1);
1746
1747got_oob:
1748	myoob();
1749	recvurg = 0;
1750	transflag = 0;
1751	return (-1);
1752}
1753
1754void
1755statfilecmd(char *filename)
1756{
1757	FILE *fin;
1758	int c;
1759	int atstart;
1760	char line[LINE_MAX];
1761
1762	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1763	fin = ftpd_popen(line, "r");
1764	lreply(211, "status of %s:", filename);
1765	atstart = 1;
1766	while ((c = getc(fin)) != EOF) {
1767		if (c == '\n') {
1768			if (ferror(stdout)){
1769				perror_reply(421, "control connection");
1770				(void) ftpd_pclose(fin);
1771				dologout(1);
1772				/* NOTREACHED */
1773			}
1774			if (ferror(fin)) {
1775				perror_reply(551, filename);
1776				(void) ftpd_pclose(fin);
1777				return;
1778			}
1779			(void) putc('\r', stdout);
1780		}
1781		if (atstart && isdigit(c))
1782			(void) putc(' ', stdout);
1783		(void) putc(c, stdout);
1784		atstart = (c == '\n');
1785	}
1786	(void) ftpd_pclose(fin);
1787	reply(211, "End of Status");
1788}
1789
1790void
1791statcmd(void)
1792{
1793	union sockunion *su;
1794	u_char *a, *p;
1795	char hbuf[MAXHOSTNAMELEN];
1796	int ispassive;
1797	int error;
1798
1799	lreply(211, "%s FTP server status:", hostname);
1800	printf("     %s\r\n", version);
1801	error = getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1802	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1803	printf("     Connected to %s", remotehost);
1804	if (error == 0 && strcmp(remotehost, hbuf) != 0)
1805		printf(" (%s)", hbuf);
1806	printf("\r\n");
1807	if (logged_in) {
1808		if (guest)
1809			printf("     Logged in anonymously\r\n");
1810		else
1811			printf("     Logged in as %s\r\n", pw->pw_name);
1812	} else if (askpasswd)
1813		printf("     Waiting for password\r\n");
1814	else
1815		printf("     Waiting for user name\r\n");
1816	printf("     TYPE: %s", typenames[type]);
1817	if (type == TYPE_A || type == TYPE_E)
1818		printf(", FORM: %s", formnames[form]);
1819	if (type == TYPE_L)
1820#if NBBY == 8
1821		printf(" %d", NBBY);
1822#else
1823		printf(" %d", bytesize);	/* need definition! */
1824#endif
1825	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1826	    strunames[stru], modenames[mode]);
1827	ispassive = 0;
1828	if (data != -1)
1829		printf("     Data connection open\r\n");
1830	else if (pdata != -1) {
1831		printf("     in Passive mode\r\n");
1832		su = (union sockunion *)&pasv_addr;
1833		ispassive++;
1834		goto printaddr;
1835	} else if (usedefault == 0) {
1836		size_t alen;
1837		int af, i;
1838
1839		su = (union sockunion *)&data_dest;
1840printaddr:
1841		/* PASV/PORT */
1842		if (su->su_family == AF_INET) {
1843			if (ispassive)
1844				printf("211- PASV ");
1845			else
1846				printf("211- PORT ");
1847			a = (u_char *)&su->su_sin.sin_addr;
1848			p = (u_char *)&su->su_sin.sin_port;
1849			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1850			    a[0], a[1], a[2], a[3],
1851			    p[0], p[1]);
1852		}
1853
1854		/* LPSV/LPRT */
1855		alen = 0;
1856		switch (su->su_family) {
1857		case AF_INET:
1858			a = (u_char *)&su->su_sin.sin_addr;
1859			p = (u_char *)&su->su_sin.sin_port;
1860			alen = sizeof(su->su_sin.sin_addr);
1861			af = 4;
1862			break;
1863		case AF_INET6:
1864			a = (u_char *)&su->su_sin6.sin6_addr;
1865			p = (u_char *)&su->su_sin6.sin6_port;
1866			alen = sizeof(su->su_sin6.sin6_addr);
1867			af = 6;
1868			break;
1869		default:
1870			af = 0;
1871			break;
1872		}
1873		if (af) {
1874			if (ispassive)
1875				printf("211- LPSV ");
1876			else
1877				printf("211- LPRT ");
1878			printf("(%u,%llu", af, (unsigned long long)alen);
1879			for (i = 0; i < alen; i++)
1880				printf(",%u", a[i]);
1881			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1882		}
1883
1884		/* EPRT/EPSV */
1885		switch (su->su_family) {
1886		case AF_INET:
1887			af = 1;
1888			break;
1889		case AF_INET6:
1890			af = 2;
1891			break;
1892		default:
1893			af = 0;
1894			break;
1895		}
1896		if (af) {
1897			char pbuf[10];
1898			union sockunion tmp = *su;
1899
1900			if (tmp.su_family == AF_INET6)
1901				tmp.su_sin6.sin6_scope_id = 0;
1902			if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1903			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1904			    NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1905				if (ispassive)
1906					printf("211- EPSV ");
1907				else
1908					printf("211- EPRT ");
1909				printf("(|%u|%s|%s|)\r\n",
1910				    af, hbuf, pbuf);
1911			}
1912		}
1913	} else
1914		printf("     No data connection\r\n");
1915	reply(211, "End of status");
1916}
1917
1918void
1919fatal(char *s)
1920{
1921
1922	reply(451, "Error in server: %s", s);
1923	reply(221, "Closing connection due to server error.");
1924	dologout(0);
1925	/* NOTREACHED */
1926}
1927
1928void
1929reply(int n, const char *fmt, ...)
1930{
1931	char *buf, *p, *next;
1932	int rval;
1933	va_list ap;
1934
1935	va_start(ap, fmt);
1936	rval = vasprintf(&buf, fmt, ap);
1937	va_end(ap);
1938	if (rval == -1 || buf == NULL) {
1939		printf("412 Local resource failure: malloc\r\n");
1940		fflush(stdout);
1941		dologout(1);
1942	}
1943	next = buf;
1944	while ((p = strsep(&next, "\n\r"))) {
1945		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1946		if (debug)
1947			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1948			    (next != '\0') ? "-" : "", p);
1949	}
1950	(void)fflush(stdout);
1951	free(buf);
1952}
1953
1954
1955void
1956reply_r(int n, const char *fmt, ...)
1957{
1958	char *p, *next;
1959	char msg[BUFSIZ];
1960	char buf[BUFSIZ];
1961	va_list ap;
1962	struct syslog_data sdata = SYSLOG_DATA_INIT;
1963
1964	sdata.log_fac = LOG_FTP;
1965	va_start(ap, fmt);
1966	vsnprintf(msg, sizeof(msg), fmt, ap);
1967	va_end(ap);
1968
1969	next = msg;
1970
1971	while ((p = strsep(&next, "\n\r"))) {
1972		snprintf(buf, sizeof(buf), "%d%s %s\r\n", n,
1973		    (next != '\0') ? "-" : "", p);
1974		write(STDOUT_FILENO, buf, strlen(buf));
1975		if (debug) {
1976			buf[strlen(buf) - 2] = '\0';
1977			syslog_r(LOG_DEBUG, &sdata, "<--- %s", buf);
1978		}
1979	}
1980}
1981
1982void
1983lreply(int n, const char *fmt, ...)
1984{
1985	va_list ap;
1986
1987	va_start(ap, fmt);
1988	(void)printf("%d- ", n);
1989	(void)vprintf(fmt, ap);
1990	va_end(ap);
1991	(void)printf("\r\n");
1992	(void)fflush(stdout);
1993	if (debug) {
1994		va_start(ap, fmt);
1995		syslog(LOG_DEBUG, "<--- %d- ", n);
1996		vsyslog(LOG_DEBUG, fmt, ap);
1997		va_end(ap);
1998	}
1999}
2000
2001static void
2002ack(char *s)
2003{
2004
2005	reply(250, "%s command successful.", s);
2006}
2007
2008void
2009nack(char *s)
2010{
2011
2012	reply(502, "%s command not implemented.", s);
2013}
2014
2015/* ARGSUSED */
2016void
2017yyerror(char *s)
2018{
2019	char *cp;
2020
2021	if ((cp = strchr(cbuf,'\n')))
2022		*cp = '\0';
2023	reply(500, "'%s': command not understood.", cbuf);
2024}
2025
2026void
2027delete(char *name)
2028{
2029	struct stat st;
2030
2031	LOGCMD("delete", name);
2032	if (stat(name, &st) < 0) {
2033		perror_reply(550, name);
2034		return;
2035	}
2036	if ((st.st_mode&S_IFMT) == S_IFDIR) {
2037		if (rmdir(name) < 0) {
2038			perror_reply(550, name);
2039			return;
2040		}
2041		goto done;
2042	}
2043	if (unlink(name) < 0) {
2044		perror_reply(550, name);
2045		return;
2046	}
2047done:
2048	ack("DELE");
2049}
2050
2051void
2052cwd(char *path)
2053{
2054	FILE *message;
2055
2056	if (chdir(path) < 0)
2057		perror_reply(550, path);
2058	else {
2059		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2060			char *cp, line[LINE_MAX];
2061
2062			while (fgets(line, sizeof(line), message) != NULL) {
2063				if ((cp = strchr(line, '\n')) != NULL)
2064					*cp = '\0';
2065				lreply(250, "%s", line);
2066			}
2067			(void) fflush(stdout);
2068			(void) fclose(message);
2069		}
2070		ack("CWD");
2071	}
2072}
2073
2074void
2075replydirname(const char *name, const char *message)
2076{
2077	char *p, *ep;
2078	char npath[MAXPATHLEN * 2];
2079
2080	p = npath;
2081	ep = &npath[sizeof(npath) - 1];
2082	while (*name) {
2083		if (*name == '"') {
2084			if (ep - p < 2)
2085				break;
2086			*p++ = *name++;
2087			*p++ = '"';
2088		} else {
2089			if (ep - p < 1)
2090				break;
2091			*p++ = *name++;
2092		}
2093	}
2094	*p = '\0';
2095	reply(257, "\"%s\" %s", npath, message);
2096}
2097
2098void
2099makedir(char *name)
2100{
2101
2102	LOGCMD("mkdir", name);
2103	if (mkdir(name, 0777) < 0)
2104		perror_reply(550, name);
2105	else
2106		replydirname(name, "directory created.");
2107}
2108
2109void
2110removedir(char *name)
2111{
2112
2113	LOGCMD("rmdir", name);
2114	if (rmdir(name) < 0)
2115		perror_reply(550, name);
2116	else
2117		ack("RMD");
2118}
2119
2120void
2121pwd(void)
2122{
2123	char path[MAXPATHLEN];
2124
2125	if (getcwd(path, sizeof(path)) == NULL)
2126		perror_reply(550, "Can't get current directory");
2127	else
2128		replydirname(path, "is current directory.");
2129}
2130
2131char *
2132renamefrom(char *name)
2133{
2134	struct stat st;
2135
2136	if (stat(name, &st) < 0) {
2137		perror_reply(550, name);
2138		return ((char *)0);
2139	}
2140	reply(350, "File exists, ready for destination name");
2141	return (name);
2142}
2143
2144void
2145renamecmd(char *from, char *to)
2146{
2147
2148	LOGCMD2("rename", from, to);
2149	if (rename(from, to) < 0)
2150		perror_reply(550, "rename");
2151	else
2152		ack("RNTO");
2153}
2154
2155static void
2156dolog(struct sockaddr *sa)
2157{
2158	char hbuf[sizeof(remotehost)];
2159
2160	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0) == 0)
2161		(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2162	else
2163		(void) strlcpy(remotehost, "unknown", sizeof(remotehost));
2164
2165#ifdef HASSETPROCTITLE
2166	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2167	setproctitle("%s", proctitle);
2168#endif /* HASSETPROCTITLE */
2169
2170	if (logging)
2171		syslog(LOG_INFO, "connection from %s", remotehost);
2172}
2173
2174/*
2175 * Record logout in wtmp file and exit with supplied status.
2176 * NOTE: because this is called from signal handlers it cannot
2177 *       use stdio (or call other functions that use stdio).
2178 */
2179void
2180dologout(int status)
2181{
2182
2183	transflag = 0;
2184
2185	if (logged_in) {
2186		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2187		ftpdlogwtmp(ttyline, "", "");
2188		if (doutmp)
2189			ftpd_logout(utmp.ut_line);
2190	}
2191	/* beware of flushing buffers after a SIGPIPE */
2192	_exit(status);
2193}
2194
2195/*ARGSUSED*/
2196static void
2197sigurg(int signo)
2198{
2199
2200	recvurg = 1;
2201}
2202
2203static void
2204myoob(void)
2205{
2206	char *cp;
2207
2208	/* only process if transfer occurring */
2209	if (!transflag)
2210		return;
2211	cp = tmpline;
2212	if (getline(cp, 7, stdin) == NULL) {
2213		reply(221, "You could at least say goodbye.");
2214		dologout(0);
2215	}
2216	upper(cp);
2217	if (strcmp(cp, "ABOR\r\n") == 0) {
2218		tmpline[0] = '\0';
2219		reply(426, "Transfer aborted. Data connection closed.");
2220		reply(226, "Abort successful");
2221	}
2222	if (strcmp(cp, "STAT\r\n") == 0) {
2223		tmpline[0] = '\0';
2224		if (file_size != (off_t) -1)
2225			reply(213, "Status: %qd of %qd bytes transferred",
2226			    byte_count, file_size);
2227		else
2228			reply(213, "Status: %qd bytes transferred", byte_count);
2229	}
2230}
2231
2232/*
2233 * Note: a response of 425 is not mentioned as a possible response to
2234 *	the PASV command in RFC959. However, it has been blessed as
2235 *	a legitimate response by Jon Postel in a telephone conversation
2236 *	with Rick Adams on 25 Jan 89.
2237 */
2238void
2239passive(void)
2240{
2241	socklen_t len;
2242	int on;
2243	u_char *p, *a;
2244
2245	if (pw == NULL) {
2246		reply(530, "Please login with USER and PASS");
2247		return;
2248	}
2249	if (pdata >= 0)
2250		close(pdata);
2251	/*
2252	 * XXX
2253	 * At this point, it would be nice to have an algorithm that
2254	 * inserted a growing delay in an attack scenario.  Such a thing
2255	 * would look like continual passive sockets being opened, but
2256	 * nothing serious being done with them.  They're not used to
2257	 * move data; the entire attempt is just to use tcp FIN_WAIT
2258	 * resources.
2259	 */
2260	pdata = socket(AF_INET, SOCK_STREAM, 0);
2261	if (pdata < 0) {
2262		perror_reply(425, "Can't open passive connection");
2263		return;
2264	}
2265
2266	on = IP_PORTRANGE_HIGH;
2267	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2268	    &on, sizeof(on)) < 0)
2269		goto pasv_error;
2270
2271	pasv_addr = ctrl_addr;
2272	pasv_addr.su_sin.sin_port = 0;
2273	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2274	    pasv_addr.su_len) < 0)
2275		goto pasv_error;
2276
2277	len = sizeof(pasv_addr);
2278	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2279		goto pasv_error;
2280	if (listen(pdata, 1) < 0)
2281		goto pasv_error;
2282	a = (u_char *)&pasv_addr.su_sin.sin_addr;
2283	p = (u_char *)&pasv_addr.su_sin.sin_port;
2284
2285	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2286	    a[1], a[2], a[3], p[0], p[1]);
2287	return;
2288
2289pasv_error:
2290	(void) close(pdata);
2291	pdata = -1;
2292	perror_reply(425, "Can't open passive connection");
2293	return;
2294}
2295
2296int
2297epsvproto2af(int proto)
2298{
2299
2300	switch (proto) {
2301	case 1:	return AF_INET;
2302#ifdef INET6
2303	case 2:	return AF_INET6;
2304#endif
2305	default: return -1;
2306	}
2307}
2308
2309int
2310af2epsvproto(int af)
2311{
2312
2313	switch (af) {
2314	case AF_INET:	return 1;
2315#ifdef INET6
2316	case AF_INET6:	return 2;
2317#endif
2318	default:	return -1;
2319	}
2320}
2321
2322/*
2323 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2324 * 229 Entering Extended Passive Mode (|||port|)
2325 */
2326void
2327long_passive(char *cmd, int pf)
2328{
2329	socklen_t len;
2330	int on;
2331	u_char *p, *a;
2332
2333	if (!logged_in) {
2334		syslog(LOG_NOTICE, "long passive but not logged in");
2335		reply(503, "Login with USER first.");
2336		return;
2337	}
2338
2339	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2340		/*
2341		 * XXX
2342		 * only EPRT/EPSV ready clients will understand this
2343		 */
2344		if (strcmp(cmd, "EPSV") != 0)
2345			reply(501, "Network protocol mismatch"); /*XXX*/
2346		else
2347			epsv_protounsupp("Network protocol mismatch");
2348
2349		return;
2350	}
2351
2352	if (pdata >= 0)
2353		close(pdata);
2354	/*
2355	 * XXX
2356	 * At this point, it would be nice to have an algorithm that
2357	 * inserted a growing delay in an attack scenario.  Such a thing
2358	 * would look like continual passive sockets being opened, but
2359	 * nothing serious being done with them.  They not used to move
2360	 * data; the entire attempt is just to use tcp FIN_WAIT
2361	 * resources.
2362	 */
2363	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2364	if (pdata < 0) {
2365		perror_reply(425, "Can't open passive connection");
2366		return;
2367	}
2368
2369	switch (ctrl_addr.su_family) {
2370	case AF_INET:
2371		on = IP_PORTRANGE_HIGH;
2372		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2373		    &on, sizeof(on)) < 0)
2374			goto pasv_error;
2375		break;
2376	case AF_INET6:
2377		on = IPV6_PORTRANGE_HIGH;
2378		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2379		    &on, sizeof(on)) < 0)
2380			goto pasv_error;
2381		break;
2382	}
2383
2384	pasv_addr = ctrl_addr;
2385	pasv_addr.su_port = 0;
2386	if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
2387		goto pasv_error;
2388	len = pasv_addr.su_len;
2389	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2390		goto pasv_error;
2391	if (listen(pdata, 1) < 0)
2392		goto pasv_error;
2393	p = (u_char *)&pasv_addr.su_port;
2394
2395	if (strcmp(cmd, "LPSV") == 0) {
2396		switch (pasv_addr.su_family) {
2397		case AF_INET:
2398			a = (u_char *)&pasv_addr.su_sin.sin_addr;
2399			reply(228,
2400			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2401			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2402			return;
2403		case AF_INET6:
2404			a = (u_char *)&pasv_addr.su_sin6.sin6_addr;
2405			reply(228,
2406			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2407			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2408				6, 16, a[0], a[1], a[2], a[3], a[4],
2409				a[5], a[6], a[7], a[8], a[9], a[10],
2410				a[11], a[12], a[13], a[14], a[15],
2411				2, p[0], p[1]);
2412			return;
2413		}
2414	} else if (strcmp(cmd, "EPSV") == 0) {
2415		switch (pasv_addr.su_family) {
2416		case AF_INET:
2417		case AF_INET6:
2418			reply(229, "Entering Extended Passive Mode (|||%u|)",
2419			    ntohs(pasv_addr.su_port));
2420			return;
2421		}
2422	} else {
2423		/* more proper error code? */
2424	}
2425
2426  pasv_error:
2427	(void) close(pdata);
2428	pdata = -1;
2429	perror_reply(425, "Can't open passive connection");
2430	return;
2431}
2432
2433/*
2434 * EPRT |proto|addr|port|
2435 */
2436int
2437extended_port(const char *arg)
2438{
2439	char *tmp = NULL;
2440	char *result[3];
2441	char *p, *q;
2442	char delim;
2443	struct addrinfo hints;
2444	struct addrinfo *res = NULL;
2445	int i;
2446	unsigned long proto;
2447
2448	if (epsvall) {
2449		reply(501, "EPRT disallowed after EPSV ALL");
2450		return -1;
2451	}
2452
2453	usedefault = 0;
2454	if (pdata >= 0) {
2455		(void) close(pdata);
2456		pdata = -1;
2457	}
2458
2459	tmp = strdup(arg);
2460	if (!tmp) {
2461		fatal("not enough core.");
2462		/*NOTREACHED*/
2463	}
2464	p = tmp;
2465	delim = p[0];
2466	p++;
2467	memset(result, 0, sizeof(result));
2468	for (i = 0; i < 3; i++) {
2469		q = strchr(p, delim);
2470		if (!q || *q != delim)
2471			goto parsefail;
2472		*q++ = '\0';
2473		result[i] = p;
2474		p = q;
2475	}
2476
2477	/* some more sanity check */
2478	p = NULL;
2479	(void)strtoul(result[2], &p, 10);
2480	if (!*result[2] || *p)
2481		goto protounsupp;
2482	p = NULL;
2483	proto = strtoul(result[0], &p, 10);
2484	if (!*result[0] || *p)
2485		goto protounsupp;
2486
2487	memset(&hints, 0, sizeof(hints));
2488	hints.ai_family = epsvproto2af((int)proto);
2489	if (hints.ai_family < 0)
2490		goto protounsupp;
2491	hints.ai_socktype = SOCK_STREAM;
2492	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2493	if (getaddrinfo(result[1], result[2], &hints, &res))
2494		goto parsefail;
2495	if (res->ai_next)
2496		goto parsefail;
2497	if (sizeof(data_dest) < res->ai_addrlen)
2498		goto parsefail;
2499	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2500	if (his_addr.su_family == AF_INET6 &&
2501	    data_dest.su_family == AF_INET6) {
2502		/* XXX more sanity checks! */
2503		data_dest.su_sin6.sin6_scope_id =
2504		    his_addr.su_sin6.sin6_scope_id;
2505	}
2506	if (pdata >= 0) {
2507		(void) close(pdata);
2508		pdata = -1;
2509	}
2510	reply(200, "EPRT command successful.");
2511
2512	if (tmp)
2513		free(tmp);
2514	if (res)
2515		freeaddrinfo(res);
2516	return 0;
2517
2518parsefail:
2519	reply(500, "Invalid argument, rejected.");
2520	usedefault = 1;
2521	if (tmp)
2522		free(tmp);
2523	if (res)
2524		freeaddrinfo(res);
2525	return -1;
2526
2527protounsupp:
2528	epsv_protounsupp("Protocol not supported");
2529	usedefault = 1;
2530	if (tmp)
2531		free(tmp);
2532	if (res)
2533		freeaddrinfo(res);
2534	return -1;
2535}
2536
2537/*
2538 * 522 Protocol not supported (proto,...)
2539 * as we assume address family for control and data connections are the same,
2540 * we do not return the list of address families we support - instead, we
2541 * return the address family of the control connection.
2542 */
2543void
2544epsv_protounsupp(const char *message)
2545{
2546	int proto;
2547
2548	proto = af2epsvproto(ctrl_addr.su_family);
2549	if (proto < 0)
2550		reply(501, "%s", message);	/*XXX*/
2551	else
2552		reply(522, "%s, use (%d)", message, proto);
2553}
2554
2555/*
2556 * Generate unique name for file with basename "local".
2557 * The file named "local" is already known to exist.
2558 * Generates failure reply on error.
2559 */
2560static int
2561guniquefd(char *local, char **nam)
2562{
2563	static char new[MAXPATHLEN];
2564	struct stat st;
2565	int count, len, fd;
2566	char *cp;
2567
2568	cp = strrchr(local, '/');
2569	if (cp)
2570		*cp = '\0';
2571	if (stat(cp ? local : ".", &st) < 0) {
2572		perror_reply(553, cp ? local : ".");
2573		return (-1);
2574	}
2575	if (cp)
2576		*cp = '/';
2577	len = strlcpy(new, local, sizeof(new));
2578	if (len+2+1 >= sizeof(new)-1)
2579		return (-1);
2580	cp = new + len;
2581	*cp++ = '.';
2582	for (count = 1; count < 100; count++) {
2583		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2584		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2585		if (fd == -1)
2586			continue;
2587		if (nam)
2588			*nam = new;
2589		return (fd);
2590	}
2591	reply(452, "Unique file name cannot be created.");
2592	return (-1);
2593}
2594
2595/*
2596 * Format and send reply containing system error number.
2597 */
2598void
2599perror_reply(int code, char *string)
2600{
2601
2602	reply(code, "%s: %s.", string, strerror(errno));
2603}
2604
2605static char *onefile[] = {
2606	"",
2607	0
2608};
2609
2610void
2611send_file_list(char *whichf)
2612{
2613	struct stat st;
2614	DIR *dirp = NULL;
2615	struct dirent *dir;
2616	FILE *dout = NULL;
2617	char **dirlist;
2618	char *dirname;
2619	int simple = 0;
2620	volatile int freeglob = 0;
2621	glob_t gl;
2622
2623	if (strpbrk(whichf, "~{[*?") != NULL) {
2624		memset(&gl, 0, sizeof(gl));
2625		freeglob = 1;
2626		if (glob(whichf,
2627		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2628		    0, &gl)) {
2629			reply(550, "not found");
2630			goto out;
2631		} else if (gl.gl_pathc == 0) {
2632			errno = ENOENT;
2633			perror_reply(550, whichf);
2634			goto out;
2635		}
2636		dirlist = gl.gl_pathv;
2637	} else {
2638		onefile[0] = whichf;
2639		dirlist = onefile;
2640		simple = 1;
2641	}
2642
2643	while ((dirname = *dirlist++)) {
2644		if (stat(dirname, &st) < 0) {
2645			/*
2646			 * If user typed "ls -l", etc, and the client
2647			 * used NLST, do what the user meant.
2648			 */
2649			if (dirname[0] == '-' && *dirlist == NULL &&
2650			    transflag == 0) {
2651				retrieve("/bin/ls %s", dirname);
2652				goto out;
2653			}
2654			perror_reply(550, whichf);
2655			if (dout != NULL) {
2656				(void) fclose(dout);
2657				transflag = 0;
2658				data = -1;
2659				pdata = -1;
2660			}
2661			goto out;
2662		}
2663
2664		if (S_ISREG(st.st_mode)) {
2665			if (dout == NULL) {
2666				dout = dataconn("file list", (off_t)-1, "w");
2667				if (dout == NULL)
2668					goto out;
2669				transflag++;
2670			}
2671			fprintf(dout, "%s%s\n", dirname,
2672				type == TYPE_A ? "\r" : "");
2673			byte_count += strlen(dirname) + 1;
2674			continue;
2675		} else if (!S_ISDIR(st.st_mode))
2676			continue;
2677
2678		if ((dirp = opendir(dirname)) == NULL)
2679			continue;
2680
2681		while ((dir = readdir(dirp)) != NULL) {
2682			char nbuf[MAXPATHLEN];
2683
2684			if (recvurg) {
2685				myoob();
2686				recvurg = 0;
2687				transflag = 0;
2688				goto out;
2689			}
2690
2691			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2692				continue;
2693			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2694			    dir->d_namlen == 2)
2695				continue;
2696
2697			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2698				 dir->d_name);
2699
2700			/*
2701			 * We have to do a stat to insure it's
2702			 * not a directory or special file.
2703			 */
2704			if (simple || (stat(nbuf, &st) == 0 &&
2705			    S_ISREG(st.st_mode))) {
2706				if (dout == NULL) {
2707					dout = dataconn("file list", (off_t)-1,
2708						"w");
2709					if (dout == NULL)
2710						goto out;
2711					transflag++;
2712				}
2713				if (nbuf[0] == '.' && nbuf[1] == '/')
2714					fprintf(dout, "%s%s\n", &nbuf[2],
2715						type == TYPE_A ? "\r" : "");
2716				else
2717					fprintf(dout, "%s%s\n", nbuf,
2718						type == TYPE_A ? "\r" : "");
2719				byte_count += strlen(nbuf) + 1;
2720			}
2721		}
2722		(void) closedir(dirp);
2723	}
2724
2725	if (dout == NULL)
2726		reply(550, "No files found.");
2727	else if (ferror(dout) != 0)
2728		perror_reply(550, "Data connection");
2729	else
2730		reply(226, "Transfer complete.");
2731
2732	transflag = 0;
2733	if (dout != NULL)
2734		(void) fclose(dout);
2735	else {
2736		if (pdata >= 0)
2737			close(pdata);
2738	}
2739	data = -1;
2740	pdata = -1;
2741out:
2742	if (freeglob) {
2743		freeglob = 0;
2744		globfree(&gl);
2745	}
2746}
2747
2748/*ARGSUSED*/
2749static void
2750reapchild(int signo)
2751{
2752	int save_errno = errno;
2753	int rval;
2754
2755	do {
2756		rval = waitpid(-1, NULL, WNOHANG);
2757	} while (rval > 0 || (rval == -1 && errno == EINTR));
2758	errno = save_errno;
2759}
2760
2761void
2762logxfer(char *name, off_t size, time_t start)
2763{
2764	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2765	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2766	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2767	char *vpw;
2768	time_t now;
2769	int len;
2770
2771	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2772		time(&now);
2773
2774		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2775		if (vpw == NULL)
2776			return;
2777
2778		snprintf(path, sizeof(path), "%s/%s", dir, name);
2779		if (realpath(path, rpath) == NULL)
2780			strlcpy(rpath, path, sizeof(rpath));
2781		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2782
2783		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2784		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2785
2786		len = snprintf(buf, sizeof(buf),
2787		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2788		    ctime(&now), now - start + (now == start),
2789		    vremotehost, (long long)size, vpath,
2790		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2791		    'o', ((guest) ? 'a' : 'r'),
2792		    vpw, 0 /* none yet */,
2793		    ((guest) ? "*" : pw->pw_name), dhostname);
2794
2795		if (len >= sizeof(buf) || len == -1) {
2796			if ((len = strlen(buf)) == 0)
2797				return;		/* should not happen */
2798			buf[len - 1] = '\n';
2799		}
2800		write(statfd, buf, len);
2801		free(vpw);
2802	}
2803}
2804
2805void
2806set_slave_signals(void)
2807{
2808	struct sigaction sa;
2809
2810	sigemptyset(&sa.sa_mask);
2811	sa.sa_flags = SA_RESTART;
2812
2813	sa.sa_handler = SIG_DFL;
2814	(void) sigaction(SIGCHLD, &sa, NULL);
2815
2816	sa.sa_handler = sigurg;
2817	sa.sa_flags = 0;		/* don't restart syscalls for SIGURG */
2818	(void) sigaction(SIGURG, &sa, NULL);
2819
2820	sigfillset(&sa.sa_mask);	/* block all signals in handler */
2821	sa.sa_flags = SA_RESTART;
2822	sa.sa_handler = sigquit;
2823	(void) sigaction(SIGHUP, &sa, NULL);
2824	(void) sigaction(SIGINT, &sa, NULL);
2825	(void) sigaction(SIGQUIT, &sa, NULL);
2826	(void) sigaction(SIGTERM, &sa, NULL);
2827
2828	sa.sa_handler = lostconn;
2829	(void) sigaction(SIGPIPE, &sa, NULL);
2830
2831	sa.sa_handler = toolong;
2832	(void) sigaction(SIGALRM, &sa, NULL);
2833
2834#ifdef F_SETOWN
2835	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2836		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
2837#endif
2838}
2839
2840#if defined(TCPWRAPPERS)
2841static int
2842check_host(struct sockaddr *sa)
2843{
2844	struct sockaddr_in *sin;
2845	struct hostent *hp;
2846	char *addr;
2847
2848	if (sa->sa_family != AF_INET)
2849		return 1;	/*XXX*/
2850
2851	sin = (struct sockaddr_in *)sa;
2852	hp = gethostbyaddr((char *)&sin->sin_addr,
2853	    sizeof(struct in_addr), AF_INET);
2854	addr = inet_ntoa(sin->sin_addr);
2855	if (hp) {
2856		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2857			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2858			    hp->h_name, addr);
2859			return (0);
2860		}
2861	} else {
2862		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2863			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2864			return (0);
2865		}
2866	}
2867	return (1);
2868}
2869#endif	/* TCPWRAPPERS */
2870
2871/*
2872 * Allocate space and return a copy of the specified dir.
2873 * If 'dir' begins with a tilde (~), expand it.
2874 */
2875char *
2876copy_dir(char *dir, struct passwd *pw)
2877{
2878	char *cp;
2879	char *newdir;
2880	char *user = NULL;
2881	size_t dirsiz;
2882
2883	/* Nothing to expand */
2884	if (dir[0] != '~')
2885		return (strdup(dir));
2886
2887	/* "dir" is of form ~user/some/dir, lookup user. */
2888	if (dir[1] != '/' && dir[1] != '\0') {
2889		if ((cp = strchr(dir + 1, '/')) == NULL)
2890		    cp = dir + strlen(dir);
2891		if ((user = malloc((size_t)(cp - dir))) == NULL)
2892			return (NULL);
2893		strlcpy(user, dir + 1, (size_t)(cp - dir));
2894
2895		/* Only do lookup if it is a different user. */
2896		if (strcmp(user, pw->pw_name) != 0) {
2897			if ((pw = getpwnam(user)) == NULL) {
2898				/* No such user, interpret literally */
2899				free(user);
2900				return(strdup(dir));
2901			}
2902		}
2903	}
2904
2905	/*
2906	 * If there is no directory separator (/) then it is just pw_dir.
2907	 * Otherwise, replace ~foo with  pw_dir.
2908	 */
2909	if ((cp = strchr(dir + 1, '/')) == NULL) {
2910		newdir = strdup(pw->pw_dir);
2911	} else {
2912		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2913		if ((newdir = malloc(dirsiz)) == NULL) {
2914			free(user);
2915			return (NULL);
2916		}
2917		strlcpy(newdir, pw->pw_dir, dirsiz);
2918		strlcat(newdir, cp, dirsiz);
2919	}
2920
2921	if (user)
2922		free(user);
2923	return(newdir);
2924}
2925