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