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