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