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