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