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