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