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