ftpd.c revision 1.173
1/*	$OpenBSD: ftpd.c,v 1.173 2006/10/18 21:46:09 millert Exp $	*/
2/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. 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.173 2006/10/18 21:46:09 millert 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) close(fd);
569		reply(530,
570			"Connection from IPv4 mapped address is not supported.");
571		exit(0);
572#endif
573	}
574#ifdef IP_TOS
575	if (his_addr.su_family == AF_INET) {
576		tos = IPTOS_LOWDELAY;
577		if (setsockopt(0, IPPROTO_IP, IP_TOS, &tos,
578		    sizeof(int)) < 0)
579			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
580	}
581#endif
582	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
583
584	/* Try to handle urgent data inline */
585#ifdef SO_OOBINLINE
586	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) < 0)
587		syslog(LOG_ERR, "setsockopt: %m");
588#endif
589
590	dolog((struct sockaddr *)&his_addr);
591
592	/*
593	 * Set up default state
594	 */
595	data = -1;
596	type = TYPE_A;
597	form = FORM_N;
598	stru = STRU_F;
599	mode = MODE_S;
600	tmpline[0] = '\0';
601
602	/* If logins are disabled, print out the message. */
603	if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
604		while (fgets(line, sizeof(line), fp) != NULL) {
605			if ((cp = strchr(line, '\n')) != NULL)
606				*cp = '\0';
607			lreply(530, "%s", line);
608		}
609		(void) fflush(stdout);
610		(void) fclose(fp);
611		reply(530, "System not available.");
612		exit(0);
613	}
614	if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
615		while (fgets(line, sizeof(line), fp) != NULL) {
616			if ((cp = strchr(line, '\n')) != NULL)
617				*cp = '\0';
618			lreply(220, "%s", line);
619		}
620		(void) fflush(stdout);
621		(void) fclose(fp);
622		/* reply(220,) must follow */
623	}
624	(void) gethostname(hostname, sizeof(hostname));
625
626	/* Make sure hostname is fully qualified. */
627	hp = gethostbyname(hostname);
628	if (hp != NULL)
629		strlcpy(hostname, hp->h_name, sizeof(hostname));
630
631	if (multihome) {
632		error = getnameinfo((struct sockaddr *)&ctrl_addr,
633		    ctrl_addr.su_len, dhostname, sizeof(dhostname), NULL, 0, 0);
634	}
635
636	if (error != 0)
637		reply(220, "FTP server (%s) ready.", version);
638	else
639		reply(220, "%s FTP server (%s) ready.",
640		    (multihome ? dhostname : hostname), version);
641
642	monitor_init();
643
644	for (;;)
645		(void) yyparse();
646	/* NOTREACHED */
647}
648
649/*
650 * Signal handlers.
651 */
652/*ARGSUSED*/
653static void
654lostconn(int signo)
655{
656	struct syslog_data sdata = SYSLOG_DATA_INIT;
657
658	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 = 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			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		if (file != NULL)
1458			(void) fclose(file);
1459		file = getdatasock(mode);
1460		if (file == NULL) {
1461			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1462
1463			error = getnameinfo((struct sockaddr *)&data_source,
1464			    data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1465			    sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1466			if (error != 0)
1467				reply(425, "Can't create data socket: %s.",
1468				    strerror(errno));
1469			else
1470				reply(425,
1471				    "Can't create data socket (%s,%s): %s.",
1472				    hbuf, pbuf, strerror(errno));
1473			return (NULL);
1474		}
1475
1476		/*
1477		 * attempt to connect to reserved port on client machine;
1478		 * this looks like an attack
1479		 */
1480		switch (data_dest.su_family) {
1481		case AF_INET:
1482			p = (in_port_t *)&data_dest.su_sin.sin_port;
1483			fa = (u_char *)&data_dest.su_sin.sin_addr;
1484			ha = (u_char *)&his_addr.su_sin.sin_addr;
1485			alen = sizeof(struct in_addr);
1486			break;
1487		case AF_INET6:
1488			p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1489			fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1490			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1491			alen = sizeof(struct in6_addr);
1492			break;
1493		default:
1494			perror_reply(425, "Can't build data connection");
1495			(void) fclose(file);
1496			pdata = -1;
1497			return (NULL);
1498		}
1499		if (data_dest.su_family != his_addr.su_family ||
1500		    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
1501			perror_reply(425, "Can't build data connection");
1502			(void) fclose(file);
1503			return NULL;
1504		}
1505		if (portcheck && memcmp(fa, ha, alen) != 0) {
1506			perror_reply(435, "Can't build data connection");
1507			(void) fclose(file);
1508			return NULL;
1509		}
1510
1511		if (connect(fileno(file), (struct sockaddr *)&data_dest,
1512		    data_dest.su_len) == 0) {
1513			reply(150, "Opening %s mode data connection for '%s'%s.",
1514			    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1515			data = fileno(file);
1516			return (file);
1517		}
1518		if (errno != EADDRINUSE)
1519			break;
1520		sleep((unsigned) swaitint);
1521		retry += swaitint;
1522	} while (retry <= swaitmax);
1523	perror_reply(425, "Can't build data connection");
1524	(void) fclose(file);
1525	return (NULL);
1526}
1527
1528/*
1529 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1530 * encapsulation of the data subject to Mode, Structure, and Type.
1531 *
1532 * NB: Form isn't handled.
1533 */
1534static int
1535send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1536{
1537	int c, cnt, filefd, netfd;
1538	char *buf, *bp;
1539	size_t len;
1540
1541	transflag++;
1542	switch (type) {
1543
1544	case TYPE_A:
1545		while ((c = getc(instr)) != EOF) {
1546			if (recvurg)
1547				goto got_oob;
1548			byte_count++;
1549			if (c == '\n') {
1550				if (ferror(outstr))
1551					goto data_err;
1552				(void) putc('\r', outstr);
1553			}
1554			(void) putc(c, outstr);
1555		}
1556		fflush(outstr);
1557		transflag = 0;
1558		if (ferror(instr))
1559			goto file_err;
1560		if (ferror(outstr))
1561			goto data_err;
1562		reply(226, "Transfer complete.");
1563		return(0);
1564
1565	case TYPE_I:
1566	case TYPE_L:
1567		/*
1568		 * isreg is only set if we are not doing restart and we
1569		 * are sending a regular file
1570		 */
1571		netfd = fileno(outstr);
1572		filefd = fileno(instr);
1573
1574		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1575			size_t fsize = (size_t)filesize;
1576
1577			buf = mmap(0, fsize, PROT_READ, MAP_SHARED, filefd,
1578			    (off_t)0);
1579			if (buf == MAP_FAILED) {
1580				syslog(LOG_WARNING, "mmap(%llu): %m",
1581				    (unsigned long long)fsize);
1582				goto oldway;
1583			}
1584			bp = buf;
1585			len = fsize;
1586			do {
1587				cnt = write(netfd, bp, len);
1588				if (recvurg) {
1589					munmap(buf, fsize);
1590					goto got_oob;
1591				}
1592				len -= cnt;
1593				bp += cnt;
1594				if (cnt > 0)
1595					byte_count += cnt;
1596			} while(cnt > 0 && len > 0);
1597
1598			transflag = 0;
1599			munmap(buf, fsize);
1600			if (cnt < 0)
1601				goto data_err;
1602			reply(226, "Transfer complete.");
1603			return(0);
1604		}
1605
1606oldway:
1607		if ((buf = malloc((size_t)blksize)) == NULL) {
1608			transflag = 0;
1609			perror_reply(451, "Local resource failure: malloc");
1610			return(-1);
1611		}
1612
1613		while ((cnt = read(filefd, buf, (size_t)blksize)) > 0 &&
1614		    write(netfd, buf, cnt) == cnt)
1615			byte_count += cnt;
1616		transflag = 0;
1617		(void)free(buf);
1618		if (cnt != 0) {
1619			if (cnt < 0)
1620				goto file_err;
1621			goto data_err;
1622		}
1623		reply(226, "Transfer complete.");
1624		return(0);
1625	default:
1626		transflag = 0;
1627		reply(550, "Unimplemented TYPE %d in send_data", type);
1628		return(-1);
1629	}
1630
1631data_err:
1632	transflag = 0;
1633	perror_reply(426, "Data connection");
1634	return(-1);
1635
1636file_err:
1637	transflag = 0;
1638	perror_reply(551, "Error on input file");
1639	return(-1);
1640
1641got_oob:
1642	myoob();
1643	recvurg = 0;
1644	transflag = 0;
1645	return(-1);
1646}
1647
1648/*
1649 * Transfer data from peer to "outstr" using the appropriate encapulation of
1650 * the data subject to Mode, Structure, and Type.
1651 *
1652 * N.B.: Form isn't handled.
1653 */
1654static int
1655receive_data(FILE *instr, FILE *outstr)
1656{
1657	int c;
1658	int cnt;
1659	char buf[BUFSIZ];
1660	struct sigaction sa, sa_saved;
1661	volatile int bare_lfs = 0;
1662
1663	transflag++;
1664	switch (type) {
1665
1666	case TYPE_I:
1667	case TYPE_L:
1668		memset(&sa, 0, sizeof(sa));
1669		sigfillset(&sa.sa_mask);
1670		sa.sa_flags = SA_RESTART;
1671		sa.sa_handler = lostconn;
1672		(void) sigaction(SIGALRM, &sa, &sa_saved);
1673		do {
1674			(void) alarm ((unsigned) timeout);
1675			cnt = read(fileno(instr), buf, sizeof(buf));
1676			(void) alarm (0);
1677			if (recvurg)
1678				goto got_oob;
1679
1680			if (cnt > 0) {
1681				if (write(fileno(outstr), buf, cnt) != cnt)
1682					goto file_err;
1683				byte_count += cnt;
1684			}
1685		} while (cnt > 0);
1686		(void) sigaction(SIGALRM, &sa_saved, NULL);
1687		if (cnt < 0)
1688			goto data_err;
1689		transflag = 0;
1690		return (0);
1691
1692	case TYPE_E:
1693		reply(553, "TYPE E not implemented.");
1694		transflag = 0;
1695		return (-1);
1696
1697	case TYPE_A:
1698		while ((c = getc(instr)) != EOF) {
1699			if (recvurg)
1700				goto got_oob;
1701			byte_count++;
1702			if (c == '\n')
1703				bare_lfs++;
1704			while (c == '\r') {
1705				if (ferror(outstr))
1706					goto data_err;
1707				if ((c = getc(instr)) != '\n') {
1708					(void) putc ('\r', outstr);
1709					if (c == '\0' || c == EOF)
1710						goto contin2;
1711				}
1712			}
1713			(void) putc(c, outstr);
1714	contin2:	;
1715		}
1716		fflush(outstr);
1717		if (ferror(instr))
1718			goto data_err;
1719		if (ferror(outstr))
1720			goto file_err;
1721		transflag = 0;
1722		if (bare_lfs) {
1723			lreply(226,
1724			    "WARNING! %d bare linefeeds received in ASCII mode",
1725			    bare_lfs);
1726			printf("   File may not have transferred correctly.\r\n");
1727		}
1728		return (0);
1729	default:
1730		reply(550, "Unimplemented TYPE %d in receive_data", type);
1731		transflag = 0;
1732		return (-1);
1733	}
1734
1735data_err:
1736	transflag = 0;
1737	perror_reply(426, "Data Connection");
1738	return (-1);
1739
1740file_err:
1741	transflag = 0;
1742	perror_reply(452, "Error writing file");
1743	return (-1);
1744
1745got_oob:
1746	myoob();
1747	recvurg = 0;
1748	transflag = 0;
1749	return (-1);
1750}
1751
1752void
1753statfilecmd(char *filename)
1754{
1755	FILE *fin;
1756	int c;
1757	int atstart;
1758	char line[LINE_MAX];
1759
1760	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1761	fin = ftpd_popen(line, "r");
1762	lreply(211, "status of %s:", filename);
1763	atstart = 1;
1764	while ((c = getc(fin)) != EOF) {
1765		if (c == '\n') {
1766			if (ferror(stdout)){
1767				perror_reply(421, "control connection");
1768				(void) ftpd_pclose(fin);
1769				dologout(1);
1770				/* NOTREACHED */
1771			}
1772			if (ferror(fin)) {
1773				perror_reply(551, filename);
1774				(void) ftpd_pclose(fin);
1775				return;
1776			}
1777			(void) putc('\r', stdout);
1778		}
1779		if (atstart && isdigit(c))
1780			(void) putc(' ', stdout);
1781		(void) putc(c, stdout);
1782		atstart = (c == '\n');
1783	}
1784	(void) ftpd_pclose(fin);
1785	reply(211, "End of Status");
1786}
1787
1788void
1789statcmd(void)
1790{
1791	union sockunion *su;
1792	u_char *a, *p;
1793	char hbuf[MAXHOSTNAMELEN];
1794	int ispassive;
1795	int error;
1796
1797	lreply(211, "%s FTP server status:", hostname);
1798	printf("     %s\r\n", version);
1799	error = getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1800	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1801	printf("     Connected to %s", remotehost);
1802	if (error == 0 && strcmp(remotehost, hbuf) != 0)
1803		printf(" (%s)", hbuf);
1804	printf("\r\n");
1805	if (logged_in) {
1806		if (guest)
1807			printf("     Logged in anonymously\r\n");
1808		else
1809			printf("     Logged in as %s\r\n", pw->pw_name);
1810	} else if (askpasswd)
1811		printf("     Waiting for password\r\n");
1812	else
1813		printf("     Waiting for user name\r\n");
1814	printf("     TYPE: %s", typenames[type]);
1815	if (type == TYPE_A || type == TYPE_E)
1816		printf(", FORM: %s", formnames[form]);
1817	if (type == TYPE_L)
1818#if NBBY == 8
1819		printf(" %d", NBBY);
1820#else
1821		printf(" %d", bytesize);	/* need definition! */
1822#endif
1823	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1824	    strunames[stru], modenames[mode]);
1825	ispassive = 0;
1826	if (data != -1)
1827		printf("     Data connection open\r\n");
1828	else if (pdata != -1) {
1829		printf("     in Passive mode\r\n");
1830		su = (union sockunion *)&pasv_addr;
1831		ispassive++;
1832		goto printaddr;
1833	} else if (usedefault == 0) {
1834		size_t alen;
1835		int af, i;
1836
1837		su = (union sockunion *)&data_dest;
1838printaddr:
1839		/* PASV/PORT */
1840		if (su->su_family == AF_INET) {
1841			if (ispassive)
1842				printf("211- PASV ");
1843			else
1844				printf("211- PORT ");
1845			a = (u_char *)&su->su_sin.sin_addr;
1846			p = (u_char *)&su->su_sin.sin_port;
1847			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1848			    a[0], a[1], a[2], a[3],
1849			    p[0], p[1]);
1850		}
1851
1852		/* LPSV/LPRT */
1853		alen = 0;
1854		switch (su->su_family) {
1855		case AF_INET:
1856			a = (u_char *)&su->su_sin.sin_addr;
1857			p = (u_char *)&su->su_sin.sin_port;
1858			alen = sizeof(su->su_sin.sin_addr);
1859			af = 4;
1860			break;
1861		case AF_INET6:
1862			a = (u_char *)&su->su_sin6.sin6_addr;
1863			p = (u_char *)&su->su_sin6.sin6_port;
1864			alen = sizeof(su->su_sin6.sin6_addr);
1865			af = 6;
1866			break;
1867		default:
1868			af = 0;
1869			break;
1870		}
1871		if (af) {
1872			if (ispassive)
1873				printf("211- LPSV ");
1874			else
1875				printf("211- LPRT ");
1876			printf("(%u,%llu", af, (unsigned long long)alen);
1877			for (i = 0; i < alen; i++)
1878				printf(",%u", a[i]);
1879			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1880		}
1881
1882		/* EPRT/EPSV */
1883		switch (su->su_family) {
1884		case AF_INET:
1885			af = 1;
1886			break;
1887		case AF_INET6:
1888			af = 2;
1889			break;
1890		default:
1891			af = 0;
1892			break;
1893		}
1894		if (af) {
1895			char pbuf[10];
1896			union sockunion tmp = *su;
1897
1898			if (tmp.su_family == AF_INET6)
1899				tmp.su_sin6.sin6_scope_id = 0;
1900			if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1901			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1902			    NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1903				if (ispassive)
1904					printf("211- EPSV ");
1905				else
1906					printf("211- EPRT ");
1907				printf("(|%u|%s|%s|)\r\n",
1908				    af, hbuf, pbuf);
1909			}
1910		}
1911	} else
1912		printf("     No data connection\r\n");
1913	reply(211, "End of status");
1914}
1915
1916void
1917fatal(char *s)
1918{
1919
1920	reply(451, "Error in server: %s", s);
1921	reply(221, "Closing connection due to server error.");
1922	dologout(0);
1923	/* NOTREACHED */
1924}
1925
1926void
1927reply(int n, const char *fmt, ...)
1928{
1929	char *buf, *p, *next;
1930	int rval;
1931	va_list ap;
1932
1933	va_start(ap, fmt);
1934	rval = vasprintf(&buf, fmt, ap);
1935	va_end(ap);
1936	if (rval == -1 || buf == NULL) {
1937		printf("412 Local resource failure: malloc\r\n");
1938		fflush(stdout);
1939		dologout(1);
1940	}
1941	next = buf;
1942	while ((p = strsep(&next, "\n\r"))) {
1943		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1944		if (debug)
1945			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1946			    (next != '\0') ? "-" : "", p);
1947	}
1948	(void)fflush(stdout);
1949	free(buf);
1950}
1951
1952
1953void
1954reply_r(int n, const char *fmt, ...)
1955{
1956	char *p, *next;
1957	char msg[BUFSIZ];
1958	char buf[BUFSIZ];
1959	va_list ap;
1960	struct syslog_data sdata = SYSLOG_DATA_INIT;
1961
1962	va_start(ap, fmt);
1963	vsnprintf(msg, sizeof(msg), fmt, ap);
1964	va_end(ap);
1965
1966	next = msg;
1967
1968	while ((p = strsep(&next, "\n\r"))) {
1969		snprintf(buf, sizeof(buf), "%d%s %s\r\n", n,
1970		    (next != '\0') ? "-" : "", p);
1971		write(STDOUT_FILENO, buf, strlen(buf));
1972		if (debug) {
1973			buf[strlen(buf) - 2] = '\0';
1974			syslog_r(LOG_DEBUG, &sdata, "<--- %s", buf);
1975		}
1976	}
1977}
1978
1979void
1980lreply(int n, const char *fmt, ...)
1981{
1982	va_list ap;
1983
1984	va_start(ap, fmt);
1985	(void)printf("%d- ", n);
1986	(void)vprintf(fmt, ap);
1987	va_end(ap);
1988	(void)printf("\r\n");
1989	(void)fflush(stdout);
1990	if (debug) {
1991		va_start(ap, fmt);
1992		syslog(LOG_DEBUG, "<--- %d- ", n);
1993		vsyslog(LOG_DEBUG, fmt, ap);
1994		va_end(ap);
1995	}
1996}
1997
1998static void
1999ack(char *s)
2000{
2001
2002	reply(250, "%s command successful.", s);
2003}
2004
2005void
2006nack(char *s)
2007{
2008
2009	reply(502, "%s command not implemented.", s);
2010}
2011
2012/* ARGSUSED */
2013void
2014yyerror(char *s)
2015{
2016	char *cp;
2017
2018	if ((cp = strchr(cbuf,'\n')))
2019		*cp = '\0';
2020	reply(500, "'%s': command not understood.", cbuf);
2021}
2022
2023void
2024delete(char *name)
2025{
2026	struct stat st;
2027
2028	LOGCMD("delete", name);
2029	if (stat(name, &st) < 0) {
2030		perror_reply(550, name);
2031		return;
2032	}
2033	if ((st.st_mode&S_IFMT) == S_IFDIR) {
2034		if (rmdir(name) < 0) {
2035			perror_reply(550, name);
2036			return;
2037		}
2038		goto done;
2039	}
2040	if (unlink(name) < 0) {
2041		perror_reply(550, name);
2042		return;
2043	}
2044done:
2045	ack("DELE");
2046}
2047
2048void
2049cwd(char *path)
2050{
2051	FILE *message;
2052
2053	if (chdir(path) < 0)
2054		perror_reply(550, path);
2055	else {
2056		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2057			char *cp, line[LINE_MAX];
2058
2059			while (fgets(line, sizeof(line), message) != NULL) {
2060				if ((cp = strchr(line, '\n')) != NULL)
2061					*cp = '\0';
2062				lreply(250, "%s", line);
2063			}
2064			(void) fflush(stdout);
2065			(void) fclose(message);
2066		}
2067		ack("CWD");
2068	}
2069}
2070
2071void
2072replydirname(const char *name, const char *message)
2073{
2074	char *p, *ep;
2075	char npath[MAXPATHLEN * 2];
2076
2077	p = npath;
2078	ep = &npath[sizeof(npath) - 1];
2079	while (*name) {
2080		if (*name == '"') {
2081			if (ep - p < 2)
2082				break;
2083			*p++ = *name++;
2084			*p++ = '"';
2085		} else {
2086			if (ep - p < 1)
2087				break;
2088			*p++ = *name++;
2089		}
2090	}
2091	*p = '\0';
2092	reply(257, "\"%s\" %s", npath, message);
2093}
2094
2095void
2096makedir(char *name)
2097{
2098
2099	LOGCMD("mkdir", name);
2100	if (mkdir(name, 0777) < 0)
2101		perror_reply(550, name);
2102	else
2103		replydirname(name, "directory created.");
2104}
2105
2106void
2107removedir(char *name)
2108{
2109
2110	LOGCMD("rmdir", name);
2111	if (rmdir(name) < 0)
2112		perror_reply(550, name);
2113	else
2114		ack("RMD");
2115}
2116
2117void
2118pwd(void)
2119{
2120	char path[MAXPATHLEN];
2121
2122	if (getcwd(path, sizeof(path)) == NULL)
2123		perror_reply(550, "Can't get current directory");
2124	else
2125		replydirname(path, "is current directory.");
2126}
2127
2128char *
2129renamefrom(char *name)
2130{
2131	struct stat st;
2132
2133	if (stat(name, &st) < 0) {
2134		perror_reply(550, name);
2135		return ((char *)0);
2136	}
2137	reply(350, "File exists, ready for destination name");
2138	return (name);
2139}
2140
2141void
2142renamecmd(char *from, char *to)
2143{
2144
2145	LOGCMD2("rename", from, to);
2146	if (rename(from, to) < 0)
2147		perror_reply(550, "rename");
2148	else
2149		ack("RNTO");
2150}
2151
2152static void
2153dolog(struct sockaddr *sa)
2154{
2155	char hbuf[sizeof(remotehost)];
2156
2157	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0) == 0)
2158		(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2159	else
2160		(void) strlcpy(remotehost, "unknown", sizeof(remotehost));
2161
2162#ifdef HASSETPROCTITLE
2163	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2164	setproctitle("%s", proctitle);
2165#endif /* HASSETPROCTITLE */
2166
2167	if (logging)
2168		syslog(LOG_INFO, "connection from %s", remotehost);
2169}
2170
2171/*
2172 * Record logout in wtmp file and exit with supplied status.
2173 * NOTE: because this is called from signal handlers it cannot
2174 *       use stdio (or call other functions that use stdio).
2175 */
2176void
2177dologout(int status)
2178{
2179
2180	transflag = 0;
2181
2182	if (logged_in) {
2183		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2184		ftpdlogwtmp(ttyline, "", "");
2185		if (doutmp)
2186			ftpd_logout(utmp.ut_line);
2187	}
2188	/* beware of flushing buffers after a SIGPIPE */
2189	_exit(status);
2190}
2191
2192/*ARGSUSED*/
2193static void
2194sigurg(int signo)
2195{
2196
2197	recvurg = 1;
2198}
2199
2200static void
2201myoob(void)
2202{
2203	char *cp;
2204
2205	/* only process if transfer occurring */
2206	if (!transflag)
2207		return;
2208	cp = tmpline;
2209	if (getline(cp, 7, stdin) == NULL) {
2210		reply(221, "You could at least say goodbye.");
2211		dologout(0);
2212	}
2213	upper(cp);
2214	if (strcmp(cp, "ABOR\r\n") == 0) {
2215		tmpline[0] = '\0';
2216		reply(426, "Transfer aborted. Data connection closed.");
2217		reply(226, "Abort successful");
2218	}
2219	if (strcmp(cp, "STAT\r\n") == 0) {
2220		tmpline[0] = '\0';
2221		if (file_size != (off_t) -1)
2222			reply(213, "Status: %qd of %qd bytes transferred",
2223			    byte_count, file_size);
2224		else
2225			reply(213, "Status: %qd bytes transferred", byte_count);
2226	}
2227}
2228
2229/*
2230 * Note: a response of 425 is not mentioned as a possible response to
2231 *	the PASV command in RFC959. However, it has been blessed as
2232 *	a legitimate response by Jon Postel in a telephone conversation
2233 *	with Rick Adams on 25 Jan 89.
2234 */
2235void
2236passive(void)
2237{
2238	socklen_t len;
2239	int on;
2240	u_char *p, *a;
2241
2242	if (pw == NULL) {
2243		reply(530, "Please login with USER and PASS");
2244		return;
2245	}
2246	if (pdata >= 0)
2247		close(pdata);
2248	/*
2249	 * XXX
2250	 * At this point, it would be nice to have an algorithm that
2251	 * inserted a growing delay in an attack scenario.  Such a thing
2252	 * would look like continual passive sockets being opened, but
2253	 * nothing serious being done with them.  They're not used to
2254	 * move data; the entire attempt is just to use tcp FIN_WAIT
2255	 * resources.
2256	 */
2257	pdata = socket(AF_INET, SOCK_STREAM, 0);
2258	if (pdata < 0) {
2259		perror_reply(425, "Can't open passive connection");
2260		return;
2261	}
2262
2263	on = IP_PORTRANGE_HIGH;
2264	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2265	    &on, sizeof(on)) < 0)
2266		goto pasv_error;
2267
2268	pasv_addr = ctrl_addr;
2269	pasv_addr.su_sin.sin_port = 0;
2270	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2271	    pasv_addr.su_len) < 0)
2272		goto pasv_error;
2273
2274	len = sizeof(pasv_addr);
2275	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2276		goto pasv_error;
2277	if (listen(pdata, 1) < 0)
2278		goto pasv_error;
2279	a = (u_char *)&pasv_addr.su_sin.sin_addr;
2280	p = (u_char *)&pasv_addr.su_sin.sin_port;
2281
2282	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2283	    a[1], a[2], a[3], p[0], p[1]);
2284	return;
2285
2286pasv_error:
2287	(void) close(pdata);
2288	pdata = -1;
2289	perror_reply(425, "Can't open passive connection");
2290	return;
2291}
2292
2293int
2294epsvproto2af(int proto)
2295{
2296
2297	switch (proto) {
2298	case 1:	return AF_INET;
2299#ifdef INET6
2300	case 2:	return AF_INET6;
2301#endif
2302	default: return -1;
2303	}
2304}
2305
2306int
2307af2epsvproto(int af)
2308{
2309
2310	switch (af) {
2311	case AF_INET:	return 1;
2312#ifdef INET6
2313	case AF_INET6:	return 2;
2314#endif
2315	default:	return -1;
2316	}
2317}
2318
2319/*
2320 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2321 * 229 Entering Extended Passive Mode (|||port|)
2322 */
2323void
2324long_passive(char *cmd, int pf)
2325{
2326	socklen_t len;
2327	int on;
2328	u_char *p, *a;
2329
2330	if (!logged_in) {
2331		syslog(LOG_NOTICE, "long passive but not logged in");
2332		reply(503, "Login with USER first.");
2333		return;
2334	}
2335
2336	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2337		/*
2338		 * XXX
2339		 * only EPRT/EPSV ready clients will understand this
2340		 */
2341		if (strcmp(cmd, "EPSV") != 0)
2342			reply(501, "Network protocol mismatch"); /*XXX*/
2343		else
2344			epsv_protounsupp("Network protocol mismatch");
2345
2346		return;
2347	}
2348
2349	if (pdata >= 0)
2350		close(pdata);
2351	/*
2352	 * XXX
2353	 * At this point, it would be nice to have an algorithm that
2354	 * inserted a growing delay in an attack scenario.  Such a thing
2355	 * would look like continual passive sockets being opened, but
2356	 * nothing serious being done with them.  They not used to move
2357	 * data; the entire attempt is just to use tcp FIN_WAIT
2358	 * resources.
2359	 */
2360	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2361	if (pdata < 0) {
2362		perror_reply(425, "Can't open passive connection");
2363		return;
2364	}
2365
2366	switch (ctrl_addr.su_family) {
2367	case AF_INET:
2368		on = IP_PORTRANGE_HIGH;
2369		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2370		    &on, sizeof(on)) < 0)
2371			goto pasv_error;
2372		break;
2373	case AF_INET6:
2374		on = IPV6_PORTRANGE_HIGH;
2375		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2376		    &on, sizeof(on)) < 0)
2377			goto pasv_error;
2378		break;
2379	}
2380
2381	pasv_addr = ctrl_addr;
2382	pasv_addr.su_port = 0;
2383	if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
2384		goto pasv_error;
2385	len = pasv_addr.su_len;
2386	if (getsockname(pdata, (struct sockaddr *)&pasv_addr, &len) < 0)
2387		goto pasv_error;
2388	if (listen(pdata, 1) < 0)
2389		goto pasv_error;
2390	p = (u_char *)&pasv_addr.su_port;
2391
2392	if (strcmp(cmd, "LPSV") == 0) {
2393		switch (pasv_addr.su_family) {
2394		case AF_INET:
2395			a = (u_char *)&pasv_addr.su_sin.sin_addr;
2396			reply(228,
2397			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2398			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2399			return;
2400		case AF_INET6:
2401			a = (u_char *)&pasv_addr.su_sin6.sin6_addr;
2402			reply(228,
2403			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2404			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2405				6, 16, a[0], a[1], a[2], a[3], a[4],
2406				a[5], a[6], a[7], a[8], a[9], a[10],
2407				a[11], a[12], a[13], a[14], a[15],
2408				2, p[0], p[1]);
2409			return;
2410		}
2411	} else if (strcmp(cmd, "EPSV") == 0) {
2412		switch (pasv_addr.su_family) {
2413		case AF_INET:
2414		case AF_INET6:
2415			reply(229, "Entering Extended Passive Mode (|||%u|)",
2416			    ntohs(pasv_addr.su_port));
2417			return;
2418		}
2419	} else {
2420		/* more proper error code? */
2421	}
2422
2423  pasv_error:
2424	(void) close(pdata);
2425	pdata = -1;
2426	perror_reply(425, "Can't open passive connection");
2427	return;
2428}
2429
2430/*
2431 * EPRT |proto|addr|port|
2432 */
2433int
2434extended_port(const char *arg)
2435{
2436	char *tmp = NULL;
2437	char *result[3];
2438	char *p, *q;
2439	char delim;
2440	struct addrinfo hints;
2441	struct addrinfo *res = NULL;
2442	int i;
2443	unsigned long proto;
2444
2445	if (epsvall) {
2446		reply(501, "EPRT disallowed after EPSV ALL");
2447		return -1;
2448	}
2449
2450	usedefault = 0;
2451	if (pdata >= 0) {
2452		(void) close(pdata);
2453		pdata = -1;
2454	}
2455
2456	tmp = strdup(arg);
2457	if (!tmp) {
2458		fatal("not enough core.");
2459		/*NOTREACHED*/
2460	}
2461	p = tmp;
2462	delim = p[0];
2463	p++;
2464	memset(result, 0, sizeof(result));
2465	for (i = 0; i < 3; i++) {
2466		q = strchr(p, delim);
2467		if (!q || *q != delim)
2468			goto parsefail;
2469		*q++ = '\0';
2470		result[i] = p;
2471		p = q;
2472	}
2473
2474	/* some more sanity check */
2475	p = NULL;
2476	(void)strtoul(result[2], &p, 10);
2477	if (!*result[2] || *p)
2478		goto protounsupp;
2479	p = NULL;
2480	proto = strtoul(result[0], &p, 10);
2481	if (!*result[0] || *p)
2482		goto protounsupp;
2483
2484	memset(&hints, 0, sizeof(hints));
2485	hints.ai_family = epsvproto2af((int)proto);
2486	if (hints.ai_family < 0)
2487		goto protounsupp;
2488	hints.ai_socktype = SOCK_STREAM;
2489	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2490	if (getaddrinfo(result[1], result[2], &hints, &res))
2491		goto parsefail;
2492	if (res->ai_next)
2493		goto parsefail;
2494	if (sizeof(data_dest) < res->ai_addrlen)
2495		goto parsefail;
2496	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2497	if (his_addr.su_family == AF_INET6 &&
2498	    data_dest.su_family == AF_INET6) {
2499		/* XXX more sanity checks! */
2500		data_dest.su_sin6.sin6_scope_id =
2501		    his_addr.su_sin6.sin6_scope_id;
2502	}
2503	if (pdata >= 0) {
2504		(void) close(pdata);
2505		pdata = -1;
2506	}
2507	reply(200, "EPRT command successful.");
2508
2509	if (tmp)
2510		free(tmp);
2511	if (res)
2512		freeaddrinfo(res);
2513	return 0;
2514
2515parsefail:
2516	reply(500, "Invalid argument, rejected.");
2517	usedefault = 1;
2518	if (tmp)
2519		free(tmp);
2520	if (res)
2521		freeaddrinfo(res);
2522	return -1;
2523
2524protounsupp:
2525	epsv_protounsupp("Protocol not supported");
2526	usedefault = 1;
2527	if (tmp)
2528		free(tmp);
2529	if (res)
2530		freeaddrinfo(res);
2531	return -1;
2532}
2533
2534/*
2535 * 522 Protocol not supported (proto,...)
2536 * as we assume address family for control and data connections are the same,
2537 * we do not return the list of address families we support - instead, we
2538 * return the address family of the control connection.
2539 */
2540void
2541epsv_protounsupp(const char *message)
2542{
2543	int proto;
2544
2545	proto = af2epsvproto(ctrl_addr.su_family);
2546	if (proto < 0)
2547		reply(501, "%s", message);	/*XXX*/
2548	else
2549		reply(522, "%s, use (%d)", message, proto);
2550}
2551
2552/*
2553 * Generate unique name for file with basename "local".
2554 * The file named "local" is already known to exist.
2555 * Generates failure reply on error.
2556 */
2557static int
2558guniquefd(char *local, char **nam)
2559{
2560	static char new[MAXPATHLEN];
2561	struct stat st;
2562	int count, len, fd;
2563	char *cp;
2564
2565	cp = strrchr(local, '/');
2566	if (cp)
2567		*cp = '\0';
2568	if (stat(cp ? local : ".", &st) < 0) {
2569		perror_reply(553, cp ? local : ".");
2570		return (-1);
2571	}
2572	if (cp)
2573		*cp = '/';
2574	len = strlcpy(new, local, sizeof(new));
2575	if (len+2+1 >= sizeof(new)-1)
2576		return (-1);
2577	cp = new + len;
2578	*cp++ = '.';
2579	for (count = 1; count < 100; count++) {
2580		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2581		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2582		if (fd == -1)
2583			continue;
2584		if (nam)
2585			*nam = new;
2586		return (fd);
2587	}
2588	reply(452, "Unique file name cannot be created.");
2589	return (-1);
2590}
2591
2592/*
2593 * Format and send reply containing system error number.
2594 */
2595void
2596perror_reply(int code, char *string)
2597{
2598
2599	reply(code, "%s: %s.", string, strerror(errno));
2600}
2601
2602static char *onefile[] = {
2603	"",
2604	0
2605};
2606
2607void
2608send_file_list(char *whichf)
2609{
2610	struct stat st;
2611	DIR *dirp = NULL;
2612	struct dirent *dir;
2613	FILE *dout = NULL;
2614	char **dirlist;
2615	char *dirname;
2616	int simple = 0;
2617	volatile int freeglob = 0;
2618	glob_t gl;
2619
2620	if (strpbrk(whichf, "~{[*?") != NULL) {
2621		memset(&gl, 0, sizeof(gl));
2622		freeglob = 1;
2623		if (glob(whichf,
2624		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2625		    0, &gl)) {
2626			reply(550, "not found");
2627			goto out;
2628		} else if (gl.gl_pathc == 0) {
2629			errno = ENOENT;
2630			perror_reply(550, whichf);
2631			goto out;
2632		}
2633		dirlist = gl.gl_pathv;
2634	} else {
2635		onefile[0] = whichf;
2636		dirlist = onefile;
2637		simple = 1;
2638	}
2639
2640	while ((dirname = *dirlist++)) {
2641		if (stat(dirname, &st) < 0) {
2642			/*
2643			 * If user typed "ls -l", etc, and the client
2644			 * used NLST, do what the user meant.
2645			 */
2646			if (dirname[0] == '-' && *dirlist == NULL &&
2647			    transflag == 0) {
2648				retrieve("/bin/ls %s", dirname);
2649				goto out;
2650			}
2651			perror_reply(550, whichf);
2652			if (dout != NULL) {
2653				(void) fclose(dout);
2654				transflag = 0;
2655				data = -1;
2656				pdata = -1;
2657			}
2658			goto out;
2659		}
2660
2661		if (S_ISREG(st.st_mode)) {
2662			if (dout == NULL) {
2663				dout = dataconn("file list", (off_t)-1, "w");
2664				if (dout == NULL)
2665					goto out;
2666				transflag++;
2667			}
2668			fprintf(dout, "%s%s\n", dirname,
2669				type == TYPE_A ? "\r" : "");
2670			byte_count += strlen(dirname) + 1;
2671			continue;
2672		} else if (!S_ISDIR(st.st_mode))
2673			continue;
2674
2675		if ((dirp = opendir(dirname)) == NULL)
2676			continue;
2677
2678		while ((dir = readdir(dirp)) != NULL) {
2679			char nbuf[MAXPATHLEN];
2680
2681			if (recvurg) {
2682				myoob();
2683				recvurg = 0;
2684				transflag = 0;
2685				goto out;
2686			}
2687
2688			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2689				continue;
2690			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2691			    dir->d_namlen == 2)
2692				continue;
2693
2694			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2695				 dir->d_name);
2696
2697			/*
2698			 * We have to do a stat to insure it's
2699			 * not a directory or special file.
2700			 */
2701			if (simple || (stat(nbuf, &st) == 0 &&
2702			    S_ISREG(st.st_mode))) {
2703				if (dout == NULL) {
2704					dout = dataconn("file list", (off_t)-1,
2705						"w");
2706					if (dout == NULL)
2707						goto out;
2708					transflag++;
2709				}
2710				if (nbuf[0] == '.' && nbuf[1] == '/')
2711					fprintf(dout, "%s%s\n", &nbuf[2],
2712						type == TYPE_A ? "\r" : "");
2713				else
2714					fprintf(dout, "%s%s\n", nbuf,
2715						type == TYPE_A ? "\r" : "");
2716				byte_count += strlen(nbuf) + 1;
2717			}
2718		}
2719		(void) closedir(dirp);
2720	}
2721
2722	if (dout == NULL)
2723		reply(550, "No files found.");
2724	else if (ferror(dout) != 0)
2725		perror_reply(550, "Data connection");
2726	else
2727		reply(226, "Transfer complete.");
2728
2729	transflag = 0;
2730	if (dout != NULL)
2731		(void) fclose(dout);
2732	else {
2733		if (pdata >= 0)
2734			close(pdata);
2735	}
2736	data = -1;
2737	pdata = -1;
2738out:
2739	if (freeglob) {
2740		freeglob = 0;
2741		globfree(&gl);
2742	}
2743}
2744
2745/*ARGSUSED*/
2746static void
2747reapchild(int signo)
2748{
2749	int save_errno = errno;
2750	int rval;
2751
2752	do {
2753		rval = waitpid(-1, NULL, WNOHANG);
2754	} while (rval > 0 || (rval == -1 && errno == EINTR));
2755	errno = save_errno;
2756}
2757
2758void
2759logxfer(char *name, off_t size, time_t start)
2760{
2761	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2762	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2763	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2764	char *vpw;
2765	time_t now;
2766	int len;
2767
2768	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2769		time(&now);
2770
2771		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2772		if (vpw == NULL)
2773			return;
2774
2775		snprintf(path, sizeof(path), "%s/%s", dir, name);
2776		if (realpath(path, rpath) == NULL)
2777			strlcpy(rpath, path, sizeof(rpath));
2778		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2779
2780		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2781		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2782
2783		len = snprintf(buf, sizeof(buf),
2784		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2785		    ctime(&now), now - start + (now == start),
2786		    vremotehost, (long long)size, vpath,
2787		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2788		    'o', ((guest) ? 'a' : 'r'),
2789		    vpw, 0 /* none yet */,
2790		    ((guest) ? "*" : pw->pw_name), dhostname);
2791
2792		if (len >= sizeof(buf) || len == -1) {
2793			if ((len = strlen(buf)) == 0)
2794				return;		/* should not happen */
2795			buf[len - 1] = '\n';
2796		}
2797		write(statfd, buf, len);
2798		free(vpw);
2799	}
2800}
2801
2802void
2803set_slave_signals(void)
2804{
2805	struct sigaction sa;
2806
2807	sigemptyset(&sa.sa_mask);
2808	sa.sa_flags = SA_RESTART;
2809
2810	sa.sa_handler = SIG_DFL;
2811	(void) sigaction(SIGCHLD, &sa, NULL);
2812
2813	sa.sa_handler = sigurg;
2814	sa.sa_flags = 0;		/* don't restart syscalls for SIGURG */
2815	(void) sigaction(SIGURG, &sa, NULL);
2816
2817	sigfillset(&sa.sa_mask);	/* block all signals in handler */
2818	sa.sa_flags = SA_RESTART;
2819	sa.sa_handler = sigquit;
2820	(void) sigaction(SIGHUP, &sa, NULL);
2821	(void) sigaction(SIGINT, &sa, NULL);
2822	(void) sigaction(SIGQUIT, &sa, NULL);
2823	(void) sigaction(SIGTERM, &sa, NULL);
2824
2825	sa.sa_handler = lostconn;
2826	(void) sigaction(SIGPIPE, &sa, NULL);
2827
2828	sa.sa_handler = toolong;
2829	(void) sigaction(SIGALRM, &sa, NULL);
2830
2831#ifdef F_SETOWN
2832	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2833		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
2834#endif
2835}
2836
2837#if defined(TCPWRAPPERS)
2838static int
2839check_host(struct sockaddr *sa)
2840{
2841	struct sockaddr_in *sin;
2842	struct hostent *hp;
2843	char *addr;
2844
2845	if (sa->sa_family != AF_INET)
2846		return 1;	/*XXX*/
2847
2848	sin = (struct sockaddr_in *)sa;
2849	hp = gethostbyaddr((char *)&sin->sin_addr,
2850	    sizeof(struct in_addr), AF_INET);
2851	addr = inet_ntoa(sin->sin_addr);
2852	if (hp) {
2853		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2854			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2855			    hp->h_name, addr);
2856			return (0);
2857		}
2858	} else {
2859		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2860			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2861			return (0);
2862		}
2863	}
2864	return (1);
2865}
2866#endif	/* TCPWRAPPERS */
2867
2868/*
2869 * Allocate space and return a copy of the specified dir.
2870 * If 'dir' begins with a tilde (~), expand it.
2871 */
2872char *
2873copy_dir(char *dir, struct passwd *pw)
2874{
2875	char *cp;
2876	char *newdir;
2877	char *user = NULL;
2878	size_t dirsiz;
2879
2880	/* Nothing to expand */
2881	if (dir[0] != '~')
2882		return (strdup(dir));
2883
2884	/* "dir" is of form ~user/some/dir, lookup user. */
2885	if (dir[1] != '/' && dir[1] != '\0') {
2886		if ((cp = strchr(dir + 1, '/')) == NULL)
2887		    cp = dir + strlen(dir);
2888		if ((user = malloc((size_t)(cp - dir))) == NULL)
2889			return (NULL);
2890		strlcpy(user, dir + 1, (size_t)(cp - dir));
2891
2892		/* Only do lookup if it is a different user. */
2893		if (strcmp(user, pw->pw_name) != 0) {
2894			if ((pw = getpwnam(user)) == NULL) {
2895				/* No such user, interpret literally */
2896				free(user);
2897				return(strdup(dir));
2898			}
2899		}
2900	}
2901
2902	/*
2903	 * If there is no directory separator (/) then it is just pw_dir.
2904	 * Otherwise, replace ~foo with  pw_dir.
2905	 */
2906	if ((cp = strchr(dir + 1, '/')) == NULL) {
2907		newdir = strdup(pw->pw_dir);
2908	} else {
2909		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2910		if ((newdir = malloc(dirsiz)) == NULL) {
2911			free(user);
2912			return (NULL);
2913		}
2914		strlcpy(newdir, pw->pw_dir, dirsiz);
2915		strlcat(newdir, cp, dirsiz);
2916	}
2917
2918	if (user)
2919		free(user);
2920	return(newdir);
2921}
2922