ftpd.c revision 1.171
1/*	$OpenBSD: ftpd.c,v 1.171 2006/04/21 17:42:50 deraadt Exp $	*/
2/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. 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.171 2006/04/21 17:42:50 deraadt 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
128static char version[] = "Version 6.6/OpenBSD";
129
130extern	off_t restart_point;
131extern	char cbuf[];
132
133union sockunion ctrl_addr;
134union sockunion data_source;
135union sockunion data_dest;
136union sockunion his_addr;
137union sockunion pasv_addr;
138
139sigset_t allsigs;
140
141int	daemon_mode = 0;
142int	data;
143int	logged_in;
144struct	passwd *pw;
145int	debug = 0;
146int	timeout = 900;    /* timeout after 15 minutes of inactivity */
147int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
148int	logging;
149int	anon_ok = 1;
150int	anon_only = 0;
151int	multihome = 0;
152int	guest;
153int	stats;
154int	statfd = -1;
155int	portcheck = 1;
156int	dochroot;
157int	type;
158int	form;
159int	stru;			/* avoid C keyword */
160int	mode;
161int	doutmp = 0;		/* update utmp file */
162int	usedefault = 1;		/* for data transfers */
163int	pdata = -1;		/* for passive mode */
164int	family = AF_UNSPEC;
165volatile sig_atomic_t transflag;
166off_t	file_size;
167off_t	byte_count;
168#if !defined(CMASK) || CMASK == 0
169#undef CMASK
170#define CMASK 022
171#endif
172mode_t	defumask = CMASK;		/* default umask value */
173int	umaskchange = 1;		/* allow user to change umask value. */
174char	tmpline[7];
175char	hostname[MAXHOSTNAMELEN];
176char	remotehost[MAXHOSTNAMELEN];
177char	dhostname[MAXHOSTNAMELEN];
178char	*guestpw;
179char	ttyline[20];
180#if 0
181char	*tty = ttyline;		/* for klogin */
182#endif
183static struct utmp utmp;	/* for utmp */
184static	login_cap_t *lc;
185static	auth_session_t *as;
186static	volatile sig_atomic_t recvurg;
187
188#if defined(TCPWRAPPERS)
189int	allow_severity = LOG_INFO;
190int	deny_severity = LOG_NOTICE;
191#endif	/* TCPWRAPPERS */
192
193char	*ident = NULL;
194
195
196int epsvall = 0;
197
198/*
199 * Timeout intervals for retrying connections
200 * to hosts that don't accept PORT cmds.  This
201 * is a kludge, but given the problems with TCP...
202 */
203#define	SWAITMAX	90	/* wait at most 90 seconds */
204#define	SWAITINT	5	/* interval between retries */
205
206int	swaitmax = SWAITMAX;
207int	swaitint = SWAITINT;
208
209#ifdef HASSETPROCTITLE
210char	proctitle[BUFSIZ];	/* initial part of title */
211#endif /* HASSETPROCTITLE */
212
213#define LOGCMD(cmd, file) \
214	if (logging > 1) \
215	    syslog(LOG_INFO,"%s %s%s", cmd, \
216		*(file) == '/' ? "" : curdir(), file);
217#define LOGCMD2(cmd, file1, file2) \
218	 if (logging > 1) \
219	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
220		*(file1) == '/' ? "" : curdir(), file1, \
221		*(file2) == '/' ? "" : curdir(), file2);
222#define LOGBYTES(cmd, file, cnt) \
223	if (logging > 1) { \
224		if (cnt == (off_t)-1) \
225		    syslog(LOG_INFO,"%s %s%s", cmd, \
226			*(file) == '/' ? "" : curdir(), file); \
227		else \
228		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
229			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
230	}
231
232static void	 ack(char *);
233static void	 sigurg(int);
234static void	 myoob(void);
235static int	 checkuser(char *, char *);
236static FILE	*dataconn(char *, off_t, char *);
237static void	 dolog(struct sockaddr *);
238static char	*copy_dir(char *, struct passwd *);
239static char	*curdir(void);
240static void	 end_login(void);
241static FILE	*getdatasock(char *);
242static int	 guniquefd(char *, char **);
243static void	 lostconn(int);
244static void	 sigquit(int);
245static int	 receive_data(FILE *, FILE *);
246static void	 replydirname(const char *, const char *);
247static int	 send_data(FILE *, FILE *, off_t, off_t, int);
248static struct passwd *
249		 sgetpwnam(char *, struct passwd *);
250static void	 reapchild(int);
251#if defined(TCPWRAPPERS)
252static int	 check_host(struct sockaddr *);
253#endif /* TCPWRAPPERS */
254static void	 usage(void);
255
256void	 logxfer(char *, off_t, time_t);
257void	 set_slave_signals(void);
258
259static char *
260curdir(void)
261{
262	static char path[MAXPATHLEN+1];	/* path + '/' */
263
264	if (getcwd(path, sizeof(path)-1) == NULL)
265		return ("");
266	if (path[1] != '\0')		/* special case for root dir. */
267		strlcat(path, "/", sizeof path);
268	/* For guest account, skip / since it's chrooted */
269	return (guest ? path+1 : path);
270}
271
272char *argstr = "AdDhnlMSt:T:u:UvP46";
273
274static void
275usage(void)
276{
277	syslog(LOG_ERR,
278	    "usage: ftpd [-46ADdlMnPSU] [-T maxtimeout] [-t timeout] [-u mask]");
279	exit(2);
280}
281
282int
283main(int argc, char *argv[])
284{
285	socklen_t addrlen;
286	int ch, on = 1, tos;
287	char *cp, line[LINE_MAX];
288	FILE *fp;
289	struct hostent *hp;
290	struct sigaction sa;
291	int error = 0;
292
293	tzset();		/* in case no timezone database in ~ftp */
294	sigfillset(&allsigs);	/* used to block signals while root */
295	sigemptyset(&sa.sa_mask);
296	sa.sa_flags = SA_RESTART;
297
298	while ((ch = getopt(argc, argv, argstr)) != -1) {
299		switch (ch) {
300		case 'A':
301			anon_only = 1;
302			break;
303
304		case 'd':
305		case 'v':		/* deprecated */
306			debug = 1;
307			break;
308
309		case 'D':
310			daemon_mode = 1;
311			break;
312
313		case 'P':
314			portcheck = 0;
315			break;
316
317		case 'h':		/* deprecated */
318			break;
319
320		case 'l':
321			logging++;	/* > 1 == extra logging */
322			break;
323
324		case 'M':
325			multihome = 1;
326			break;
327
328		case 'n':
329			anon_ok = 0;
330			break;
331
332		case 'S':
333			stats = 1;
334			break;
335
336		case 't':
337			timeout = atoi(optarg);
338			if (maxtimeout < timeout)
339				maxtimeout = timeout;
340			break;
341
342		case 'T':
343			maxtimeout = atoi(optarg);
344			if (timeout > maxtimeout)
345				timeout = maxtimeout;
346			break;
347
348		case 'u':
349		    {
350			long val = 0;
351			char *p;
352			umaskchange = 0;
353
354			val = strtol(optarg, &p, 8);
355			if (*p != '\0' || val < 0 || (val & ~ACCESSPERMS)) {
356				syslog(LOG_ERR,
357				    "%s is a bad value for -u, aborting..",
358				    optarg);
359				exit(2);
360			} else
361				defumask = val;
362			break;
363		    }
364
365		case 'U':
366			doutmp = 1;
367			break;
368
369		case '4':
370			family = AF_INET;
371			break;
372
373		case '6':
374			family = AF_INET6;
375			break;
376
377		default:
378			usage();
379			break;
380		}
381	}
382
383	(void) freopen(_PATH_DEVNULL, "w", stderr);
384
385	/*
386	 * LOG_NDELAY sets up the logging connection immediately,
387	 * necessary for anonymous ftp's that chroot and can't do it later.
388	 */
389	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
390
391	if (getpwnam(FTPD_PRIVSEP_USER) == NULL) {
392		syslog(LOG_ERR, "privilege separation user %s not found",
393		    FTPD_PRIVSEP_USER);
394		exit(1);
395	}
396	endpwent();
397
398	if (daemon_mode) {
399		int *fds, i, fd;
400		struct pollfd *pfds;
401		struct addrinfo hints, *res, *res0;
402		nfds_t n;
403
404		/*
405		 * Detach from parent.
406		 */
407		if (daemon(1, 1) < 0) {
408			syslog(LOG_ERR, "failed to become a daemon");
409			exit(1);
410		}
411		sa.sa_handler = reapchild;
412		(void) sigaction(SIGCHLD, &sa, NULL);
413
414		memset(&hints, 0, sizeof(hints));
415		hints.ai_family = family;
416		hints.ai_socktype = SOCK_STREAM;
417		hints.ai_protocol = IPPROTO_TCP;
418		hints.ai_flags = AI_PASSIVE;
419		error = getaddrinfo(NULL, "ftp", &hints, &res0);
420		if (error) {
421			syslog(LOG_ERR, "%s", gai_strerror(error));
422			exit(1);
423		}
424
425		n = 0;
426		for (res = res0; res; res = res->ai_next)
427			n++;
428
429		fds = malloc(n * sizeof(int));
430		pfds = malloc(n * sizeof(struct pollfd));
431		if (!fds || !pfds) {
432			syslog(LOG_ERR, "%s", strerror(errno));
433			exit(1);
434		}
435
436		/*
437		 * Open sockets, bind it to the FTP port, and start
438		 * listening.
439		 */
440		n = 0;
441		for (res = res0; res; res = res->ai_next) {
442			fds[n] = socket(res->ai_family, res->ai_socktype,
443			    res->ai_protocol);
444			if (fds[n] < 0)
445				continue;
446
447			if (setsockopt(fds[n], SOL_SOCKET, SO_REUSEADDR,
448			    &on, sizeof(on)) < 0) {
449				close(fds[n]);
450				fds[n] = -1;
451				continue;
452			}
453
454			if (bind(fds[n], res->ai_addr, res->ai_addrlen) < 0) {
455				close(fds[n]);
456				fds[n] = -1;
457				continue;
458			}
459			if (listen(fds[n], 32) < 0) {
460				close(fds[n]);
461				fds[n] = -1;
462				continue;
463			}
464
465			pfds[n].fd = fds[n];
466			pfds[n].events = POLLIN;
467			n++;
468		}
469		freeaddrinfo(res0);
470
471		if (n == 0) {
472			syslog(LOG_ERR, "could not open control socket");
473			exit(1);
474		}
475
476		/* Stash pid in pidfile */
477		if (pidfile(NULL))
478			syslog(LOG_ERR, "can't open pidfile: %m");
479		/*
480		 * Loop forever accepting connection requests and forking off
481		 * children to handle them.
482		 */
483		while (1) {
484			if (poll(pfds, n, INFTIM) < 0) {
485				if (errno == EINTR)
486					continue;
487				syslog(LOG_ERR, "poll: %m");
488				exit(1);
489			}
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) fclose(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	if (debug)
659		syslog_r(LOG_DEBUG, &sdata, "lost connection");
660	dologout(1);
661}
662
663static void
664sigquit(int signo)
665{
666	struct syslog_data sdata = SYSLOG_DATA_INIT;
667
668	syslog_r(LOG_ERR, &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();
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();
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();
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();
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();
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;
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			perror_reply(425, "Can't build data connection");
1421			(void) close(pdata);
1422			(void) close(s);
1423			pdata = -1;
1424			return (NULL);
1425		}
1426		if (from.su_family != his_addr.su_family ||
1427		    ntohs(*p) < IPPORT_RESERVED) {
1428			perror_reply(425, "Can't build data connection");
1429			(void) close(pdata);
1430			(void) close(s);
1431			pdata = -1;
1432			return (NULL);
1433		}
1434		if (portcheck && memcmp(fa, ha, alen) != 0) {
1435			perror_reply(435, "Can't build data connection");
1436			(void) close(pdata);
1437			(void) close(s);
1438			pdata = -1;
1439			return (NULL);
1440		}
1441		(void) close(pdata);
1442		pdata = s;
1443		reply(150, "Opening %s mode data connection for '%s'%s.",
1444		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1445		return (fdopen(pdata, mode));
1446	}
1447	if (data >= 0) {
1448		reply(125, "Using existing data connection for '%s'%s.",
1449		    name, sizebuf);
1450		usedefault = 1;
1451		return (fdopen(data, mode));
1452	}
1453	if (usedefault)
1454		data_dest = his_addr;
1455	usedefault = 1;
1456	do {
1457		file = getdatasock(mode);
1458		if (file == NULL) {
1459			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1460
1461			error = getnameinfo((struct sockaddr *)&data_source,
1462			    data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1463			    sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1464			if (error != 0)
1465				reply(425, "Can't create data socket: %s.",
1466				    strerror(errno));
1467			else
1468				reply(425,
1469				    "Can't create data socket (%s,%s): %s.",
1470				    hbuf, pbuf, strerror(errno));
1471			return (NULL);
1472		}
1473
1474		/*
1475		 * attempt to connect to reserved port on client machine;
1476		 * this looks like an attack
1477		 */
1478		switch (data_dest.su_family) {
1479		case AF_INET:
1480			p = (in_port_t *)&data_dest.su_sin.sin_port;
1481			fa = (u_char *)&data_dest.su_sin.sin_addr;
1482			ha = (u_char *)&his_addr.su_sin.sin_addr;
1483			alen = sizeof(struct in_addr);
1484			break;
1485		case AF_INET6:
1486			p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1487			fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1488			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1489			alen = sizeof(struct in6_addr);
1490			break;
1491		default:
1492			perror_reply(425, "Can't build data connection");
1493			(void) fclose(file);
1494			pdata = -1;
1495			return (NULL);
1496		}
1497		if (data_dest.su_family != his_addr.su_family ||
1498		    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
1499			perror_reply(425, "Can't build data connection");
1500			(void) fclose(file);
1501			return NULL;
1502		}
1503		if (portcheck && memcmp(fa, ha, alen) != 0) {
1504			perror_reply(435, "Can't build data connection");
1505			(void) fclose(file);
1506			return NULL;
1507		}
1508
1509		if (connect(fileno(file), (struct sockaddr *)&data_dest,
1510		    data_dest.su_len) == 0) {
1511			reply(150, "Opening %s mode data connection for '%s'%s.",
1512			    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1513			data = fileno(file);
1514			return (file);
1515		}
1516		if (errno != EADDRINUSE)
1517			break;
1518		(void) fclose(file);
1519		sleep((unsigned) swaitint);
1520		retry += swaitint;
1521	} while (retry <= swaitmax);
1522	perror_reply(425, "Can't build data connection");
1523	(void) fclose(file);
1524	return (NULL);
1525}
1526
1527/*
1528 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1529 * encapsulation of the data subject to Mode, Structure, and Type.
1530 *
1531 * NB: Form isn't handled.
1532 */
1533static int
1534send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1535{
1536	int c, cnt, filefd, netfd;
1537	char *buf, *bp;
1538	size_t len;
1539
1540	transflag++;
1541	switch (type) {
1542
1543	case TYPE_A:
1544		while ((c = getc(instr)) != EOF) {
1545			if (recvurg)
1546				goto got_oob;
1547			byte_count++;
1548			if (c == '\n') {
1549				if (ferror(outstr))
1550					goto data_err;
1551				(void) putc('\r', outstr);
1552			}
1553			(void) putc(c, outstr);
1554		}
1555		fflush(outstr);
1556		transflag = 0;
1557		if (ferror(instr))
1558			goto file_err;
1559		if (ferror(outstr))
1560			goto data_err;
1561		reply(226, "Transfer complete.");
1562		return(0);
1563
1564	case TYPE_I:
1565	case TYPE_L:
1566		/*
1567		 * isreg is only set if we are not doing restart and we
1568		 * are sending a regular file
1569		 */
1570		netfd = fileno(outstr);
1571		filefd = fileno(instr);
1572
1573		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1574			size_t fsize = (size_t)filesize;
1575
1576			buf = mmap(0, fsize, PROT_READ, MAP_SHARED, filefd,
1577			    (off_t)0);
1578			if (buf == MAP_FAILED) {
1579				syslog(LOG_WARNING, "mmap(%llu): %m",
1580				    (unsigned long long)fsize);
1581				goto oldway;
1582			}
1583			bp = buf;
1584			len = fsize;
1585			do {
1586				cnt = write(netfd, bp, len);
1587				if (recvurg) {
1588					munmap(buf, fsize);
1589					goto got_oob;
1590				}
1591				len -= cnt;
1592				bp += cnt;
1593				if (cnt > 0)
1594					byte_count += cnt;
1595			} while(cnt > 0 && len > 0);
1596
1597			transflag = 0;
1598			munmap(buf, fsize);
1599			if (cnt < 0)
1600				goto data_err;
1601			reply(226, "Transfer complete.");
1602			return(0);
1603		}
1604
1605oldway:
1606		if ((buf = malloc((size_t)blksize)) == NULL) {
1607			transflag = 0;
1608			perror_reply(451, "Local resource failure: malloc");
1609			return(-1);
1610		}
1611
1612		while ((cnt = read(filefd, buf, (size_t)blksize)) > 0 &&
1613		    write(netfd, buf, cnt) == cnt)
1614			byte_count += cnt;
1615		transflag = 0;
1616		(void)free(buf);
1617		if (cnt != 0) {
1618			if (cnt < 0)
1619				goto file_err;
1620			goto data_err;
1621		}
1622		reply(226, "Transfer complete.");
1623		return(0);
1624	default:
1625		transflag = 0;
1626		reply(550, "Unimplemented TYPE %d in send_data", type);
1627		return(-1);
1628	}
1629
1630data_err:
1631	transflag = 0;
1632	perror_reply(426, "Data connection");
1633	return(-1);
1634
1635file_err:
1636	transflag = 0;
1637	perror_reply(551, "Error on input file");
1638	return(-1);
1639
1640got_oob:
1641	myoob();
1642	recvurg = 0;
1643	transflag = 0;
1644	return(-1);
1645}
1646
1647/*
1648 * Transfer data from peer to "outstr" using the appropriate encapulation of
1649 * the data subject to Mode, Structure, and Type.
1650 *
1651 * N.B.: Form isn't handled.
1652 */
1653static int
1654receive_data(FILE *instr, FILE *outstr)
1655{
1656	int c;
1657	int cnt;
1658	char buf[BUFSIZ];
1659	struct sigaction sa, sa_saved;
1660	volatile int bare_lfs = 0;
1661
1662	transflag++;
1663	switch (type) {
1664
1665	case TYPE_I:
1666	case TYPE_L:
1667		memset(&sa, 0, sizeof(sa));
1668		sigfillset(&sa.sa_mask);
1669		sa.sa_flags = SA_RESTART;
1670		sa.sa_handler = lostconn;
1671		(void) sigaction(SIGALRM, &sa, &sa_saved);
1672		do {
1673			(void) alarm ((unsigned) timeout);
1674			cnt = read(fileno(instr), buf, sizeof(buf));
1675			(void) alarm (0);
1676			if (recvurg)
1677				goto got_oob;
1678
1679			if (cnt > 0) {
1680				if (write(fileno(outstr), buf, cnt) != cnt)
1681					goto file_err;
1682				byte_count += cnt;
1683			}
1684		} while (cnt > 0);
1685		(void) sigaction(SIGALRM, &sa_saved, NULL);
1686		if (cnt < 0)
1687			goto data_err;
1688		transflag = 0;
1689		return (0);
1690
1691	case TYPE_E:
1692		reply(553, "TYPE E not implemented.");
1693		transflag = 0;
1694		return (-1);
1695
1696	case TYPE_A:
1697		while ((c = getc(instr)) != EOF) {
1698			if (recvurg)
1699				goto got_oob;
1700			byte_count++;
1701			if (c == '\n')
1702				bare_lfs++;
1703			while (c == '\r') {
1704				if (ferror(outstr))
1705					goto data_err;
1706				if ((c = getc(instr)) != '\n') {
1707					(void) putc ('\r', outstr);
1708					if (c == '\0' || c == EOF)
1709						goto contin2;
1710				}
1711			}
1712			(void) putc(c, outstr);
1713	contin2:	;
1714		}
1715		fflush(outstr);
1716		if (ferror(instr))
1717			goto data_err;
1718		if (ferror(outstr))
1719			goto file_err;
1720		transflag = 0;
1721		if (bare_lfs) {
1722			lreply(226,
1723			    "WARNING! %d bare linefeeds received in ASCII mode",
1724			    bare_lfs);
1725			printf("   File may not have transferred correctly.\r\n");
1726		}
1727		return (0);
1728	default:
1729		reply(550, "Unimplemented TYPE %d in receive_data", type);
1730		transflag = 0;
1731		return (-1);
1732	}
1733
1734data_err:
1735	transflag = 0;
1736	perror_reply(426, "Data Connection");
1737	return (-1);
1738
1739file_err:
1740	transflag = 0;
1741	perror_reply(452, "Error writing file");
1742	return (-1);
1743
1744got_oob:
1745	myoob();
1746	recvurg = 0;
1747	transflag = 0;
1748	return (-1);
1749}
1750
1751void
1752statfilecmd(char *filename)
1753{
1754	FILE *fin;
1755	int c;
1756	int atstart;
1757	char line[LINE_MAX];
1758
1759	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1760	fin = ftpd_popen(line, "r");
1761	lreply(211, "status of %s:", filename);
1762	atstart = 1;
1763	while ((c = getc(fin)) != EOF) {
1764		if (c == '\n') {
1765			if (ferror(stdout)){
1766				perror_reply(421, "control connection");
1767				(void) ftpd_pclose(fin);
1768				dologout(1);
1769				/* NOTREACHED */
1770			}
1771			if (ferror(fin)) {
1772				perror_reply(551, filename);
1773				(void) ftpd_pclose(fin);
1774				return;
1775			}
1776			(void) putc('\r', stdout);
1777		}
1778		if (atstart && isdigit(c))
1779			(void) putc(' ', stdout);
1780		(void) putc(c, stdout);
1781		atstart = (c == '\n');
1782	}
1783	(void) ftpd_pclose(fin);
1784	reply(211, "End of Status");
1785}
1786
1787void
1788statcmd(void)
1789{
1790	union sockunion *su;
1791	u_char *a, *p;
1792	char hbuf[MAXHOSTNAMELEN];
1793	int ispassive;
1794	int error;
1795
1796	lreply(211, "%s FTP server status:", hostname);
1797	printf("     %s\r\n", version);
1798	error = getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1799	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1800	printf("     Connected to %s", remotehost);
1801	if (error == 0 && strcmp(remotehost, hbuf) != 0)
1802		printf(" (%s)", hbuf);
1803	printf("\r\n");
1804	if (logged_in) {
1805		if (guest)
1806			printf("     Logged in anonymously\r\n");
1807		else
1808			printf("     Logged in as %s\r\n", pw->pw_name);
1809	} else if (askpasswd)
1810		printf("     Waiting for password\r\n");
1811	else
1812		printf("     Waiting for user name\r\n");
1813	printf("     TYPE: %s", typenames[type]);
1814	if (type == TYPE_A || type == TYPE_E)
1815		printf(", FORM: %s", formnames[form]);
1816	if (type == TYPE_L)
1817#if NBBY == 8
1818		printf(" %d", NBBY);
1819#else
1820		printf(" %d", bytesize);	/* need definition! */
1821#endif
1822	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1823	    strunames[stru], modenames[mode]);
1824	ispassive = 0;
1825	if (data != -1)
1826		printf("     Data connection open\r\n");
1827	else if (pdata != -1) {
1828		printf("     in Passive mode\r\n");
1829		su = (union sockunion *)&pasv_addr;
1830		ispassive++;
1831		goto printaddr;
1832	} else if (usedefault == 0) {
1833		size_t alen;
1834		int af, i;
1835
1836		su = (union sockunion *)&data_dest;
1837printaddr:
1838		/* PASV/PORT */
1839		if (su->su_family == AF_INET) {
1840			if (ispassive)
1841				printf("211- PASV ");
1842			else
1843				printf("211- PORT ");
1844			a = (u_char *)&su->su_sin.sin_addr;
1845			p = (u_char *)&su->su_sin.sin_port;
1846			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1847			    a[0], a[1], a[2], a[3],
1848			    p[0], p[1]);
1849		}
1850
1851		/* LPSV/LPRT */
1852		alen = 0;
1853		switch (su->su_family) {
1854		case AF_INET:
1855			a = (u_char *)&su->su_sin.sin_addr;
1856			p = (u_char *)&su->su_sin.sin_port;
1857			alen = sizeof(su->su_sin.sin_addr);
1858			af = 4;
1859			break;
1860		case AF_INET6:
1861			a = (u_char *)&su->su_sin6.sin6_addr;
1862			p = (u_char *)&su->su_sin6.sin6_port;
1863			alen = sizeof(su->su_sin6.sin6_addr);
1864			af = 6;
1865			break;
1866		default:
1867			af = 0;
1868			break;
1869		}
1870		if (af) {
1871			if (ispassive)
1872				printf("211- LPSV ");
1873			else
1874				printf("211- LPRT ");
1875			printf("(%u,%llu", af, (unsigned long long)alen);
1876			for (i = 0; i < alen; i++)
1877				printf(",%u", a[i]);
1878			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1879		}
1880
1881		/* EPRT/EPSV */
1882		switch (su->su_family) {
1883		case AF_INET:
1884			af = 1;
1885			break;
1886		case AF_INET6:
1887			af = 2;
1888			break;
1889		default:
1890			af = 0;
1891			break;
1892		}
1893		if (af) {
1894			char pbuf[10];
1895			union sockunion tmp = *su;
1896
1897			if (tmp.su_family == AF_INET6)
1898				tmp.su_sin6.sin6_scope_id = 0;
1899			if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1900			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1901			    NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1902				if (ispassive)
1903					printf("211- EPSV ");
1904				else
1905					printf("211- EPRT ");
1906				printf("(|%u|%s|%s|)\r\n",
1907				    af, hbuf, pbuf);
1908			}
1909		}
1910	} else
1911		printf("     No data connection\r\n");
1912	reply(211, "End of status");
1913}
1914
1915void
1916fatal(char *s)
1917{
1918
1919	reply(451, "Error in server: %s", s);
1920	reply(221, "Closing connection due to server error.");
1921	dologout(0);
1922	/* NOTREACHED */
1923}
1924
1925void
1926reply(int n, const char *fmt, ...)
1927{
1928	char *buf, *p, *next;
1929	int rval;
1930	va_list ap;
1931
1932	va_start(ap, fmt);
1933	rval = vasprintf(&buf, fmt, ap);
1934	va_end(ap);
1935	if (rval == -1 || buf == NULL) {
1936		printf("412 Local resource failure: malloc\r\n");
1937		fflush(stdout);
1938		dologout(1);
1939	}
1940	next = buf;
1941	while ((p = strsep(&next, "\n\r"))) {
1942		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1943		if (debug)
1944			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1945			    (next != '\0') ? "-" : "", p);
1946	}
1947	(void)fflush(stdout);
1948	free(buf);
1949}
1950
1951
1952void
1953reply_r(int n, const char *fmt, ...)
1954{
1955	char *p, *next;
1956	char msg[BUFSIZ];
1957	char buf[BUFSIZ];
1958	va_list ap;
1959	struct syslog_data sdata = SYSLOG_DATA_INIT;
1960
1961	va_start(ap, fmt);
1962	vsnprintf(msg, sizeof(msg), fmt, ap);
1963	va_end(ap);
1964
1965	next = msg;
1966
1967	while ((p = strsep(&next, "\n\r"))) {
1968		snprintf(buf, sizeof(buf), "%d%s %s\r\n", n,
1969		    (next != '\0') ? "-" : "", p);
1970		write(STDOUT_FILENO, buf, strlen(buf));
1971		if (debug) {
1972			buf[strlen(buf) - 2] = '\0';
1973			syslog_r(LOG_DEBUG, &sdata, "<--- %s", buf);
1974		}
1975	}
1976}
1977
1978void
1979lreply(int n, const char *fmt, ...)
1980{
1981	va_list ap;
1982
1983	va_start(ap, fmt);
1984	(void)printf("%d- ", n);
1985	(void)vprintf(fmt, ap);
1986	va_end(ap);
1987	(void)printf("\r\n");
1988	(void)fflush(stdout);
1989	if (debug) {
1990		va_start(ap, fmt);
1991		syslog(LOG_DEBUG, "<--- %d- ", n);
1992		vsyslog(LOG_DEBUG, fmt, ap);
1993		va_end(ap);
1994	}
1995}
1996
1997static void
1998ack(char *s)
1999{
2000
2001	reply(250, "%s command successful.", s);
2002}
2003
2004void
2005nack(char *s)
2006{
2007
2008	reply(502, "%s command not implemented.", s);
2009}
2010
2011/* ARGSUSED */
2012void
2013yyerror(char *s)
2014{
2015	char *cp;
2016
2017	if ((cp = strchr(cbuf,'\n')))
2018		*cp = '\0';
2019	reply(500, "'%s': command not understood.", cbuf);
2020}
2021
2022void
2023delete(char *name)
2024{
2025	struct stat st;
2026
2027	LOGCMD("delete", name);
2028	if (stat(name, &st) < 0) {
2029		perror_reply(550, name);
2030		return;
2031	}
2032	if ((st.st_mode&S_IFMT) == S_IFDIR) {
2033		if (rmdir(name) < 0) {
2034			perror_reply(550, name);
2035			return;
2036		}
2037		goto done;
2038	}
2039	if (unlink(name) < 0) {
2040		perror_reply(550, name);
2041		return;
2042	}
2043done:
2044	ack("DELE");
2045}
2046
2047void
2048cwd(char *path)
2049{
2050	FILE *message;
2051
2052	if (chdir(path) < 0)
2053		perror_reply(550, path);
2054	else {
2055		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2056			char *cp, line[LINE_MAX];
2057
2058			while (fgets(line, sizeof(line), message) != NULL) {
2059				if ((cp = strchr(line, '\n')) != NULL)
2060					*cp = '\0';
2061				lreply(250, "%s", line);
2062			}
2063			(void) fflush(stdout);
2064			(void) fclose(message);
2065		}
2066		ack("CWD");
2067	}
2068}
2069
2070void
2071replydirname(const char *name, const char *message)
2072{
2073	char *p, *ep;
2074	char npath[MAXPATHLEN * 2];
2075
2076	p = npath;
2077	ep = &npath[sizeof(npath) - 1];
2078	while (*name) {
2079		if (*name == '"') {
2080			if (ep - p < 2)
2081				break;
2082			*p++ = *name++;
2083			*p++ = '"';
2084		} else {
2085			if (ep - p < 1)
2086				break;
2087			*p++ = *name++;
2088		}
2089	}
2090	*p = '\0';
2091	reply(257, "\"%s\" %s", npath, message);
2092}
2093
2094void
2095makedir(char *name)
2096{
2097
2098	LOGCMD("mkdir", name);
2099	if (mkdir(name, 0777) < 0)
2100		perror_reply(550, name);
2101	else
2102		replydirname(name, "directory created.");
2103}
2104
2105void
2106removedir(char *name)
2107{
2108
2109	LOGCMD("rmdir", name);
2110	if (rmdir(name) < 0)
2111		perror_reply(550, name);
2112	else
2113		ack("RMD");
2114}
2115
2116void
2117pwd(void)
2118{
2119	char path[MAXPATHLEN];
2120
2121	if (getcwd(path, sizeof(path)) == NULL)
2122		perror_reply(550, "Can't get current directory");
2123	else
2124		replydirname(path, "is current directory.");
2125}
2126
2127char *
2128renamefrom(char *name)
2129{
2130	struct stat st;
2131
2132	if (stat(name, &st) < 0) {
2133		perror_reply(550, name);
2134		return ((char *)0);
2135	}
2136	reply(350, "File exists, ready for destination name");
2137	return (name);
2138}
2139
2140void
2141renamecmd(char *from, char *to)
2142{
2143
2144	LOGCMD2("rename", from, to);
2145	if (rename(from, to) < 0)
2146		perror_reply(550, "rename");
2147	else
2148		ack("RNTO");
2149}
2150
2151static void
2152dolog(struct sockaddr *sa)
2153{
2154	char hbuf[sizeof(remotehost)];
2155
2156	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0) == 0)
2157		(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2158	else
2159		(void) strlcpy(remotehost, "unknown", sizeof(remotehost));
2160
2161#ifdef HASSETPROCTITLE
2162	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2163	setproctitle("%s", proctitle);
2164#endif /* HASSETPROCTITLE */
2165
2166	if (logging)
2167		syslog(LOG_INFO, "connection from %s", remotehost);
2168}
2169
2170/*
2171 * Record logout in wtmp file and exit with supplied status.
2172 * NOTE: because this is called from signal handlers it cannot
2173 *       use stdio (or call other functions that use stdio).
2174 */
2175void
2176dologout(int status)
2177{
2178
2179	transflag = 0;
2180
2181	if (logged_in) {
2182		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2183		ftpdlogwtmp(ttyline, "", "");
2184		if (doutmp)
2185			ftpd_logout(utmp.ut_line);
2186	}
2187	/* beware of flushing buffers after a SIGPIPE */
2188	_exit(status);
2189}
2190
2191/*ARGSUSED*/
2192static void
2193sigurg(int signo)
2194{
2195
2196	recvurg = 1;
2197}
2198
2199static void
2200myoob(void)
2201{
2202	char *cp;
2203
2204	/* only process if transfer occurring */
2205	if (!transflag)
2206		return;
2207	cp = tmpline;
2208	if (getline(cp, 7, stdin) == NULL) {
2209		reply(221, "You could at least say goodbye.");
2210		dologout(0);
2211	}
2212	upper(cp);
2213	if (strcmp(cp, "ABOR\r\n") == 0) {
2214		tmpline[0] = '\0';
2215		reply(426, "Transfer aborted. Data connection closed.");
2216		reply(226, "Abort successful");
2217	}
2218	if (strcmp(cp, "STAT\r\n") == 0) {
2219		tmpline[0] = '\0';
2220		if (file_size != (off_t) -1)
2221			reply(213, "Status: %qd of %qd bytes transferred",
2222			    byte_count, file_size);
2223		else
2224			reply(213, "Status: %qd bytes transferred", byte_count);
2225	}
2226}
2227
2228/*
2229 * Note: a response of 425 is not mentioned as a possible response to
2230 *	the PASV command in RFC959. However, it has been blessed as
2231 *	a legitimate response by Jon Postel in a telephone conversation
2232 *	with Rick Adams on 25 Jan 89.
2233 */
2234void
2235passive(void)
2236{
2237	socklen_t len;
2238	int on;
2239	u_char *p, *a;
2240
2241	if (pw == NULL) {
2242		reply(530, "Please login with USER and PASS");
2243		return;
2244	}
2245	if (pdata >= 0)
2246		close(pdata);
2247	/*
2248	 * XXX
2249	 * At this point, it would be nice to have an algorithm that
2250	 * inserted a growing delay in an attack scenario.  Such a thing
2251	 * would look like continual passive sockets being opened, but
2252	 * nothing serious being done with them.  They're not used to
2253	 * move data; the entire attempt is just to use tcp FIN_WAIT
2254	 * resources.
2255	 */
2256	pdata = socket(AF_INET, SOCK_STREAM, 0);
2257	if (pdata < 0) {
2258		perror_reply(425, "Can't open passive connection");
2259		return;
2260	}
2261
2262	on = IP_PORTRANGE_HIGH;
2263	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2264	    &on, sizeof(on)) < 0)
2265		goto pasv_error;
2266
2267	pasv_addr = ctrl_addr;
2268	pasv_addr.su_sin.sin_port = 0;
2269	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2270	    pasv_addr.su_len) < 0)
2271		goto pasv_error;
2272
2273	len = sizeof(pasv_addr);
2274	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2275		goto pasv_error;
2276	if (listen(pdata, 1) < 0)
2277		goto pasv_error;
2278	a = (u_char *)&pasv_addr.su_sin.sin_addr;
2279	p = (u_char *)&pasv_addr.su_sin.sin_port;
2280
2281	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2282	    a[1], a[2], a[3], p[0], p[1]);
2283	return;
2284
2285pasv_error:
2286	(void) close(pdata);
2287	pdata = -1;
2288	perror_reply(425, "Can't open passive connection");
2289	return;
2290}
2291
2292int
2293epsvproto2af(int proto)
2294{
2295
2296	switch (proto) {
2297	case 1:	return AF_INET;
2298#ifdef INET6
2299	case 2:	return AF_INET6;
2300#endif
2301	default: return -1;
2302	}
2303}
2304
2305int
2306af2epsvproto(int af)
2307{
2308
2309	switch (af) {
2310	case AF_INET:	return 1;
2311#ifdef INET6
2312	case AF_INET6:	return 2;
2313#endif
2314	default:	return -1;
2315	}
2316}
2317
2318/*
2319 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2320 * 229 Entering Extended Passive Mode (|||port|)
2321 */
2322void
2323long_passive(char *cmd, int pf)
2324{
2325	socklen_t len;
2326	int on;
2327	u_char *p, *a;
2328
2329	if (!logged_in) {
2330		syslog(LOG_NOTICE, "long passive but not logged in");
2331		reply(503, "Login with USER first.");
2332		return;
2333	}
2334
2335	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2336		/*
2337		 * XXX
2338		 * only EPRT/EPSV ready clients will understand this
2339		 */
2340		if (strcmp(cmd, "EPSV") != 0)
2341			reply(501, "Network protocol mismatch"); /*XXX*/
2342		else
2343			epsv_protounsupp("Network protocol mismatch");
2344
2345		return;
2346	}
2347
2348	if (pdata >= 0)
2349		close(pdata);
2350	/*
2351	 * XXX
2352	 * At this point, it would be nice to have an algorithm that
2353	 * inserted a growing delay in an attack scenario.  Such a thing
2354	 * would look like continual passive sockets being opened, but
2355	 * nothing serious being done with them.  They not used to move
2356	 * data; the entire attempt is just to use tcp FIN_WAIT
2357	 * resources.
2358	 */
2359	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2360	if (pdata < 0) {
2361		perror_reply(425, "Can't open passive connection");
2362		return;
2363	}
2364
2365	switch (ctrl_addr.su_family) {
2366	case AF_INET:
2367		on = IP_PORTRANGE_HIGH;
2368		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2369		    &on, sizeof(on)) < 0)
2370			goto pasv_error;
2371		break;
2372	case AF_INET6:
2373		on = IPV6_PORTRANGE_HIGH;
2374		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2375		    &on, sizeof(on)) < 0)
2376			goto pasv_error;
2377		break;
2378	}
2379
2380	pasv_addr = ctrl_addr;
2381	pasv_addr.su_port = 0;
2382	if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
2383		goto pasv_error;
2384	len = pasv_addr.su_len;
2385	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2386		goto pasv_error;
2387	if (listen(pdata, 1) < 0)
2388		goto pasv_error;
2389	p = (u_char *)&pasv_addr.su_port;
2390
2391	if (strcmp(cmd, "LPSV") == 0) {
2392		switch (pasv_addr.su_family) {
2393		case AF_INET:
2394			a = (u_char *)&pasv_addr.su_sin.sin_addr;
2395			reply(228,
2396			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2397			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2398			return;
2399		case AF_INET6:
2400			a = (u_char *)&pasv_addr.su_sin6.sin6_addr;
2401			reply(228,
2402			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2403			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2404				6, 16, a[0], a[1], a[2], a[3], a[4],
2405				a[5], a[6], a[7], a[8], a[9], a[10],
2406				a[11], a[12], a[13], a[14], a[15],
2407				2, p[0], p[1]);
2408			return;
2409		}
2410	} else if (strcmp(cmd, "EPSV") == 0) {
2411		switch (pasv_addr.su_family) {
2412		case AF_INET:
2413		case AF_INET6:
2414			reply(229, "Entering Extended Passive Mode (|||%u|)",
2415			    ntohs(pasv_addr.su_port));
2416			return;
2417		}
2418	} else {
2419		/* more proper error code? */
2420	}
2421
2422  pasv_error:
2423	(void) close(pdata);
2424	pdata = -1;
2425	perror_reply(425, "Can't open passive connection");
2426	return;
2427}
2428
2429/*
2430 * EPRT |proto|addr|port|
2431 */
2432int
2433extended_port(const char *arg)
2434{
2435	char *tmp = NULL;
2436	char *result[3];
2437	char *p, *q;
2438	char delim;
2439	struct addrinfo hints;
2440	struct addrinfo *res = NULL;
2441	int i;
2442	unsigned long proto;
2443
2444	if (epsvall) {
2445		reply(501, "EPRT disallowed after EPSV ALL");
2446		return -1;
2447	}
2448
2449	usedefault = 0;
2450	if (pdata >= 0) {
2451		(void) close(pdata);
2452		pdata = -1;
2453	}
2454
2455	tmp = strdup(arg);
2456	if (!tmp) {
2457		fatal("not enough core.");
2458		/*NOTREACHED*/
2459	}
2460	p = tmp;
2461	delim = p[0];
2462	p++;
2463	memset(result, 0, sizeof(result));
2464	for (i = 0; i < 3; i++) {
2465		q = strchr(p, delim);
2466		if (!q || *q != delim)
2467			goto parsefail;
2468		*q++ = '\0';
2469		result[i] = p;
2470		p = q;
2471	}
2472
2473	/* some more sanity check */
2474	p = NULL;
2475	(void)strtoul(result[2], &p, 10);
2476	if (!*result[2] || *p)
2477		goto protounsupp;
2478	p = NULL;
2479	proto = strtoul(result[0], &p, 10);
2480	if (!*result[0] || *p)
2481		goto protounsupp;
2482
2483	memset(&hints, 0, sizeof(hints));
2484	hints.ai_family = epsvproto2af((int)proto);
2485	if (hints.ai_family < 0)
2486		goto protounsupp;
2487	hints.ai_socktype = SOCK_STREAM;
2488	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2489	if (getaddrinfo(result[1], result[2], &hints, &res))
2490		goto parsefail;
2491	if (res->ai_next)
2492		goto parsefail;
2493	if (sizeof(data_dest) < res->ai_addrlen)
2494		goto parsefail;
2495	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2496	if (his_addr.su_family == AF_INET6 &&
2497	    data_dest.su_family == AF_INET6) {
2498		/* XXX more sanity checks! */
2499		data_dest.su_sin6.sin6_scope_id =
2500		    his_addr.su_sin6.sin6_scope_id;
2501	}
2502	if (pdata >= 0) {
2503		(void) close(pdata);
2504		pdata = -1;
2505	}
2506	reply(200, "EPRT command successful.");
2507
2508	if (tmp)
2509		free(tmp);
2510	if (res)
2511		freeaddrinfo(res);
2512	return 0;
2513
2514parsefail:
2515	reply(500, "Invalid argument, rejected.");
2516	usedefault = 1;
2517	if (tmp)
2518		free(tmp);
2519	if (res)
2520		freeaddrinfo(res);
2521	return -1;
2522
2523protounsupp:
2524	epsv_protounsupp("Protocol not supported");
2525	usedefault = 1;
2526	if (tmp)
2527		free(tmp);
2528	if (res)
2529		freeaddrinfo(res);
2530	return -1;
2531}
2532
2533/*
2534 * 522 Protocol not supported (proto,...)
2535 * as we assume address family for control and data connections are the same,
2536 * we do not return the list of address families we support - instead, we
2537 * return the address family of the control connection.
2538 */
2539void
2540epsv_protounsupp(const char *message)
2541{
2542	int proto;
2543
2544	proto = af2epsvproto(ctrl_addr.su_family);
2545	if (proto < 0)
2546		reply(501, "%s", message);	/*XXX*/
2547	else
2548		reply(522, "%s, use (%d)", message, proto);
2549}
2550
2551/*
2552 * Generate unique name for file with basename "local".
2553 * The file named "local" is already known to exist.
2554 * Generates failure reply on error.
2555 */
2556static int
2557guniquefd(char *local, char **nam)
2558{
2559	static char new[MAXPATHLEN];
2560	struct stat st;
2561	int count, len, fd;
2562	char *cp;
2563
2564	cp = strrchr(local, '/');
2565	if (cp)
2566		*cp = '\0';
2567	if (stat(cp ? local : ".", &st) < 0) {
2568		perror_reply(553, cp ? local : ".");
2569		return (-1);
2570	}
2571	if (cp)
2572		*cp = '/';
2573	len = strlcpy(new, local, sizeof(new));
2574	if (len+2+1 >= sizeof(new)-1)
2575		return (-1);
2576	cp = new + len;
2577	*cp++ = '.';
2578	for (count = 1; count < 100; count++) {
2579		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2580		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2581		if (fd == -1)
2582			continue;
2583		if (nam)
2584			*nam = new;
2585		return (fd);
2586	}
2587	reply(452, "Unique file name cannot be created.");
2588	return (-1);
2589}
2590
2591/*
2592 * Format and send reply containing system error number.
2593 */
2594void
2595perror_reply(int code, char *string)
2596{
2597
2598	reply(code, "%s: %s.", string, strerror(errno));
2599}
2600
2601static char *onefile[] = {
2602	"",
2603	0
2604};
2605
2606void
2607send_file_list(char *whichf)
2608{
2609	struct stat st;
2610	DIR *dirp = NULL;
2611	struct dirent *dir;
2612	FILE *dout = NULL;
2613	char **dirlist;
2614	char *dirname;
2615	int simple = 0;
2616	volatile int freeglob = 0;
2617	glob_t gl;
2618
2619	if (strpbrk(whichf, "~{[*?") != NULL) {
2620		memset(&gl, 0, sizeof(gl));
2621		freeglob = 1;
2622		if (glob(whichf,
2623		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2624		    0, &gl)) {
2625			reply(550, "not found");
2626			goto out;
2627		} else if (gl.gl_pathc == 0) {
2628			errno = ENOENT;
2629			perror_reply(550, whichf);
2630			goto out;
2631		}
2632		dirlist = gl.gl_pathv;
2633	} else {
2634		onefile[0] = whichf;
2635		dirlist = onefile;
2636		simple = 1;
2637	}
2638
2639	while ((dirname = *dirlist++)) {
2640		if (stat(dirname, &st) < 0) {
2641			/*
2642			 * If user typed "ls -l", etc, and the client
2643			 * used NLST, do what the user meant.
2644			 */
2645			if (dirname[0] == '-' && *dirlist == NULL &&
2646			    transflag == 0) {
2647				retrieve("/bin/ls %s", dirname);
2648				goto out;
2649			}
2650			perror_reply(550, whichf);
2651			if (dout != NULL) {
2652				(void) fclose(dout);
2653				transflag = 0;
2654				data = -1;
2655				pdata = -1;
2656			}
2657			goto out;
2658		}
2659
2660		if (S_ISREG(st.st_mode)) {
2661			if (dout == NULL) {
2662				dout = dataconn("file list", (off_t)-1, "w");
2663				if (dout == NULL)
2664					goto out;
2665				transflag++;
2666			}
2667			fprintf(dout, "%s%s\n", dirname,
2668				type == TYPE_A ? "\r" : "");
2669			byte_count += strlen(dirname) + 1;
2670			continue;
2671		} else if (!S_ISDIR(st.st_mode))
2672			continue;
2673
2674		if ((dirp = opendir(dirname)) == NULL)
2675			continue;
2676
2677		while ((dir = readdir(dirp)) != NULL) {
2678			char nbuf[MAXPATHLEN];
2679
2680			if (recvurg) {
2681				myoob();
2682				recvurg = 0;
2683				transflag = 0;
2684				goto out;
2685			}
2686
2687			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2688				continue;
2689			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2690			    dir->d_namlen == 2)
2691				continue;
2692
2693			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2694				 dir->d_name);
2695
2696			/*
2697			 * We have to do a stat to insure it's
2698			 * not a directory or special file.
2699			 */
2700			if (simple || (stat(nbuf, &st) == 0 &&
2701			    S_ISREG(st.st_mode))) {
2702				if (dout == NULL) {
2703					dout = dataconn("file list", (off_t)-1,
2704						"w");
2705					if (dout == NULL)
2706						goto out;
2707					transflag++;
2708				}
2709				if (nbuf[0] == '.' && nbuf[1] == '/')
2710					fprintf(dout, "%s%s\n", &nbuf[2],
2711						type == TYPE_A ? "\r" : "");
2712				else
2713					fprintf(dout, "%s%s\n", nbuf,
2714						type == TYPE_A ? "\r" : "");
2715				byte_count += strlen(nbuf) + 1;
2716			}
2717		}
2718		(void) closedir(dirp);
2719	}
2720
2721	if (dout == NULL)
2722		reply(550, "No files found.");
2723	else if (ferror(dout) != 0)
2724		perror_reply(550, "Data connection");
2725	else
2726		reply(226, "Transfer complete.");
2727
2728	transflag = 0;
2729	if (dout != NULL)
2730		(void) fclose(dout);
2731	else {
2732		if (pdata >= 0)
2733			close(pdata);
2734	}
2735	data = -1;
2736	pdata = -1;
2737out:
2738	if (freeglob) {
2739		freeglob = 0;
2740		globfree(&gl);
2741	}
2742}
2743
2744/*ARGSUSED*/
2745static void
2746reapchild(int signo)
2747{
2748	int save_errno = errno;
2749	int rval;
2750
2751	do {
2752		rval = waitpid(-1, NULL, WNOHANG);
2753	} while (rval > 0 || (rval == -1 && errno == EINTR));
2754	errno = save_errno;
2755}
2756
2757void
2758logxfer(char *name, off_t size, time_t start)
2759{
2760	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2761	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2762	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2763	char *vpw;
2764	time_t now;
2765	int len;
2766
2767	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2768		time(&now);
2769
2770		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2771		if (vpw == NULL)
2772			return;
2773
2774		snprintf(path, sizeof(path), "%s/%s", dir, name);
2775		if (realpath(path, rpath) == NULL)
2776			strlcpy(rpath, path, sizeof(rpath));
2777		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2778
2779		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2780		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2781
2782		len = snprintf(buf, sizeof(buf),
2783		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2784		    ctime(&now), now - start + (now == start),
2785		    vremotehost, (long long)size, vpath,
2786		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2787		    'o', ((guest) ? 'a' : 'r'),
2788		    vpw, 0 /* none yet */,
2789		    ((guest) ? "*" : pw->pw_name), dhostname);
2790
2791		if (len >= sizeof(buf) || len == -1) {
2792			if ((len = strlen(buf)) == 0)
2793				return;		/* should not happen */
2794			buf[len - 1] = '\n';
2795		}
2796		write(statfd, buf, len);
2797		free(vpw);
2798	}
2799}
2800
2801void
2802set_slave_signals(void)
2803{
2804	struct sigaction sa;
2805
2806	sigemptyset(&sa.sa_mask);
2807	sa.sa_flags = SA_RESTART;
2808
2809	sa.sa_handler = SIG_DFL;
2810	(void) sigaction(SIGCHLD, &sa, NULL);
2811
2812	sa.sa_handler = sigurg;
2813	sa.sa_flags = 0;		/* don't restart syscalls for SIGURG */
2814	(void) sigaction(SIGURG, &sa, NULL);
2815
2816	sigfillset(&sa.sa_mask);	/* block all signals in handler */
2817	sa.sa_flags = SA_RESTART;
2818	sa.sa_handler = sigquit;
2819	(void) sigaction(SIGHUP, &sa, NULL);
2820	(void) sigaction(SIGINT, &sa, NULL);
2821	(void) sigaction(SIGQUIT, &sa, NULL);
2822	(void) sigaction(SIGTERM, &sa, NULL);
2823
2824	sa.sa_handler = lostconn;
2825	(void) sigaction(SIGPIPE, &sa, NULL);
2826
2827	sa.sa_handler = toolong;
2828	(void) sigaction(SIGALRM, &sa, NULL);
2829
2830#ifdef F_SETOWN
2831	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2832		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
2833#endif
2834}
2835
2836#if defined(TCPWRAPPERS)
2837static int
2838check_host(struct sockaddr *sa)
2839{
2840	struct sockaddr_in *sin;
2841	struct hostent *hp;
2842	char *addr;
2843
2844	if (sa->sa_family != AF_INET)
2845		return 1;	/*XXX*/
2846
2847	sin = (struct sockaddr_in *)sa;
2848	hp = gethostbyaddr((char *)&sin->sin_addr,
2849	    sizeof(struct in_addr), AF_INET);
2850	addr = inet_ntoa(sin->sin_addr);
2851	if (hp) {
2852		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2853			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2854			    hp->h_name, addr);
2855			return (0);
2856		}
2857	} else {
2858		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2859			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2860			return (0);
2861		}
2862	}
2863	return (1);
2864}
2865#endif	/* TCPWRAPPERS */
2866
2867/*
2868 * Allocate space and return a copy of the specified dir.
2869 * If 'dir' begins with a tilde (~), expand it.
2870 */
2871char *
2872copy_dir(char *dir, struct passwd *pw)
2873{
2874	char *cp;
2875	char *newdir;
2876	char *user = NULL;
2877	size_t dirsiz;
2878
2879	/* Nothing to expand */
2880	if (dir[0] != '~')
2881		return (strdup(dir));
2882
2883	/* "dir" is of form ~user/some/dir, lookup user. */
2884	if (dir[1] != '/' && dir[1] != '\0') {
2885		if ((cp = strchr(dir + 1, '/')) == NULL)
2886		    cp = dir + strlen(dir);
2887		if ((user = malloc((size_t)(cp - dir))) == NULL)
2888			return (NULL);
2889		strlcpy(user, dir + 1, (size_t)(cp - dir));
2890
2891		/* Only do lookup if it is a different user. */
2892		if (strcmp(user, pw->pw_name) != 0) {
2893			if ((pw = getpwnam(user)) == NULL) {
2894				/* No such user, interpret literally */
2895				free(user);
2896				return(strdup(dir));
2897			}
2898		}
2899	}
2900
2901	/*
2902	 * If there is no directory separator (/) then it is just pw_dir.
2903	 * Otherwise, replace ~foo with  pw_dir.
2904	 */
2905	if ((cp = strchr(dir + 1, '/')) == NULL) {
2906		newdir = strdup(pw->pw_dir);
2907	} else {
2908		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2909		if ((newdir = malloc(dirsiz)) == NULL) {
2910			free(user);
2911			return (NULL);
2912		}
2913		strlcpy(newdir, pw->pw_dir, dirsiz);
2914		strlcat(newdir, cp, dirsiz);
2915	}
2916
2917	if (user)
2918		free(user);
2919	return(newdir);
2920}
2921