ftpd.c revision 1.128
1/*	$OpenBSD: ftpd.c,v 1.128 2002/06/09 00:37:37 itojun 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.128 2002/06/09 00:37:37 itojun 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		strlcat(path, "/", sizeof 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%ld", (long)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				as = NULL;
894			}
895		} else {
896			authok = auth_userresponse(as, passwd, 0);
897			as = NULL;
898		}
899		if (authok == 0) {
900			reply(530, "Login incorrect.");
901			if (logging)
902				syslog(LOG_NOTICE,
903				    "FTP LOGIN FAILED FROM %s, %s",
904				    remotehost, curname);
905			pw = NULL;
906			if (login_attempts++ >= 5) {
907				syslog(LOG_NOTICE,
908				    "repeated login failures from %s",
909				    remotehost);
910				exit(0);
911			}
912			return;
913		}
914	} else if (lc != NULL) {
915		/* Save anonymous' password. */
916		if (guestpw != NULL)
917			free(guestpw);
918		guestpw = strdup(passwd);
919		if (guestpw == NULL)
920			fatal("Out of memory.");
921
922		authok = auth_approval(as, lc, pw->pw_name, "ftp");
923		auth_close(as);
924		as = NULL;
925		if (authok == 0) {
926			syslog(LOG_INFO|LOG_AUTH,
927			    "FTP LOGIN FAILED (HOST) as %s: approval failure.",
928			    pw->pw_name);
929			reply(530, "Approval failure.");
930			exit(0);
931		}
932	} else {
933		syslog(LOG_INFO|LOG_AUTH,
934		    "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
935		    pw->pw_class, pw->pw_name);
936		reply(530, "Permission denied.");
937		exit(0);
938	}
939	login_attempts = 0;		/* this time successful */
940	if (setegid((gid_t)pw->pw_gid) < 0) {
941		reply(550, "Can't set gid.");
942		return;
943	}
944	/* set umask via setusercontext() unless -u flag was given. */
945	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
946	if (umaskchange)
947		flags |= LOGIN_SETUMASK;
948	else
949		(void) umask(defumask);
950	setusercontext(lc, pw, (uid_t)0, flags);
951
952	/* open wtmp before chroot */
953	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
954
955	/* open utmp before chroot */
956	if (doutmp) {
957		memset((void *)&utmp, 0, sizeof(utmp));
958		(void)time(&utmp.ut_time);
959		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
960		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
961		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
962		login(&utmp);
963	}
964
965	/* open stats file before chroot */
966	if (guest && (stats == 1) && (statfd < 0))
967		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
968			stats = 0;
969
970	logged_in = 1;
971
972	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
973		char *newdir;
974
975		newdir = copy_dir(dir, pw);
976		if (newdir == NULL) {
977			perror_reply(421, "Local resource failure: malloc");
978			dologout(1);
979			/* NOTREACHED */
980		}
981		free(dir);
982		free(pw->pw_dir);
983		pw->pw_dir = newdir;
984	}
985
986	/* make sure pw->pw_dir is big enough to hold "/" */
987	if (strlen(pw->pw_dir) < 1) {
988		char *newdir;
989
990		newdir = malloc(2);
991		if (newdir == NULL) {
992			perror_reply(421, "Local resource failure: malloc");
993			dologout(1);
994			/* NOTREACHED */
995		}
996		strlcpy(newdir, pw->pw_dir, 2);
997		free(pw->pw_dir);
998		pw->pw_dir = newdir;
999	}
1000
1001	if (guest || dochroot) {
1002		if (multihome && guest) {
1003			struct stat ts;
1004
1005			/* Compute root directory. */
1006			snprintf(rootdir, sizeof(rootdir), "%s/%s",
1007				  pw->pw_dir, dhostname);
1008			if (stat(rootdir, &ts) < 0) {
1009				snprintf(rootdir, sizeof(rootdir), "%s/%s",
1010					  pw->pw_dir, hostname);
1011			}
1012		} else
1013			strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1014	}
1015	if (guest) {
1016		/*
1017		 * We MUST do a chdir() after the chroot. Otherwise
1018		 * the old current directory will be accessible as "."
1019		 * outside the new root!
1020		 */
1021		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1022			reply(550, "Can't set guest privileges.");
1023			goto bad;
1024		}
1025		strcpy(pw->pw_dir, "/");
1026		if (setenv("HOME", "/", 1) == -1) {
1027			reply(550, "Can't setup environment.");
1028			goto bad;
1029		}
1030	} else if (dochroot) {
1031		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1032			reply(550, "Can't change root.");
1033			goto bad;
1034		}
1035		strcpy(pw->pw_dir, "/");
1036		if (setenv("HOME", "/", 1) == -1) {
1037			reply(550, "Can't setup environment.");
1038			goto bad;
1039		}
1040	} else if (chdir(pw->pw_dir) < 0) {
1041		if (chdir("/") < 0) {
1042			reply(530, "User %s: can't change directory to %s.",
1043			    pw->pw_name, pw->pw_dir);
1044			goto bad;
1045		} else
1046			lreply(230, "No directory! Logging in with home=/");
1047	}
1048	if (seteuid((uid_t)pw->pw_uid) < 0) {
1049		reply(550, "Can't set uid.");
1050		goto bad;
1051	}
1052	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1053
1054	/*
1055	 * Set home directory so that use of ~ (tilde) works correctly.
1056	 */
1057	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1058		if (setenv("HOME", homedir, 1) == -1) {
1059			reply(550, "Can't setup environment.");
1060			goto bad;
1061		}
1062	}
1063
1064	/*
1065	 * Display a login message, if it exists.
1066	 * N.B. reply(230,) must follow the message.
1067	 */
1068	motd = login_getcapstr(lc, "welcome", NULL, NULL);
1069	if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1070		char *cp, line[LINE_MAX];
1071
1072		while (fgets(line, sizeof(line), fp) != NULL) {
1073			if ((cp = strchr(line, '\n')) != NULL)
1074				*cp = '\0';
1075			lreply(230, "%s", line);
1076		}
1077		(void) fflush(stdout);
1078		(void) fclose(fp);
1079	}
1080	if (motd != NULL)
1081		free(motd);
1082	if (guest) {
1083		if (ident != NULL)
1084			free(ident);
1085		ident = strdup(passwd);
1086		if (ident == NULL)
1087			fatal("Ran out of memory.");
1088		reply(230, "Guest login ok, access restrictions apply.");
1089#ifdef HASSETPROCTITLE
1090		snprintf(proctitle, sizeof(proctitle),
1091		    "%s: anonymous/%.*s", remotehost,
1092		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1093		    sizeof(": anonymous/")), passwd);
1094		setproctitle("%s", proctitle);
1095#endif /* HASSETPROCTITLE */
1096		if (logging)
1097			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1098			    remotehost, passwd);
1099	} else {
1100		reply(230, "User %s logged in.", pw->pw_name);
1101#ifdef HASSETPROCTITLE
1102		snprintf(proctitle, sizeof(proctitle),
1103		    "%s: %s", remotehost, pw->pw_name);
1104		setproctitle("%s", proctitle);
1105#endif /* HASSETPROCTITLE */
1106		if (logging)
1107			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1108			    remotehost, pw->pw_name);
1109	}
1110	login_close(lc);
1111	lc = NULL;
1112	return;
1113bad:
1114	/* Forget all about it... */
1115	login_close(lc);
1116	lc = NULL;
1117	end_login();
1118}
1119
1120void
1121retrieve(cmd, name)
1122	char *cmd, *name;
1123{
1124	FILE *fin, *dout;
1125	struct stat st;
1126	int (*closefunc)(FILE *);
1127	time_t start;
1128
1129	if (cmd == 0) {
1130		fin = fopen(name, "r"), closefunc = fclose;
1131		st.st_size = 0;
1132	} else {
1133		char line[BUFSIZ];
1134
1135		(void) snprintf(line, sizeof(line), cmd, name);
1136		name = line;
1137		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1138		st.st_size = -1;
1139		st.st_blksize = BUFSIZ;
1140	}
1141	if (fin == NULL) {
1142		if (errno != 0) {
1143			perror_reply(550, name);
1144			if (cmd == 0) {
1145				LOGCMD("get", name);
1146			}
1147		}
1148		return;
1149	}
1150	byte_count = -1;
1151	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1152		reply(550, "%s: not a plain file.", name);
1153		goto done;
1154	}
1155	if (restart_point) {
1156		if (type == TYPE_A) {
1157			off_t i, n;
1158			int c;
1159
1160			n = restart_point;
1161			i = 0;
1162			while (i++ < n) {
1163				if ((c=getc(fin)) == EOF) {
1164					perror_reply(550, name);
1165					goto done;
1166				}
1167				if (c == '\n')
1168					i++;
1169			}
1170		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1171			perror_reply(550, name);
1172			goto done;
1173		}
1174	}
1175	dout = dataconn(name, st.st_size, "w");
1176	if (dout == NULL)
1177		goto done;
1178	time(&start);
1179	send_data(fin, dout, st.st_blksize, st.st_size,
1180		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1181	if ((cmd == 0) && stats)
1182		logxfer(name, byte_count, start);
1183	(void) fclose(dout);
1184	data = -1;
1185done:
1186	if (pdata >= 0)
1187		(void) close(pdata);
1188	pdata = -1;
1189	if (cmd == 0)
1190		LOGBYTES("get", name, byte_count);
1191	(*closefunc)(fin);
1192}
1193
1194void
1195store(name, mode, unique)
1196	char *name, *mode;
1197	int unique;
1198{
1199	FILE *fout, *din;
1200	int (*closefunc)(FILE *);
1201	struct stat st;
1202	int fd;
1203
1204	if (restart_point && *mode != 'a')
1205		mode = "r+";
1206
1207	if (unique && stat(name, &st) == 0) {
1208		char *nam;
1209
1210		fd = guniquefd(name, &nam);
1211		if (fd == -1) {
1212			LOGCMD(*mode == 'w' ? "put" : "append", name);
1213			return;
1214		}
1215		name = nam;
1216		fout = fdopen(fd, mode);
1217	} else
1218		fout = fopen(name, mode);
1219
1220	closefunc = fclose;
1221	if (fout == NULL) {
1222		perror_reply(553, name);
1223		LOGCMD(*mode == 'w' ? "put" : "append", name);
1224		return;
1225	}
1226	byte_count = -1;
1227	if (restart_point) {
1228		if (type == TYPE_A) {
1229			off_t i, n;
1230			int c;
1231
1232			n = restart_point;
1233			i = 0;
1234			while (i++ < n) {
1235				if ((c=getc(fout)) == EOF) {
1236					perror_reply(550, name);
1237					goto done;
1238				}
1239				if (c == '\n')
1240					i++;
1241			}
1242			/*
1243			 * We must do this seek to "current" position
1244			 * because we are changing from reading to
1245			 * writing.
1246			 */
1247			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1248				perror_reply(550, name);
1249				goto done;
1250			}
1251		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1252			perror_reply(550, name);
1253			goto done;
1254		}
1255	}
1256	din = dataconn(name, (off_t)-1, "r");
1257	if (din == NULL)
1258		goto done;
1259	if (receive_data(din, fout) == 0) {
1260		if (unique)
1261			reply(226, "Transfer complete (unique file name:%s).",
1262			    name);
1263		else
1264			reply(226, "Transfer complete.");
1265	}
1266	(void) fclose(din);
1267	data = -1;
1268	pdata = -1;
1269done:
1270	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1271	(*closefunc)(fout);
1272}
1273
1274static FILE *
1275getdatasock(mode)
1276	char *mode;
1277{
1278	int on = 1, s, t, tries;
1279
1280	if (data >= 0)
1281		return (fdopen(data, mode));
1282	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1283	(void) seteuid((uid_t)0);
1284	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1285	if (s < 0)
1286		goto bad;
1287	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1288	    (char *) &on, sizeof(on)) < 0)
1289		goto bad;
1290	/* anchor socket to avoid multi-homing problems */
1291	data_source = ctrl_addr;
1292	data_source.su_port = htons(20); /* ftp-data port */
1293	for (tries = 1; ; tries++) {
1294		if (bind(s, (struct sockaddr *)&data_source,
1295		    data_source.su_len) >= 0)
1296			break;
1297		if (errno != EADDRINUSE || tries > 10)
1298			goto bad;
1299		sleep(tries);
1300	}
1301	(void) seteuid((uid_t)pw->pw_uid);
1302	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1303
1304#ifdef IP_TOS
1305	if (ctrl_addr.su_family == AF_INET) {
1306		on = IPTOS_THROUGHPUT;
1307		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1308		    sizeof(int)) < 0)
1309			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1310	}
1311#endif
1312#ifdef TCP_NOPUSH
1313	/*
1314	 * Turn off push flag to keep sender TCP from sending short packets
1315	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1316	 * to set the send buffer size as well, but that may not be desirable
1317	 * in heavy-load situations.
1318	 */
1319	on = 1;
1320	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof(on)) < 0)
1321		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1322#endif
1323#ifdef SO_SNDBUF
1324	on = 65536;
1325	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof(on)) < 0)
1326		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1327#endif
1328
1329	return (fdopen(s, mode));
1330bad:
1331	/* Return the real value of errno (close may change it) */
1332	t = errno;
1333	(void) seteuid((uid_t)pw->pw_uid);
1334	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1335	(void) close(s);
1336	errno = t;
1337	return (NULL);
1338}
1339
1340static FILE *
1341dataconn(name, size, mode)
1342	char *name;
1343	off_t size;
1344	char *mode;
1345{
1346	char sizebuf[32];
1347	FILE *file;
1348	int retry = 0;
1349	in_port_t *p;
1350	char *fa, *ha;
1351	int alen;
1352
1353	file_size = size;
1354	byte_count = 0;
1355	if (size != (off_t) -1) {
1356		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1357				size);
1358	} else
1359		sizebuf[0] = '\0';
1360	if (pdata >= 0) {
1361		union sockunion from;
1362		int s, fromlen = sizeof(from);
1363
1364		signal (SIGALRM, toolong);
1365		(void) alarm ((unsigned) timeout);
1366		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1367		(void) alarm (0);
1368		if (s < 0) {
1369			reply(425, "Can't open data connection.");
1370			(void) close(pdata);
1371			pdata = -1;
1372			return (NULL);
1373		}
1374		switch (from.su_family) {
1375		case AF_INET:
1376			p = (in_port_t *)&from.su_sin.sin_port;
1377			fa = (u_char *)&from.su_sin.sin_addr;
1378			ha = (u_char *)&his_addr.su_sin.sin_addr;
1379			alen = sizeof(struct in_addr);
1380			break;
1381		case AF_INET6:
1382			p = (in_port_t *)&from.su_sin6.sin6_port;
1383			fa = (u_char *)&from.su_sin6.sin6_addr;
1384			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1385			alen = sizeof(struct in6_addr);
1386			break;
1387		default:
1388			perror_reply(425, "Can't build data connection");
1389			(void) close(pdata);
1390			(void) close(s);
1391			pdata = -1;
1392			return (NULL);
1393		}
1394		if (from.su_family != his_addr.su_family ||
1395		    ntohs(*p) < IPPORT_RESERVED) {
1396			perror_reply(425, "Can't build data connection");
1397			(void) close(pdata);
1398			(void) close(s);
1399			pdata = -1;
1400			return (NULL);
1401		}
1402		if (portcheck && memcmp(fa, ha, alen) != 0) {
1403			perror_reply(435, "Can't build data connection");
1404			(void) close(pdata);
1405			(void) close(s);
1406			pdata = -1;
1407			return (NULL);
1408		}
1409		(void) close(pdata);
1410		pdata = s;
1411		reply(150, "Opening %s mode data connection for '%s'%s.",
1412		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1413		return (fdopen(pdata, mode));
1414	}
1415	if (data >= 0) {
1416		reply(125, "Using existing data connection for '%s'%s.",
1417		    name, sizebuf);
1418		usedefault = 1;
1419		return (fdopen(data, mode));
1420	}
1421	if (usedefault)
1422		data_dest = his_addr;
1423	usedefault = 1;
1424	file = getdatasock(mode);
1425	if (file == NULL) {
1426		char hbuf[MAXHOSTNAMELEN], pbuf[10];
1427
1428		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1429		    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1430		    NI_NUMERICHOST | NI_NUMERICSERV);
1431		reply(425, "Can't create data socket (%s,%s): %s.",
1432		    hbuf, pbuf, strerror(errno));
1433		return (NULL);
1434	}
1435	data = fileno(file);
1436
1437	/*
1438	 * attempt to connect to reserved port on client machine;
1439	 * this looks like an attack
1440	 */
1441	switch (data_dest.su_family) {
1442	case AF_INET:
1443		p = (in_port_t *)&data_dest.su_sin.sin_port;
1444		fa = (u_char *)&data_dest.su_sin.sin_addr;
1445		ha = (u_char *)&his_addr.su_sin.sin_addr;
1446		alen = sizeof(struct in_addr);
1447		break;
1448	case AF_INET6:
1449		p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1450		fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1451		ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1452		alen = sizeof(struct in6_addr);
1453		break;
1454	default:
1455		perror_reply(425, "Can't build data connection");
1456		(void) fclose(file);
1457		pdata = -1;
1458		return (NULL);
1459	}
1460	if (data_dest.su_family != his_addr.su_family ||
1461	    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) {	/* XXX */
1462		perror_reply(425, "Can't build data connection");
1463		(void) fclose(file);
1464		data = -1;
1465		return NULL;
1466	}
1467	if (portcheck && memcmp(fa, ha, alen) != 0) {
1468		perror_reply(435, "Can't build data connection");
1469		(void) fclose(file);
1470		data = -1;
1471		return NULL;
1472	}
1473	while (connect(data, (struct sockaddr *)&data_dest,
1474	    data_dest.su_len) < 0) {
1475		if (errno == EADDRINUSE && retry < swaitmax) {
1476			sleep((unsigned) swaitint);
1477			retry += swaitint;
1478			continue;
1479		}
1480		perror_reply(425, "Can't build data connection");
1481		(void) fclose(file);
1482		data = -1;
1483		return (NULL);
1484	}
1485	reply(150, "Opening %s mode data connection for '%s'%s.",
1486	    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1487	return (file);
1488}
1489
1490/*
1491 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1492 * encapsulation of the data subject to Mode, Structure, and Type.
1493 *
1494 * NB: Form isn't handled.
1495 */
1496static int
1497send_data(instr, outstr, blksize, filesize, isreg)
1498	FILE *instr, *outstr;
1499	off_t blksize;
1500	off_t filesize;
1501	int isreg;
1502{
1503	int c, cnt, filefd, netfd;
1504	char *buf, *bp;
1505	size_t len;
1506
1507	transflag++;
1508	switch (type) {
1509
1510	case TYPE_A:
1511		while ((c = getc(instr)) != EOF) {
1512			if (recvurg)
1513				goto got_oob;
1514			byte_count++;
1515			if (c == '\n') {
1516				if (ferror(outstr))
1517					goto data_err;
1518				(void) putc('\r', outstr);
1519			}
1520			(void) putc(c, outstr);
1521		}
1522		fflush(outstr);
1523		transflag = 0;
1524		if (ferror(instr))
1525			goto file_err;
1526		if (ferror(outstr))
1527			goto data_err;
1528		reply(226, "Transfer complete.");
1529		return(0);
1530
1531	case TYPE_I:
1532	case TYPE_L:
1533		/*
1534		 * isreg is only set if we are not doing restart and we
1535		 * are sending a regular file
1536		 */
1537		netfd = fileno(outstr);
1538		filefd = fileno(instr);
1539
1540		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1541			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1542				   (off_t)0);
1543			if (buf == MAP_FAILED) {
1544				syslog(LOG_WARNING, "mmap(%lu): %m",
1545				    (unsigned long)filesize);
1546				goto oldway;
1547			}
1548			bp = buf;
1549			len = filesize;
1550			do {
1551				cnt = write(netfd, bp, len);
1552				if (recvurg) {
1553					munmap(buf, (size_t)filesize);
1554					goto got_oob;
1555				}
1556				len -= cnt;
1557				bp += cnt;
1558				if (cnt > 0) byte_count += cnt;
1559			} while(cnt > 0 && len > 0);
1560
1561			transflag = 0;
1562			munmap(buf, (size_t)filesize);
1563			if (cnt < 0)
1564				goto data_err;
1565			reply(226, "Transfer complete.");
1566			return(0);
1567		}
1568
1569oldway:
1570		if ((buf = malloc((u_int)blksize)) == NULL) {
1571			transflag = 0;
1572			perror_reply(451, "Local resource failure: malloc");
1573			return(-1);
1574		}
1575
1576		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1577		    write(netfd, buf, cnt) == cnt)
1578			byte_count += cnt;
1579		transflag = 0;
1580		(void)free(buf);
1581		if (cnt != 0) {
1582			if (cnt < 0)
1583				goto file_err;
1584			goto data_err;
1585		}
1586		reply(226, "Transfer complete.");
1587		return(0);
1588	default:
1589		transflag = 0;
1590		reply(550, "Unimplemented TYPE %d in send_data", type);
1591		return(-1);
1592	}
1593
1594data_err:
1595	transflag = 0;
1596	perror_reply(426, "Data connection");
1597	return(-1);
1598
1599file_err:
1600	transflag = 0;
1601	perror_reply(551, "Error on input file");
1602	return(-1);
1603
1604got_oob:
1605	myoob();
1606	recvurg = 0;
1607	transflag = 0;
1608	return(-1);
1609}
1610
1611/*
1612 * Transfer data from peer to "outstr" using the appropriate encapulation of
1613 * the data subject to Mode, Structure, and Type.
1614 *
1615 * N.B.: Form isn't handled.
1616 */
1617static int
1618receive_data(instr, outstr)
1619	FILE *instr, *outstr;
1620{
1621	int c;
1622	int cnt;
1623	char buf[BUFSIZ];
1624	struct sigaction sa;
1625	volatile int bare_lfs = 0;
1626
1627	transflag++;
1628	switch (type) {
1629
1630	case TYPE_I:
1631	case TYPE_L:
1632		sigfillset(&sa.sa_mask);
1633		sa.sa_flags = SA_RESTART;
1634		sigaction(SIGALRM, &sa, NULL);
1635
1636		do {
1637			(void) alarm ((unsigned) timeout);
1638			cnt = read(fileno(instr), buf, sizeof(buf));
1639			(void) alarm (0);
1640			if (recvurg)
1641				goto got_oob;
1642
1643			if (cnt > 0) {
1644				if (write(fileno(outstr), buf, cnt) != cnt)
1645					goto file_err;
1646				byte_count += cnt;
1647			}
1648		} while (cnt > 0);
1649		if (cnt < 0)
1650			goto data_err;
1651		transflag = 0;
1652		return (0);
1653
1654	case TYPE_E:
1655		reply(553, "TYPE E not implemented.");
1656		transflag = 0;
1657		return (-1);
1658
1659	case TYPE_A:
1660		while ((c = getc(instr)) != EOF) {
1661			if (recvurg)
1662				goto got_oob;
1663			byte_count++;
1664			if (c == '\n')
1665				bare_lfs++;
1666			while (c == '\r') {
1667				if (ferror(outstr))
1668					goto data_err;
1669				if ((c = getc(instr)) != '\n') {
1670					(void) putc ('\r', outstr);
1671					if (c == '\0' || c == EOF)
1672						goto contin2;
1673				}
1674			}
1675			(void) putc(c, outstr);
1676	contin2:	;
1677		}
1678		fflush(outstr);
1679		if (ferror(instr))
1680			goto data_err;
1681		if (ferror(outstr))
1682			goto file_err;
1683		transflag = 0;
1684		if (bare_lfs) {
1685			lreply(226,
1686			    "WARNING! %d bare linefeeds received in ASCII mode",
1687			    bare_lfs);
1688			printf("   File may not have transferred correctly.\r\n");
1689		}
1690		return (0);
1691	default:
1692		reply(550, "Unimplemented TYPE %d in receive_data", type);
1693		transflag = 0;
1694		return (-1);
1695	}
1696
1697data_err:
1698	transflag = 0;
1699	perror_reply(426, "Data Connection");
1700	return (-1);
1701
1702file_err:
1703	transflag = 0;
1704	perror_reply(452, "Error writing file");
1705	return (-1);
1706
1707got_oob:
1708	myoob();
1709	recvurg = 0;
1710	transflag = 0;
1711	return (-1);
1712}
1713
1714void
1715statfilecmd(filename)
1716	char *filename;
1717{
1718	FILE *fin;
1719	int c;
1720	int atstart;
1721	char line[LINE_MAX];
1722
1723	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1724	fin = ftpd_popen(line, "r");
1725	lreply(211, "status of %s:", filename);
1726	atstart = 1;
1727	while ((c = getc(fin)) != EOF) {
1728		if (c == '\n') {
1729			if (ferror(stdout)){
1730				perror_reply(421, "control connection");
1731				(void) ftpd_pclose(fin);
1732				dologout(1);
1733				/* NOTREACHED */
1734			}
1735			if (ferror(fin)) {
1736				perror_reply(551, filename);
1737				(void) ftpd_pclose(fin);
1738				return;
1739			}
1740			(void) putc('\r', stdout);
1741		}
1742		if (atstart && isdigit(c))
1743			(void) putc(' ', stdout);
1744		(void) putc(c, stdout);
1745		atstart = (c == '\n');
1746	}
1747	(void) ftpd_pclose(fin);
1748	reply(211, "End of Status");
1749}
1750
1751void
1752statcmd()
1753{
1754	union sockunion *su;
1755	u_char *a, *p;
1756	char hbuf[MAXHOSTNAMELEN];
1757	int ispassive;
1758
1759	lreply(211, "%s FTP server status:", hostname, version);
1760	printf("     %s\r\n", version);
1761	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1762	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1763	printf("     Connected to %s", remotehost);
1764	if (strcmp(remotehost, hbuf) != 0)
1765		printf(" (%s)", hbuf);
1766	printf("\r\n");
1767	if (logged_in) {
1768		if (guest)
1769			printf("     Logged in anonymously\r\n");
1770		else
1771			printf("     Logged in as %s\r\n", pw->pw_name);
1772	} else if (askpasswd)
1773		printf("     Waiting for password\r\n");
1774	else
1775		printf("     Waiting for user name\r\n");
1776	printf("     TYPE: %s", typenames[type]);
1777	if (type == TYPE_A || type == TYPE_E)
1778		printf(", FORM: %s", formnames[form]);
1779	if (type == TYPE_L)
1780#if NBBY == 8
1781		printf(" %d", NBBY);
1782#else
1783		printf(" %d", bytesize);	/* need definition! */
1784#endif
1785	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1786	    strunames[stru], modenames[mode]);
1787	ispassive = 0;
1788	if (data != -1)
1789		printf("     Data connection open\r\n");
1790	else if (pdata != -1) {
1791		printf("     in Passive mode\r\n");
1792		su = (union sockunion *)&pasv_addr;
1793		ispassive++;
1794		goto printaddr;
1795	} else if (usedefault == 0) {
1796		su = (union sockunion *)&data_dest;
1797printaddr:
1798		/* PASV/PORT */
1799		if (su->su_family == AF_INET) {
1800			if (ispassive)
1801				printf("211- PASV ");
1802			else
1803				printf("211- PORT ");
1804			a = (u_char *) &su->su_sin.sin_addr;
1805			p = (u_char *) &su->su_sin.sin_port;
1806			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1807			    a[0], a[1], a[2], a[3],
1808			    p[0], p[1]);
1809		}
1810
1811		/* LPSV/LPRT */
1812	    {
1813		int alen, af, i;
1814
1815		alen = 0;
1816		switch (su->su_family) {
1817		case AF_INET:
1818			a = (u_char *) &su->su_sin.sin_addr;
1819			p = (u_char *) &su->su_sin.sin_port;
1820			alen = sizeof(su->su_sin.sin_addr);
1821			af = 4;
1822			break;
1823		case AF_INET6:
1824			a = (u_char *) &su->su_sin6.sin6_addr;
1825			p = (u_char *) &su->su_sin6.sin6_port;
1826			alen = sizeof(su->su_sin6.sin6_addr);
1827			af = 6;
1828			break;
1829		default:
1830			af = 0;
1831			break;
1832		}
1833		if (af) {
1834			if (ispassive)
1835				printf("211- LPSV ");
1836			else
1837				printf("211- LPRT ");
1838			printf("(%u,%u", af, alen);
1839			for (i = 0; i < alen; i++)
1840				printf(",%u", a[i]);
1841			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1842		}
1843	    }
1844
1845		/* EPRT/EPSV */
1846	    {
1847		u_char af;
1848
1849		switch (su->su_family) {
1850		case AF_INET:
1851			af = 1;
1852			break;
1853		case AF_INET6:
1854			af = 2;
1855			break;
1856		default:
1857			af = 0;
1858			break;
1859		}
1860		if (af) {
1861			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1862			union sockunion tmp = *su;
1863
1864			if (tmp.su_family == AF_INET6)
1865				tmp.su_sin6.sin6_scope_id = 0;
1866			if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1867			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1868			    NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1869				if (ispassive)
1870					printf("211- EPSV ");
1871				else
1872					printf("211- EPRT ");
1873				printf("(|%u|%s|%s|)\r\n",
1874					af, hbuf, pbuf);
1875			}
1876		}
1877	    }
1878	} else
1879		printf("     No data connection\r\n");
1880	reply(211, "End of status");
1881}
1882
1883void
1884fatal(s)
1885	char *s;
1886{
1887
1888	reply(451, "Error in server: %s", s);
1889	reply(221, "Closing connection due to server error.");
1890	dologout(0);
1891	/* NOTREACHED */
1892}
1893
1894void
1895reply(int n, const char *fmt, ...)
1896{
1897	char *buf, *p, *next;
1898	va_list ap;
1899
1900	va_start(ap, fmt);
1901	if (vasprintf(&buf, fmt, ap) == -1 || buf == NULL) {
1902		printf("412 Local resource failure: malloc\r\n");
1903		fflush(stdout);
1904		dologout(1);
1905	}
1906	next = buf;
1907	while ((p = strsep(&next, "\n\r"))) {
1908		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1909		if (debug)
1910			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1911			    (next != '\0') ? "-" : "", p);
1912	}
1913	(void)fflush(stdout);
1914	free(buf);
1915	va_end(ap);
1916}
1917
1918void
1919lreply(int n, const char *fmt, ...)
1920{
1921	va_list ap;
1922
1923	va_start(ap, fmt);
1924	(void)printf("%d- ", n);
1925	(void)vprintf(fmt, ap);
1926	va_end(ap);
1927	(void)printf("\r\n");
1928	(void)fflush(stdout);
1929	if (debug) {
1930		va_start(ap, fmt);
1931		syslog(LOG_DEBUG, "<--- %d- ", n);
1932		vsyslog(LOG_DEBUG, fmt, ap);
1933		va_end(ap);
1934	}
1935}
1936
1937static void
1938ack(s)
1939	char *s;
1940{
1941
1942	reply(250, "%s command successful.", s);
1943}
1944
1945void
1946nack(s)
1947	char *s;
1948{
1949
1950	reply(502, "%s command not implemented.", s);
1951}
1952
1953/* ARGSUSED */
1954void
1955yyerror(s)
1956	char *s;
1957{
1958	char *cp;
1959
1960	if ((cp = strchr(cbuf,'\n')))
1961		*cp = '\0';
1962	reply(500, "'%s': command not understood.", cbuf);
1963}
1964
1965void
1966delete(name)
1967	char *name;
1968{
1969	struct stat st;
1970
1971	LOGCMD("delete", name);
1972	if (stat(name, &st) < 0) {
1973		perror_reply(550, name);
1974		return;
1975	}
1976	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1977		if (rmdir(name) < 0) {
1978			perror_reply(550, name);
1979			return;
1980		}
1981		goto done;
1982	}
1983	if (unlink(name) < 0) {
1984		perror_reply(550, name);
1985		return;
1986	}
1987done:
1988	ack("DELE");
1989}
1990
1991void
1992cwd(path)
1993	char *path;
1994{
1995	FILE *message;
1996
1997	if (chdir(path) < 0)
1998		perror_reply(550, path);
1999	else {
2000		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2001			char *cp, line[LINE_MAX];
2002
2003			while (fgets(line, sizeof(line), message) != NULL) {
2004				if ((cp = strchr(line, '\n')) != NULL)
2005					*cp = '\0';
2006				lreply(250, "%s", line);
2007			}
2008			(void) fflush(stdout);
2009			(void) fclose(message);
2010		}
2011		ack("CWD");
2012	}
2013}
2014
2015void
2016replydirname(name, message)
2017	const char *name, *message;
2018{
2019	char *p, *ep;
2020	char npath[MAXPATHLEN * 2];
2021
2022	p = npath;
2023	ep = &npath[sizeof(npath) - 1];
2024	while (*name) {
2025		if (*name == '"') {
2026			if (ep - p < 2)
2027				break;
2028			*p++ = *name++;
2029			*p++ = '"';
2030		} else {
2031			if (ep - p < 1)
2032				break;
2033			*p++ = *name++;
2034		}
2035	}
2036	*p = '\0';
2037	reply(257, "\"%s\" %s", npath, message);
2038}
2039
2040void
2041makedir(name)
2042	char *name;
2043{
2044
2045	LOGCMD("mkdir", name);
2046	if (mkdir(name, 0777) < 0)
2047		perror_reply(550, name);
2048	else
2049		replydirname(name, "directory created.");
2050}
2051
2052void
2053removedir(name)
2054	char *name;
2055{
2056
2057	LOGCMD("rmdir", name);
2058	if (rmdir(name) < 0)
2059		perror_reply(550, name);
2060	else
2061		ack("RMD");
2062}
2063
2064void
2065pwd()
2066{
2067	char path[MAXPATHLEN];
2068
2069	if (getcwd(path, sizeof(path)) == NULL)
2070		reply(550, "Can't get current directory: %s.", strerror(errno));
2071	else
2072		replydirname(path, "is current directory.");
2073}
2074
2075char *
2076renamefrom(name)
2077	char *name;
2078{
2079	struct stat st;
2080
2081	if (stat(name, &st) < 0) {
2082		perror_reply(550, name);
2083		return ((char *)0);
2084	}
2085	reply(350, "File exists, ready for destination name");
2086	return (name);
2087}
2088
2089void
2090renamecmd(from, to)
2091	char *from, *to;
2092{
2093
2094	LOGCMD2("rename", from, to);
2095	if (rename(from, to) < 0)
2096		perror_reply(550, "rename");
2097	else
2098		ack("RNTO");
2099}
2100
2101static void
2102dolog(sa)
2103	struct sockaddr *sa;
2104{
2105	char hbuf[sizeof(remotehost)];
2106
2107	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2108	(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2109
2110#ifdef HASSETPROCTITLE
2111	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2112	setproctitle("%s", proctitle);
2113#endif /* HASSETPROCTITLE */
2114
2115	if (logging)
2116		syslog(LOG_INFO, "connection from %s", remotehost);
2117}
2118
2119/*
2120 * Record logout in wtmp file and exit with supplied status.
2121 * NOTE: because this is called from signal handlers it cannot
2122 *       use stdio (or call other functions that use stdio).
2123 */
2124void
2125dologout(status)
2126	int status;
2127{
2128
2129	transflag = 0;
2130
2131	if (logged_in) {
2132		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2133		(void) seteuid((uid_t)0);
2134		ftpdlogwtmp(ttyline, "", "");
2135		if (doutmp)
2136			logout(utmp.ut_line);
2137	}
2138	/* beware of flushing buffers after a SIGPIPE */
2139	_exit(status);
2140}
2141
2142static void
2143sigurg(signo)
2144	int signo;
2145{
2146
2147	recvurg = 1;
2148}
2149
2150static void
2151myoob()
2152{
2153	char *cp;
2154
2155	/* only process if transfer occurring */
2156	if (!transflag)
2157		return;
2158	cp = tmpline;
2159	if (getline(cp, 7, stdin) == NULL) {
2160		reply(221, "You could at least say goodbye.");
2161		dologout(0);
2162	}
2163	upper(cp);
2164	if (strcmp(cp, "ABOR\r\n") == 0) {
2165		tmpline[0] = '\0';
2166		reply(426, "Transfer aborted. Data connection closed.");
2167		reply(226, "Abort successful");
2168	}
2169	if (strcmp(cp, "STAT\r\n") == 0) {
2170		tmpline[0] = '\0';
2171		if (file_size != (off_t) -1)
2172			reply(213, "Status: %qd of %qd bytes transferred",
2173			    byte_count, file_size);
2174		else
2175			reply(213, "Status: %qd bytes transferred", byte_count);
2176	}
2177}
2178
2179/*
2180 * Note: a response of 425 is not mentioned as a possible response to
2181 *	the PASV command in RFC959. However, it has been blessed as
2182 *	a legitimate response by Jon Postel in a telephone conversation
2183 *	with Rick Adams on 25 Jan 89.
2184 */
2185void
2186passive()
2187{
2188	int len, on;
2189	u_char *p, *a;
2190
2191	if (pw == NULL) {
2192		reply(530, "Please login with USER and PASS");
2193		return;
2194	}
2195	if (pdata >= 0)
2196		close(pdata);
2197	/*
2198	 * XXX
2199	 * At this point, it would be nice to have an algorithm that
2200	 * inserted a growing delay in an attack scenario.  Such a thing
2201	 * would look like continual passive sockets being opened, but
2202	 * nothing serious being done with them.  They're not used to
2203	 * move data; the entire attempt is just to use tcp FIN_WAIT
2204	 * resources.
2205	 */
2206	pdata = socket(AF_INET, SOCK_STREAM, 0);
2207	if (pdata < 0) {
2208		perror_reply(425, "Can't open passive connection");
2209		return;
2210	}
2211
2212#ifdef IP_PORTRANGE
2213	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2214	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2215	    (char *)&on, sizeof(on)) < 0)
2216		goto pasv_error;
2217#endif
2218
2219	pasv_addr = ctrl_addr;
2220	pasv_addr.su_sin.sin_port = 0;
2221	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2222		 pasv_addr.su_len) < 0)
2223		goto pasv_error;
2224
2225	len = sizeof(pasv_addr);
2226	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2227		goto pasv_error;
2228	if (listen(pdata, 1) < 0)
2229		goto pasv_error;
2230	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2231	p = (u_char *) &pasv_addr.su_sin.sin_port;
2232
2233	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2234	    a[1], a[2], a[3], p[0], p[1]);
2235	return;
2236
2237pasv_error:
2238	(void) seteuid((uid_t)pw->pw_uid);
2239	(void) close(pdata);
2240	pdata = -1;
2241	perror_reply(425, "Can't open passive connection");
2242	return;
2243}
2244
2245/*
2246 * convert protocol identifier to/from AF
2247 */
2248int
2249lpsvproto2af(int proto)
2250{
2251
2252	switch (proto) {
2253	case 4:	return AF_INET;
2254#ifdef INET6
2255	case 6:	return AF_INET6;
2256#endif
2257	default: return -1;
2258	}
2259}
2260
2261int
2262af2lpsvproto(int af)
2263{
2264
2265	switch (af) {
2266	case AF_INET:	return 4;
2267#ifdef INET6
2268	case AF_INET6:	return 6;
2269#endif
2270	default:	return -1;
2271	}
2272}
2273
2274int
2275epsvproto2af(int proto)
2276{
2277
2278	switch (proto) {
2279	case 1:	return AF_INET;
2280#ifdef INET6
2281	case 2:	return AF_INET6;
2282#endif
2283	default: return -1;
2284	}
2285}
2286
2287int
2288af2epsvproto(int af)
2289{
2290
2291	switch (af) {
2292	case AF_INET:	return 1;
2293#ifdef INET6
2294	case AF_INET6:	return 2;
2295#endif
2296	default:	return -1;
2297	}
2298}
2299
2300/*
2301 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2302 * 229 Entering Extended Passive Mode (|||port|)
2303 */
2304void
2305long_passive(char *cmd, int pf)
2306{
2307	int len, on;
2308	u_char *p, *a;
2309
2310	if (!logged_in) {
2311		syslog(LOG_NOTICE, "long passive but not logged in");
2312		reply(503, "Login with USER first.");
2313		return;
2314	}
2315
2316	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2317		/*
2318		 * XXX
2319		 * only EPRT/EPSV ready clients will understand this
2320		 */
2321		if (strcmp(cmd, "EPSV") != 0)
2322			reply(501, "Network protocol mismatch"); /*XXX*/
2323		else
2324			epsv_protounsupp("Network protocol mismatch");
2325
2326		return;
2327	}
2328
2329	if (pdata >= 0)
2330		close(pdata);
2331	/*
2332	 * XXX
2333	 * At this point, it would be nice to have an algorithm that
2334	 * inserted a growing delay in an attack scenario.  Such a thing
2335	 * would look like continual passive sockets being opened, but
2336	 * nothing serious being done with them.  They not used to move
2337	 * data; the entire attempt is just to use tcp FIN_WAIT
2338	 * resources.
2339	 */
2340	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2341	if (pdata < 0) {
2342		perror_reply(425, "Can't open passive connection");
2343		return;
2344	}
2345
2346	switch (ctrl_addr.su_family) {
2347	case AF_INET:
2348#ifdef IP_PORTRANGE
2349		on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2350		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2351		    (char *)&on, sizeof(on)) < 0)
2352			goto pasv_error;
2353#endif
2354		break;
2355	case AF_INET6:
2356#ifdef IPV6_PORTRANGE
2357		on = high_data_ports ? IPV6_PORTRANGE_HIGH
2358				     : IPV6_PORTRANGE_DEFAULT;
2359		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2360		    (char *)&on, sizeof(on)) < 0)
2361			goto pasv_error;
2362#endif
2363		break;
2364	}
2365
2366	pasv_addr = ctrl_addr;
2367	pasv_addr.su_port = 0;
2368	(void) seteuid((uid_t) 0);
2369	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2370		(void) seteuid((uid_t) pw->pw_uid);
2371		goto pasv_error;
2372	}
2373	(void) seteuid((uid_t) pw->pw_uid);
2374	len = pasv_addr.su_len;
2375	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2376		goto pasv_error;
2377	if (listen(pdata, 1) < 0)
2378		goto pasv_error;
2379	p = (u_char *) &pasv_addr.su_port;
2380
2381	if (strcmp(cmd, "LPSV") == 0) {
2382		switch (pasv_addr.su_family) {
2383		case AF_INET:
2384			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2385			reply(228,
2386			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2387			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2388			return;
2389		case AF_INET6:
2390			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2391			reply(228,
2392			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2393			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2394				6, 16, a[0], a[1], a[2], a[3], a[4],
2395				a[5], a[6], a[7], a[8], a[9], a[10],
2396				a[11], a[12], a[13], a[14], a[15],
2397				2, p[0], p[1]);
2398			return;
2399		}
2400	} else if (strcmp(cmd, "EPSV") == 0) {
2401		switch (pasv_addr.su_family) {
2402		case AF_INET:
2403		case AF_INET6:
2404			reply(229, "Entering Extended Passive Mode (|||%u|)",
2405			    ntohs(pasv_addr.su_port));
2406			return;
2407		}
2408	} else {
2409		/* more proper error code? */
2410	}
2411
2412  pasv_error:
2413	(void) close(pdata);
2414	pdata = -1;
2415	perror_reply(425, "Can't open passive connection");
2416	return;
2417}
2418
2419/*
2420 * EPRT |proto|addr|port|
2421 */
2422int
2423extended_port(const char *arg)
2424{
2425	char *tmp = NULL;
2426	char *result[3];
2427	char *p, *q;
2428	char delim;
2429	struct addrinfo hints;
2430	struct addrinfo *res = NULL;
2431	int i;
2432	unsigned long proto;
2433
2434	if (epsvall) {
2435		reply(501, "EPRT disallowed after EPSV ALL");
2436		return -1;
2437	}
2438
2439	usedefault = 0;
2440	if (pdata >= 0) {
2441		(void) close(pdata);
2442		pdata = -1;
2443	}
2444
2445	tmp = strdup(arg);
2446	if (!tmp) {
2447		fatal("not enough core.");
2448		/*NOTREACHED*/
2449	}
2450	p = tmp;
2451	delim = p[0];
2452	p++;
2453	memset(result, 0, sizeof(result));
2454	for (i = 0; i < 3; i++) {
2455		q = strchr(p, delim);
2456		if (!q || *q != delim)
2457			goto parsefail;
2458		*q++ = '\0';
2459		result[i] = p;
2460		p = q;
2461	}
2462
2463	/* some more sanity check */
2464	p = NULL;
2465	(void)strtoul(result[2], &p, 10);
2466	if (!*result[2] || *p)
2467		goto protounsupp;
2468	p = NULL;
2469	proto = strtoul(result[0], &p, 10);
2470	if (!*result[0] || *p)
2471		goto protounsupp;
2472
2473	memset(&hints, 0, sizeof(hints));
2474	hints.ai_family = epsvproto2af((int)proto);
2475	if (hints.ai_family < 0)
2476		goto protounsupp;
2477	hints.ai_socktype = SOCK_STREAM;
2478	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2479	if (getaddrinfo(result[1], result[2], &hints, &res))
2480		goto parsefail;
2481	if (res->ai_next)
2482		goto parsefail;
2483	if (sizeof(data_dest) < res->ai_addrlen)
2484		goto parsefail;
2485	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2486	if (his_addr.su_family == AF_INET6 &&
2487	    data_dest.su_family == AF_INET6) {
2488		/* XXX more sanity checks! */
2489		data_dest.su_sin6.sin6_scope_id =
2490		    his_addr.su_sin6.sin6_scope_id;
2491	}
2492	if (pdata >= 0) {
2493		(void) close(pdata);
2494		pdata = -1;
2495	}
2496	reply(200, "EPRT command successful.");
2497
2498	if (tmp)
2499		free(tmp);
2500	if (res)
2501		freeaddrinfo(res);
2502	return 0;
2503
2504parsefail:
2505	reply(500, "Invalid argument, rejected.");
2506	usedefault = 1;
2507	if (tmp)
2508		free(tmp);
2509	if (res)
2510		freeaddrinfo(res);
2511	return -1;
2512
2513protounsupp:
2514	epsv_protounsupp("Protocol not supported");
2515	usedefault = 1;
2516	if (tmp)
2517		free(tmp);
2518	if (res)
2519		freeaddrinfo(res);
2520	return -1;
2521}
2522
2523/*
2524 * 522 Protocol not supported (proto,...)
2525 * as we assume address family for control and data connections are the same,
2526 * we do not return the list of address families we support - instead, we
2527 * return the address family of the control connection.
2528 */
2529void
2530epsv_protounsupp(const char *message)
2531{
2532	int proto;
2533
2534	proto = af2epsvproto(ctrl_addr.su_family);
2535	if (proto < 0)
2536		reply(501, "%s", message);	/*XXX*/
2537	else
2538		reply(522, "%s, use (%d)", message, proto);
2539}
2540
2541/*
2542 * Generate unique name for file with basename "local".
2543 * The file named "local" is already known to exist.
2544 * Generates failure reply on error.
2545 */
2546static int
2547guniquefd(local, nam)
2548	char *local;
2549	char **nam;
2550{
2551	static char new[MAXPATHLEN];
2552	struct stat st;
2553	int count, len, fd;
2554	char *cp;
2555
2556	cp = strrchr(local, '/');
2557	if (cp)
2558		*cp = '\0';
2559	if (stat(cp ? local : ".", &st) < 0) {
2560		perror_reply(553, cp ? local : ".");
2561		return (-1);
2562	}
2563	if (cp)
2564		*cp = '/';
2565	len = strlcpy(new, local, sizeof(new));
2566	if (len+2+1 >= sizeof(new)-1)
2567		return (-1);
2568	cp = new + len;
2569	*cp++ = '.';
2570	for (count = 1; count < 100; count++) {
2571		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2572		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2573		if (fd == -1)
2574			continue;
2575		if (nam)
2576			*nam = new;
2577		return (fd);
2578	}
2579	reply(452, "Unique file name cannot be created.");
2580	return (-1);
2581}
2582
2583/*
2584 * Format and send reply containing system error number.
2585 */
2586void
2587perror_reply(code, string)
2588	int code;
2589	char *string;
2590{
2591
2592	reply(code, "%s: %s.", string, strerror(errno));
2593}
2594
2595static char *onefile[] = {
2596	"",
2597	0
2598};
2599
2600void
2601send_file_list(whichf)
2602	char *whichf;
2603{
2604	struct stat st;
2605	DIR *dirp = NULL;
2606	struct dirent *dir;
2607	FILE *dout = NULL;
2608	char **dirlist;
2609	char *dirname;
2610	int simple = 0;
2611	volatile int freeglob = 0;
2612	glob_t gl;
2613
2614	if (strpbrk(whichf, "~{[*?") != NULL) {
2615		memset(&gl, 0, sizeof(gl));
2616		freeglob = 1;
2617		if (glob(whichf,
2618		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2619		    0, &gl)) {
2620			reply(550, "not found");
2621			goto out;
2622		} else if (gl.gl_pathc == 0) {
2623			errno = ENOENT;
2624			perror_reply(550, whichf);
2625			goto out;
2626		}
2627		dirlist = gl.gl_pathv;
2628	} else {
2629		onefile[0] = whichf;
2630		dirlist = onefile;
2631		simple = 1;
2632	}
2633
2634	while ((dirname = *dirlist++)) {
2635		if (stat(dirname, &st) < 0) {
2636			/*
2637			 * If user typed "ls -l", etc, and the client
2638			 * used NLST, do what the user meant.
2639			 */
2640			if (dirname[0] == '-' && *dirlist == NULL &&
2641			    transflag == 0) {
2642				retrieve("/bin/ls %s", dirname);
2643				goto out;
2644			}
2645			perror_reply(550, whichf);
2646			if (dout != NULL) {
2647				(void) fclose(dout);
2648				transflag = 0;
2649				data = -1;
2650				pdata = -1;
2651			}
2652			goto out;
2653		}
2654
2655		if (S_ISREG(st.st_mode)) {
2656			if (dout == NULL) {
2657				dout = dataconn("file list", (off_t)-1, "w");
2658				if (dout == NULL)
2659					goto out;
2660				transflag++;
2661			}
2662			fprintf(dout, "%s%s\n", dirname,
2663				type == TYPE_A ? "\r" : "");
2664			byte_count += strlen(dirname) + 1;
2665			continue;
2666		} else if (!S_ISDIR(st.st_mode))
2667			continue;
2668
2669		if ((dirp = opendir(dirname)) == NULL)
2670			continue;
2671
2672		while ((dir = readdir(dirp)) != NULL) {
2673			char nbuf[MAXPATHLEN];
2674
2675			if (recvurg) {
2676				myoob();
2677				recvurg = 0;
2678				transflag = 0;
2679				goto out;
2680			}
2681
2682			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2683				continue;
2684			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2685			    dir->d_namlen == 2)
2686				continue;
2687
2688			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2689				 dir->d_name);
2690
2691			/*
2692			 * We have to do a stat to insure it's
2693			 * not a directory or special file.
2694			 */
2695			if (simple || (stat(nbuf, &st) == 0 &&
2696			    S_ISREG(st.st_mode))) {
2697				if (dout == NULL) {
2698					dout = dataconn("file list", (off_t)-1,
2699						"w");
2700					if (dout == NULL)
2701						goto out;
2702					transflag++;
2703				}
2704				if (nbuf[0] == '.' && nbuf[1] == '/')
2705					fprintf(dout, "%s%s\n", &nbuf[2],
2706						type == TYPE_A ? "\r" : "");
2707				else
2708					fprintf(dout, "%s%s\n", nbuf,
2709						type == TYPE_A ? "\r" : "");
2710				byte_count += strlen(nbuf) + 1;
2711			}
2712		}
2713		(void) closedir(dirp);
2714	}
2715
2716	if (dout == NULL)
2717		reply(550, "No files found.");
2718	else if (ferror(dout) != 0)
2719		perror_reply(550, "Data connection");
2720	else
2721		reply(226, "Transfer complete.");
2722
2723	transflag = 0;
2724	if (dout != NULL)
2725		(void) fclose(dout);
2726	else {
2727		if (pdata >= 0)
2728			close(pdata);
2729	}
2730	data = -1;
2731	pdata = -1;
2732out:
2733	if (freeglob) {
2734		freeglob = 0;
2735		globfree(&gl);
2736	}
2737}
2738
2739static void
2740reapchild(signo)
2741	int signo;
2742{
2743	int save_errno = errno;
2744	int rval;
2745
2746	do {
2747		rval = waitpid(-1, NULL, WNOHANG);
2748	} while (rval > 0 || (rval == -1 && errno == EINTR));
2749	errno = save_errno;
2750}
2751
2752void
2753logxfer(name, size, start)
2754	char *name;
2755	off_t size;
2756	time_t start;
2757{
2758	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2759	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2760	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2761	char *vpw;
2762	time_t now;
2763	int len;
2764
2765	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2766		time(&now);
2767
2768		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2769		if (vpw == NULL)
2770			return;
2771
2772		snprintf(path, sizeof(path), "%s/%s", dir, name);
2773		if (realpath(path, rpath) == NULL)
2774			strlcpy(rpath, path, sizeof(rpath));
2775		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2776
2777		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2778		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2779
2780		len = snprintf(buf, sizeof(buf),
2781		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2782		    ctime(&now), now - start + (now == start),
2783		    vremotehost, (long long) size, vpath,
2784		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2785		    'o', ((guest) ? 'a' : 'r'),
2786		    vpw, 0 /* none yet */,
2787		    ((guest) ? "*" : pw->pw_name), dhostname);
2788		if (len >= sizeof(buf)) {
2789			len = sizeof(buf);
2790			buf[sizeof(buf) - 1] = '\n';
2791		}
2792		write(statfd, buf, len);
2793		free(vpw);
2794	}
2795}
2796
2797#if defined(TCPWRAPPERS)
2798static int
2799check_host(sa)
2800	struct sockaddr *sa;
2801{
2802	struct sockaddr_in *sin;
2803	struct hostent *hp;
2804	char *addr;
2805
2806	if (sa->sa_family != AF_INET)
2807		return 1;	/*XXX*/
2808
2809	sin = (struct sockaddr_in *)sa;
2810	hp = gethostbyaddr((char *)&sin->sin_addr,
2811	    sizeof(struct in_addr), AF_INET);
2812	addr = inet_ntoa(sin->sin_addr);
2813	if (hp) {
2814		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2815			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2816			    hp->h_name, addr);
2817			return (0);
2818		}
2819	} else {
2820		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2821			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2822			return (0);
2823		}
2824	}
2825	return (1);
2826}
2827#endif	/* TCPWRAPPERS */
2828
2829/*
2830 * Allocate space and return a copy of the specified dir.
2831 * If 'dir' begins with a tilde (~), expand it.
2832 */
2833char *
2834copy_dir(dir, pw)
2835	char *dir;
2836	struct passwd *pw;
2837{
2838	char *cp;
2839	char *newdir;
2840	char *user = NULL;
2841	size_t dirsiz;
2842
2843	/* Nothing to expand */
2844	if (dir[0] !=  '~')
2845		return (strdup(dir));
2846
2847	/* "dir" is of form ~user/some/dir, lookup user. */
2848	if (dir[1] != '/' && dir[1] != '\0') {
2849		if ((cp = strchr(dir + 1, '/')) == NULL)
2850		    cp = dir + strlen(dir);
2851		if ((user = malloc(cp - dir)) == NULL)
2852			return (NULL);
2853		strlcpy(user, dir + 1, cp - dir);
2854
2855		/* Only do lookup if it is a different user. */
2856		if (strcmp(user, pw->pw_name) != 0) {
2857			if ((pw = getpwnam(user)) == NULL) {
2858				/* No such user, interpret literally */
2859				free(user);
2860				return(strdup(dir));
2861			}
2862		}
2863	}
2864
2865	/*
2866	 * If there is no directory separator (/) then it is just pw_dir.
2867	 * Otherwise, replace ~foo with  pw_dir.
2868	 */
2869	if ((cp = strchr(dir + 1, '/')) == NULL) {
2870		newdir = strdup(pw->pw_dir);
2871	} else {
2872		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2873		if ((newdir = malloc(dirsiz)) == NULL) {
2874			free(user);
2875			return (NULL);
2876		}
2877		strlcpy(newdir, pw->pw_dir, dirsiz);
2878		strlcat(newdir, cp, dirsiz);
2879	}
2880
2881	if (user)
2882		free(user);
2883	return(newdir);
2884}
2885