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