ftpd.c revision 1.79
1/*	$OpenBSD: ftpd.c,v 1.79 2000/09/15 07:13:45 deraadt Exp $	*/
2/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 *    must display the following acknowledgement:
47 *	This product includes software developed by the University of
48 *	California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66#ifndef lint
67static char copyright[] =
68"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
69	The Regents of the University of California.  All rights reserved.\n";
70#endif /* not lint */
71
72#ifndef lint
73#if 0
74static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
75#else
76static char rcsid[] = "$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 027
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	setusercontext(NULL, getpwuid(0), (uid_t)0,
842	    LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
843	logged_in = 0;
844	guest = 0;
845	dochroot = 0;
846}
847
848void
849pass(passwd)
850	char *passwd;
851{
852	int rval;
853	FILE *fp;
854	static char homedir[MAXPATHLEN];
855	char *dir, rootdir[MAXPATHLEN];
856	sigset_t allsigs;
857
858	if (logged_in || askpasswd == 0) {
859		reply(503, "Login with USER first.");
860		return;
861	}
862	askpasswd = 0;
863	if (!guest) {		/* "ftp" is only account allowed no password */
864		if (pw == NULL) {
865			useconds_t us;
866
867			/* Sleep between 1 and 3 seconds to emulate a crypt. */
868			us = arc4random() % 3000000;
869			usleep(us);
870			rval = 1;	/* failure below */
871			goto skip;
872		}
873#if defined(KERBEROS)
874		rval = klogin(pw, "", hostname, passwd);
875		if (rval == 0)
876			goto skip;
877#endif
878#ifdef SKEY
879		if (skey_haskey(pw->pw_name) == 0 &&
880		   (skey_passcheck(pw->pw_name, passwd) != -1)) {
881			rval = 0;
882			goto skip;
883		}
884#endif
885		/* the strcmp does not catch null passwords! */
886		if (strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) ||
887		    *pw->pw_passwd == '\0') {
888			rval = 1;	 /* failure */
889			goto skip;
890		}
891		rval = 0;
892
893skip:
894		/*
895		 * If rval == 1, the user failed the authentication check
896		 * above.  If rval == 0, either Kerberos or local authentication
897		 * succeeded.
898		 */
899		if (rval) {
900			reply(530, "Login incorrect.");
901			if (logging)
902				syslog(LOG_NOTICE,
903				    "FTP LOGIN FAILED FROM %s, %s",
904				    remotehost, curname);
905			pw = NULL;
906			if (login_attempts++ >= 5) {
907				syslog(LOG_NOTICE,
908				    "repeated login failures from %s",
909				    remotehost);
910				exit(0);
911			}
912			return;
913		}
914	} else {
915		/* Save anonymous' password. */
916		guestpw = strdup(passwd);
917		if (guestpw == (char *)NULL)
918			fatal("Out of memory");
919	}
920	login_attempts = 0;		/* this time successful */
921	if (setegid((gid_t)pw->pw_gid) < 0) {
922		reply(550, "Can't set gid.");
923		return;
924	}
925	(void) umask(defumask);		/* may be overridden by login.conf */
926	setusercontext(lc, pw, (uid_t)0,
927	    LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
928
929	/* open wtmp before chroot */
930	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
931
932	/* open utmp before chroot */
933	if (doutmp) {
934		memset((void *)&utmp, 0, sizeof(utmp));
935		(void)time(&utmp.ut_time);
936		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
937		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
938		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
939		login(&utmp);
940	}
941
942	/* open stats file before chroot */
943	if (guest && (stats == 1) && (statfd < 0))
944		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
945			stats = 0;
946
947	logged_in = 1;
948
949	dochroot = login_getcapbool(lc, "ftp-chroot", 0) ||
950	    checkuser(_PATH_FTPCHROOT, pw->pw_name);
951	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
952		free(pw->pw_dir);
953		pw->pw_dir = sgetsave(dir);
954	}
955	if (guest || dochroot) {
956		if (multihome && guest) {
957			struct stat ts;
958
959			/* Compute root directory. */
960			snprintf(rootdir, sizeof(rootdir), "%s/%s",
961				  pw->pw_dir, dhostname);
962			if (stat(rootdir, &ts) < 0) {
963				snprintf(rootdir, sizeof(rootdir), "%s/%s",
964					  pw->pw_dir, hostname);
965			}
966		} else
967			strcpy(rootdir, pw->pw_dir);
968	}
969	if (guest) {
970		/*
971		 * We MUST do a chdir() after the chroot. Otherwise
972		 * the old current directory will be accessible as "."
973		 * outside the new root!
974		 */
975		if (chroot(rootdir) < 0 || chdir("/") < 0) {
976			reply(550, "Can't set guest privileges.");
977			goto bad;
978		}
979		strcpy(pw->pw_dir, "/");
980		if (setenv("HOME", "/", 1) == -1) {
981			reply(550, "Can't setup environment.");
982			goto bad;
983		}
984	} else if (dochroot) {
985		if (chroot(rootdir) < 0 || chdir("/") < 0) {
986			reply(550, "Can't change root.");
987			goto bad;
988		}
989		strcpy(pw->pw_dir, "/");
990		if (setenv("HOME", "/", 1) == -1) {
991			reply(550, "Can't setup environment.");
992			goto bad;
993		}
994	} else if (chdir(pw->pw_dir) < 0) {
995		if (chdir("/") < 0) {
996			reply(530, "User %s: can't change directory to %s.",
997			    pw->pw_name, pw->pw_dir);
998			goto bad;
999		} else
1000			lreply(230, "No directory! Logging in with home=/");
1001	}
1002	if (seteuid((uid_t)pw->pw_uid) < 0) {
1003		reply(550, "Can't set uid.");
1004		goto bad;
1005	}
1006	sigfillset(&allsigs);
1007	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1008
1009	/*
1010	 * Set home directory so that use of ~ (tilde) works correctly.
1011	 */
1012	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1013		if (setenv("HOME", homedir, 1) == -1) {
1014			reply(550, "Can't setup environment.");
1015			goto bad;
1016		}
1017	}
1018
1019	/*
1020	 * Display a login message, if it exists.
1021	 * N.B. reply(230,) must follow the message.
1022	 */
1023	if ((fp = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
1024		char *cp, line[LINE_MAX];
1025
1026		while (fgets(line, sizeof(line), fp) != NULL) {
1027			if ((cp = strchr(line, '\n')) != NULL)
1028				*cp = '\0';
1029			lreply(230, "%s", line);
1030		}
1031		(void) fflush(stdout);
1032		(void) fclose(fp);
1033	}
1034	if (guest) {
1035		if (ident != NULL)
1036			free(ident);
1037		ident = strdup(passwd);
1038		if (ident == NULL)
1039			fatal("Ran out of memory.");
1040		reply(230, "Guest login ok, access restrictions apply.");
1041#ifdef HASSETPROCTITLE
1042		snprintf(proctitle, sizeof(proctitle),
1043		    "%s: anonymous/%.*s", remotehost,
1044		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1045		    sizeof(": anonymous/")), passwd);
1046		setproctitle("%s", proctitle);
1047#endif /* HASSETPROCTITLE */
1048		if (logging)
1049			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1050			    remotehost, passwd);
1051	} else {
1052		reply(230, "User %s logged in.", pw->pw_name);
1053#ifdef HASSETPROCTITLE
1054		snprintf(proctitle, sizeof(proctitle),
1055		    "%s: %s", remotehost, pw->pw_name);
1056		setproctitle("%s", proctitle);
1057#endif /* HASSETPROCTITLE */
1058		if (logging)
1059			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1060			    remotehost, pw->pw_name);
1061	}
1062	login_close(lc);
1063	lc = NULL;
1064	return;
1065bad:
1066	/* Forget all about it... */
1067	login_close(lc);
1068	lc = NULL;
1069	end_login();
1070}
1071
1072void
1073retrieve(cmd, name)
1074	char *cmd, *name;
1075{
1076	FILE *fin, *dout;
1077	struct stat st;
1078	int (*closefunc) __P((FILE *));
1079	time_t start;
1080
1081	if (cmd == 0) {
1082		fin = fopen(name, "r"), closefunc = fclose;
1083		st.st_size = 0;
1084	} else {
1085		char line[BUFSIZ];
1086
1087		(void) snprintf(line, sizeof(line), cmd, name);
1088		name = line;
1089		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1090		st.st_size = -1;
1091		st.st_blksize = BUFSIZ;
1092	}
1093	if (fin == NULL) {
1094		if (errno != 0) {
1095			perror_reply(550, name);
1096			if (cmd == 0) {
1097				LOGCMD("get", name);
1098			}
1099		}
1100		return;
1101	}
1102	byte_count = -1;
1103	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1104		reply(550, "%s: not a plain file.", name);
1105		goto done;
1106	}
1107	if (restart_point) {
1108		if (type == TYPE_A) {
1109			off_t i, n;
1110			int c;
1111
1112			n = restart_point;
1113			i = 0;
1114			while (i++ < n) {
1115				if ((c=getc(fin)) == EOF) {
1116					perror_reply(550, name);
1117					goto done;
1118				}
1119				if (c == '\n')
1120					i++;
1121			}
1122		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1123			perror_reply(550, name);
1124			goto done;
1125		}
1126	}
1127	dout = dataconn(name, st.st_size, "w");
1128	if (dout == NULL)
1129		goto done;
1130	time(&start);
1131	send_data(fin, dout, st.st_blksize, st.st_size,
1132		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1133	if ((cmd == 0) && stats)
1134		logxfer(name, st.st_size, start);
1135	(void) fclose(dout);
1136	data = -1;
1137done:
1138	if (pdata >= 0)
1139		(void) close(pdata);
1140	pdata = -1;
1141	if (cmd == 0)
1142		LOGBYTES("get", name, byte_count);
1143	(*closefunc)(fin);
1144}
1145
1146void
1147store(name, mode, unique)
1148	char *name, *mode;
1149	int unique;
1150{
1151	FILE *fout, *din;
1152	int (*closefunc) __P((FILE *));
1153	struct stat st;
1154	int fd;
1155
1156	if (restart_point && *mode != 'a')
1157		mode = "r+";
1158
1159	if (unique && stat(name, &st) == 0) {
1160		char *nam;
1161
1162		fd = guniquefd(name, &nam);
1163		if (fd == -1) {
1164			LOGCMD(*mode == 'w' ? "put" : "append", name);
1165			return;
1166		}
1167		name = nam;
1168		fout = fdopen(fd, mode);
1169	} else
1170		fout = fopen(name, mode);
1171
1172	closefunc = fclose;
1173	if (fout == NULL) {
1174		perror_reply(553, name);
1175		LOGCMD(*mode == 'w' ? "put" : "append", name);
1176		return;
1177	}
1178	byte_count = -1;
1179	if (restart_point) {
1180		if (type == TYPE_A) {
1181			off_t i, n;
1182			int c;
1183
1184			n = restart_point;
1185			i = 0;
1186			while (i++ < n) {
1187				if ((c=getc(fout)) == EOF) {
1188					perror_reply(550, name);
1189					goto done;
1190				}
1191				if (c == '\n')
1192					i++;
1193			}
1194			/*
1195			 * We must do this seek to "current" position
1196			 * because we are changing from reading to
1197			 * writing.
1198			 */
1199			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1200				perror_reply(550, name);
1201				goto done;
1202			}
1203		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1204			perror_reply(550, name);
1205			goto done;
1206		}
1207	}
1208	din = dataconn(name, (off_t)-1, "r");
1209	if (din == NULL)
1210		goto done;
1211	if (receive_data(din, fout) == 0) {
1212		if (unique)
1213			reply(226, "Transfer complete (unique file name:%s).",
1214			    name);
1215		else
1216			reply(226, "Transfer complete.");
1217	}
1218	(void) fclose(din);
1219	data = -1;
1220	pdata = -1;
1221done:
1222	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1223	(*closefunc)(fout);
1224}
1225
1226static FILE *
1227getdatasock(mode)
1228	char *mode;
1229{
1230	int on = 1, s, t, tries;
1231	sigset_t allsigs;
1232
1233	if (data >= 0)
1234		return (fdopen(data, mode));
1235	sigfillset(&allsigs);
1236	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1237	(void) seteuid((uid_t)0);
1238	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1239	if (s < 0)
1240		goto bad;
1241	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1242	    (char *) &on, sizeof(on)) < 0)
1243		goto bad;
1244	/* anchor socket to avoid multi-homing problems */
1245	data_source = ctrl_addr;
1246	data_source.su_port = htons(20); /* ftp-data port */
1247	for (tries = 1; ; tries++) {
1248		if (bind(s, (struct sockaddr *)&data_source,
1249		    data_source.su_len) >= 0)
1250			break;
1251		if (errno != EADDRINUSE || tries > 10)
1252			goto bad;
1253		sleep(tries);
1254	}
1255	(void) seteuid((uid_t)pw->pw_uid);
1256	sigfillset(&allsigs);
1257	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1258
1259#ifdef IP_TOS
1260	if (ctrl_addr.su_family == AF_INET) {
1261		on = IPTOS_THROUGHPUT;
1262		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1263		    sizeof(int)) < 0)
1264			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1265	}
1266#endif
1267#ifdef TCP_NOPUSH
1268	/*
1269	 * Turn off push flag to keep sender TCP from sending short packets
1270	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1271	 * to set the send buffer size as well, but that may not be desirable
1272	 * in heavy-load situations.
1273	 */
1274	on = 1;
1275	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1276		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1277#endif
1278#ifdef SO_SNDBUF
1279	on = 65536;
1280	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1281		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1282#endif
1283
1284	return (fdopen(s, mode));
1285bad:
1286	/* Return the real value of errno (close may change it) */
1287	t = errno;
1288	(void) seteuid((uid_t)pw->pw_uid);
1289	sigfillset (&allsigs);
1290	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1291	(void) close(s);
1292	errno = t;
1293	return (NULL);
1294}
1295
1296static FILE *
1297dataconn(name, size, mode)
1298	char *name;
1299	off_t size;
1300	char *mode;
1301{
1302	char sizebuf[32];
1303	FILE *file;
1304	int retry = 0;
1305	in_port_t *p;
1306	char *fa, *ha;
1307	int alen;
1308
1309	file_size = size;
1310	byte_count = 0;
1311	if (size != (off_t) -1) {
1312		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1313				size);
1314	} else
1315		sizebuf[0] = '\0';
1316	if (pdata >= 0) {
1317		union sockunion from;
1318		int s, fromlen = sizeof(from);
1319
1320		signal (SIGALRM, toolong);
1321		(void) alarm ((unsigned) timeout);
1322		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1323		(void) alarm (0);
1324		if (s < 0) {
1325			reply(425, "Can't open data connection.");
1326			(void) close(pdata);
1327			pdata = -1;
1328			return (NULL);
1329		}
1330		switch (from.su_family) {
1331		case AF_INET:
1332			p = (in_port_t *)&from.su_sin.sin_port;
1333			fa = (u_char *)&from.su_sin.sin_addr;
1334			ha = (u_char *)&his_addr.su_sin.sin_addr;
1335			alen = sizeof(struct in_addr);
1336			break;
1337		case AF_INET6:
1338			p = (in_port_t *)&from.su_sin6.sin6_port;
1339			fa = (u_char *)&from.su_sin6.sin6_addr;
1340			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1341			alen = sizeof(struct in6_addr);
1342			break;
1343		default:
1344			perror_reply(425, "Can't build data connection");
1345			(void) close(pdata);
1346			(void) close(s);
1347			pdata = -1;
1348			return (NULL);
1349		}
1350		if (from.su_family != his_addr.su_family ||
1351		    ntohs(*p) < IPPORT_RESERVED) {
1352			perror_reply(425, "Can't build data connection");
1353			(void) close(pdata);
1354			(void) close(s);
1355			pdata = -1;
1356			return (NULL);
1357		}
1358		if (memcmp(fa, ha, alen) != 0) {
1359			perror_reply(435, "Can't build data connection");
1360			(void) close(pdata);
1361			(void) close(s);
1362			pdata = -1;
1363			return (NULL);
1364		}
1365		(void) close(pdata);
1366		pdata = s;
1367		reply(150, "Opening %s mode data connection for '%s'%s.",
1368		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1369		return (fdopen(pdata, mode));
1370	}
1371	if (data >= 0) {
1372		reply(125, "Using existing data connection for '%s'%s.",
1373		    name, sizebuf);
1374		usedefault = 1;
1375		return (fdopen(data, mode));
1376	}
1377	if (usedefault)
1378		data_dest = his_addr;
1379	usedefault = 1;
1380	file = getdatasock(mode);
1381	if (file == NULL) {
1382		char hbuf[MAXHOSTNAMELEN], pbuf[10];
1383
1384		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1385		    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1386		    NI_NUMERICHOST | NI_NUMERICSERV);
1387		reply(425, "Can't create data socket (%s,%s): %s.",
1388		    hbuf, pbuf, strerror(errno));
1389		return (NULL);
1390	}
1391	data = fileno(file);
1392
1393	/*
1394	 * attempt to connect to reserved port on client machine;
1395	 * this looks like an attack
1396	 */
1397	switch (data_dest.su_family) {
1398	case AF_INET:
1399		p = (in_port_t *)&data_dest.su_sin.sin_port;
1400		fa = (u_char *)&data_dest.su_sin.sin_addr;
1401		ha = (u_char *)&his_addr.su_sin.sin_addr;
1402		alen = sizeof(struct in_addr);
1403		break;
1404	case AF_INET6:
1405		p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1406		fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1407		ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1408		alen = sizeof(struct in6_addr);
1409		break;
1410	default:
1411		perror_reply(425, "Can't build data connection");
1412		(void) fclose(file);
1413		pdata = -1;
1414		return (NULL);
1415	}
1416	if (data_dest.su_family != his_addr.su_family ||
1417	    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) {	/* XXX */
1418		perror_reply(425, "Can't build data connection");
1419		(void) fclose(file);
1420		data = -1;
1421		return NULL;
1422	}
1423	if (memcmp(fa, ha, alen) != 0) {
1424		perror_reply(435, "Can't build data connection");
1425		(void) fclose(file);
1426		data = -1;
1427		return NULL;
1428	}
1429	while (connect(data, (struct sockaddr *)&data_dest,
1430	    data_dest.su_len) < 0) {
1431		if (errno == EADDRINUSE && retry < swaitmax) {
1432			sleep((unsigned) swaitint);
1433			retry += swaitint;
1434			continue;
1435		}
1436		perror_reply(425, "Can't build data connection");
1437		(void) fclose(file);
1438		data = -1;
1439		return (NULL);
1440	}
1441	reply(150, "Opening %s mode data connection for '%s'%s.",
1442	    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1443	return (file);
1444}
1445
1446/*
1447 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1448 * encapsulation of the data subject to Mode, Structure, and Type.
1449 *
1450 * NB: Form isn't handled.
1451 */
1452static void
1453send_data(instr, outstr, blksize, filesize, isreg)
1454	FILE *instr, *outstr;
1455	off_t blksize;
1456	off_t filesize;
1457	int isreg;
1458{
1459	int c, cnt, filefd, netfd;
1460	char *buf, *bp;
1461	size_t len;
1462
1463	transflag++;
1464	if (setjmp(urgcatch)) {
1465		transflag = 0;
1466		return;
1467	}
1468	switch (type) {
1469
1470	case TYPE_A:
1471		while ((c = getc(instr)) != EOF) {
1472			byte_count++;
1473			if (c == '\n') {
1474				if (ferror(outstr))
1475					goto data_err;
1476				(void) putc('\r', outstr);
1477			}
1478			(void) putc(c, outstr);
1479		}
1480		fflush(outstr);
1481		transflag = 0;
1482		if (ferror(instr))
1483			goto file_err;
1484		if (ferror(outstr))
1485			goto data_err;
1486		reply(226, "Transfer complete.");
1487		return;
1488
1489	case TYPE_I:
1490	case TYPE_L:
1491		/*
1492		 * isreg is only set if we are not doing restart and we
1493		 * are sending a regular file
1494		 */
1495		netfd = fileno(outstr);
1496		filefd = fileno(instr);
1497
1498		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1499			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1500				   (off_t)0);
1501			if (!buf) {
1502				syslog(LOG_WARNING, "mmap(%lu): %m",
1503				    (unsigned long)filesize);
1504				goto oldway;
1505			}
1506			bp = buf;
1507			len = filesize;
1508			do {
1509				cnt = write(netfd, bp, len);
1510				len -= cnt;
1511				bp += cnt;
1512				if (cnt > 0) byte_count += cnt;
1513			} while(cnt > 0 && len > 0);
1514
1515			transflag = 0;
1516			munmap(buf, (size_t)filesize);
1517			if (cnt < 0)
1518				goto data_err;
1519			reply(226, "Transfer complete.");
1520			return;
1521		}
1522
1523oldway:
1524		if ((buf = malloc((u_int)blksize)) == NULL) {
1525			transflag = 0;
1526			perror_reply(451, "Local resource failure: malloc");
1527			return;
1528		}
1529
1530		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1531		    write(netfd, buf, cnt) == cnt)
1532			byte_count += cnt;
1533		transflag = 0;
1534		(void)free(buf);
1535		if (cnt != 0) {
1536			if (cnt < 0)
1537				goto file_err;
1538			goto data_err;
1539		}
1540		reply(226, "Transfer complete.");
1541		return;
1542	default:
1543		transflag = 0;
1544		reply(550, "Unimplemented TYPE %d in send_data", type);
1545		return;
1546	}
1547
1548data_err:
1549	transflag = 0;
1550	perror_reply(426, "Data connection");
1551	return;
1552
1553file_err:
1554	transflag = 0;
1555	perror_reply(551, "Error on input file");
1556}
1557
1558/*
1559 * Transfer data from peer to "outstr" using the appropriate encapulation of
1560 * the data subject to Mode, Structure, and Type.
1561 *
1562 * N.B.: Form isn't handled.
1563 */
1564static int
1565receive_data(instr, outstr)
1566	FILE *instr, *outstr;
1567{
1568	int c;
1569	int cnt, bare_lfs = 0;
1570	char buf[BUFSIZ];
1571
1572	transflag++;
1573	if (setjmp(urgcatch)) {
1574		transflag = 0;
1575		return (-1);
1576	}
1577	switch (type) {
1578
1579	case TYPE_I:
1580	case TYPE_L:
1581		signal (SIGALRM, lostconn);
1582
1583		do {
1584			(void) alarm ((unsigned) timeout);
1585			cnt = read(fileno(instr), buf, sizeof(buf));
1586			(void) alarm (0);
1587
1588			if (cnt > 0) {
1589				if (write(fileno(outstr), buf, cnt) != cnt)
1590					goto file_err;
1591				byte_count += cnt;
1592			}
1593		} while (cnt > 0);
1594		if (cnt < 0)
1595			goto data_err;
1596		transflag = 0;
1597		return (0);
1598
1599	case TYPE_E:
1600		reply(553, "TYPE E not implemented.");
1601		transflag = 0;
1602		return (-1);
1603
1604	case TYPE_A:
1605		while ((c = getc(instr)) != EOF) {
1606			byte_count++;
1607			if (c == '\n')
1608				bare_lfs++;
1609			while (c == '\r') {
1610				if (ferror(outstr))
1611					goto data_err;
1612				if ((c = getc(instr)) != '\n') {
1613					(void) putc ('\r', outstr);
1614					if (c == '\0' || c == EOF)
1615						goto contin2;
1616				}
1617			}
1618			(void) putc(c, outstr);
1619	contin2:	;
1620		}
1621		fflush(outstr);
1622		if (ferror(instr))
1623			goto data_err;
1624		if (ferror(outstr))
1625			goto file_err;
1626		transflag = 0;
1627		if (bare_lfs) {
1628			lreply(226,
1629			    "WARNING! %d bare linefeeds received in ASCII mode",
1630			    bare_lfs);
1631			printf("   File may not have transferred correctly.\r\n");
1632		}
1633		return (0);
1634	default:
1635		reply(550, "Unimplemented TYPE %d in receive_data", type);
1636		transflag = 0;
1637		return (-1);
1638	}
1639
1640data_err:
1641	transflag = 0;
1642	perror_reply(426, "Data Connection");
1643	return (-1);
1644
1645file_err:
1646	transflag = 0;
1647	perror_reply(452, "Error writing file");
1648	return (-1);
1649}
1650
1651void
1652statfilecmd(filename)
1653	char *filename;
1654{
1655	FILE *fin;
1656	int c;
1657	int atstart;
1658	char line[LINE_MAX];
1659
1660	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1661	fin = ftpd_popen(line, "r");
1662	lreply(211, "status of %s:", filename);
1663	atstart = 1;
1664	while ((c = getc(fin)) != EOF) {
1665		if (c == '\n') {
1666			if (ferror(stdout)){
1667				perror_reply(421, "control connection");
1668				(void) ftpd_pclose(fin);
1669				dologout(1);
1670				/* NOTREACHED */
1671			}
1672			if (ferror(fin)) {
1673				perror_reply(551, filename);
1674				(void) ftpd_pclose(fin);
1675				return;
1676			}
1677			(void) putc('\r', stdout);
1678		}
1679		if (atstart && isdigit(c))
1680			(void) putc(' ', stdout);
1681		(void) putc(c, stdout);
1682		atstart = (c == '\n');
1683	}
1684	(void) ftpd_pclose(fin);
1685	reply(211, "End of Status");
1686}
1687
1688void
1689statcmd()
1690{
1691	union sockunion *su;
1692	u_char *a, *p;
1693	char hbuf[MAXHOSTNAMELEN];
1694	int ispassive;
1695
1696	lreply(211, "%s FTP server status:", hostname, version);
1697	printf("     %s\r\n", version);
1698	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1699	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1700	printf("     Connected to %s", remotehost);
1701	if (strcmp(remotehost, hbuf) != 0)
1702		printf(" (%s)", hbuf);
1703	printf("\r\n");
1704	if (logged_in) {
1705		if (guest)
1706			printf("     Logged in anonymously\r\n");
1707		else
1708			printf("     Logged in as %s\r\n", pw->pw_name);
1709	} else if (askpasswd)
1710		printf("     Waiting for password\r\n");
1711	else
1712		printf("     Waiting for user name\r\n");
1713	printf("     TYPE: %s", typenames[type]);
1714	if (type == TYPE_A || type == TYPE_E)
1715		printf(", FORM: %s", formnames[form]);
1716	if (type == TYPE_L)
1717#if NBBY == 8
1718		printf(" %d", NBBY);
1719#else
1720		printf(" %d", bytesize);	/* need definition! */
1721#endif
1722	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1723	    strunames[stru], modenames[mode]);
1724	ispassive = 0;
1725	if (data != -1)
1726		printf("     Data connection open\r\n");
1727	else if (pdata != -1) {
1728		printf("     in Passive mode\r\n");
1729		su = (union sockunion *)&pasv_addr;
1730		ispassive++;
1731		goto printaddr;
1732	} else if (usedefault == 0) {
1733		su = (union sockunion *)&data_dest;
1734printaddr:
1735		/* PASV/PORT */
1736		if (su->su_family == AF_INET) {
1737			if (ispassive)
1738				printf("211- PASV ");
1739			else
1740				printf("211- PORT ");
1741			a = (u_char *) &su->su_sin.sin_addr;
1742			p = (u_char *) &su->su_sin.sin_port;
1743			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1744			    a[0], a[1], a[2], a[3],
1745			    p[0], p[1]);
1746		}
1747
1748		/* LPSV/LPRT */
1749	    {
1750		int alen, af, i;
1751
1752		alen = 0;
1753		switch (su->su_family) {
1754		case AF_INET:
1755			a = (u_char *) &su->su_sin.sin_addr;
1756			p = (u_char *) &su->su_sin.sin_port;
1757			alen = sizeof(su->su_sin.sin_addr);
1758			af = 4;
1759			break;
1760		case AF_INET6:
1761			a = (u_char *) &su->su_sin6.sin6_addr;
1762			p = (u_char *) &su->su_sin6.sin6_port;
1763			alen = sizeof(su->su_sin6.sin6_addr);
1764			af = 6;
1765			break;
1766		default:
1767			af = 0;
1768			break;
1769		}
1770		if (af) {
1771			if (ispassive)
1772				printf("211- LPSV ");
1773			else
1774				printf("211- LPRT ");
1775			printf("(%u,%u", af, alen);
1776			for (i = 0; i < alen; i++)
1777				printf(",%u", a[i]);
1778			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1779		}
1780	    }
1781
1782		/* EPRT/EPSV */
1783epsvonly:
1784	    {
1785		u_char af;
1786
1787		switch (su->su_family) {
1788		case AF_INET:
1789			af = 1;
1790			break;
1791		case AF_INET6:
1792			af = 2;
1793			break;
1794		default:
1795			af = 0;
1796			break;
1797		}
1798		if (af) {
1799			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1800			if (getnameinfo((struct sockaddr *)su, su->su_len,
1801			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1802			    NI_NUMERICHOST) == 0) {
1803				if (ispassive)
1804					printf("211- EPSV ");
1805				else
1806					printf("211- EPRT ");
1807				printf("(|%u|%s|%s|)\r\n",
1808					af, hbuf, pbuf);
1809			}
1810		}
1811	    }
1812	} else
1813		printf("     No data connection\r\n");
1814	reply(211, "End of status");
1815}
1816
1817void
1818fatal(s)
1819	char *s;
1820{
1821
1822	reply(451, "Error in server: %s\n", s);
1823	reply(221, "Closing connection due to server error.");
1824	dologout(0);
1825	/* NOTREACHED */
1826}
1827
1828void
1829#ifdef __STDC__
1830reply(int n, const char *fmt, ...)
1831#else
1832reply(n, fmt, va_alist)
1833	int n;
1834	char *fmt;
1835	va_dcl
1836#endif
1837{
1838	va_list ap;
1839#ifdef __STDC__
1840	va_start(ap, fmt);
1841#else
1842	va_start(ap);
1843#endif
1844	(void)printf("%d ", n);
1845	(void)vprintf(fmt, ap);
1846	(void)printf("\r\n");
1847	(void)fflush(stdout);
1848	if (debug) {
1849		syslog(LOG_DEBUG, "<--- %d ", n);
1850		vsyslog(LOG_DEBUG, fmt, ap);
1851	}
1852}
1853
1854void
1855#ifdef __STDC__
1856lreply(int n, const char *fmt, ...)
1857#else
1858lreply(n, fmt, va_alist)
1859	int n;
1860	char *fmt;
1861	va_dcl
1862#endif
1863{
1864	va_list ap;
1865#ifdef __STDC__
1866	va_start(ap, fmt);
1867#else
1868	va_start(ap);
1869#endif
1870	(void)printf("%d- ", n);
1871	(void)vprintf(fmt, ap);
1872	(void)printf("\r\n");
1873	(void)fflush(stdout);
1874	if (debug) {
1875		syslog(LOG_DEBUG, "<--- %d- ", n);
1876		vsyslog(LOG_DEBUG, fmt, ap);
1877	}
1878}
1879
1880static void
1881ack(s)
1882	char *s;
1883{
1884
1885	reply(250, "%s command successful.", s);
1886}
1887
1888void
1889nack(s)
1890	char *s;
1891{
1892
1893	reply(502, "%s command not implemented.", s);
1894}
1895
1896/* ARGSUSED */
1897void
1898yyerror(s)
1899	char *s;
1900{
1901	char *cp;
1902
1903	if ((cp = strchr(cbuf,'\n')))
1904		*cp = '\0';
1905	reply(500, "'%s': command not understood.", cbuf);
1906}
1907
1908void
1909delete(name)
1910	char *name;
1911{
1912	struct stat st;
1913
1914	LOGCMD("delete", name);
1915	if (stat(name, &st) < 0) {
1916		perror_reply(550, name);
1917		return;
1918	}
1919	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1920		if (rmdir(name) < 0) {
1921			perror_reply(550, name);
1922			return;
1923		}
1924		goto done;
1925	}
1926	if (unlink(name) < 0) {
1927		perror_reply(550, name);
1928		return;
1929	}
1930done:
1931	ack("DELE");
1932}
1933
1934void
1935cwd(path)
1936	char *path;
1937{
1938	FILE *message;
1939
1940	if (chdir(path) < 0)
1941		perror_reply(550, path);
1942	else {
1943		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
1944			char *cp, line[LINE_MAX];
1945
1946			while (fgets(line, sizeof(line), message) != NULL) {
1947				if ((cp = strchr(line, '\n')) != NULL)
1948					*cp = '\0';
1949				lreply(250, "%s", line);
1950			}
1951			(void) fflush(stdout);
1952			(void) fclose(message);
1953		}
1954		ack("CWD");
1955	}
1956}
1957
1958void
1959replydirname(name, message)
1960	const char *name, *message;
1961{
1962	char npath[MAXPATHLEN];
1963	int i;
1964
1965	for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
1966		npath[i] = *name;
1967		if (*name == '"')
1968			npath[++i] = '"';
1969	}
1970	npath[i] = '\0';
1971	reply(257, "\"%s\" %s", npath, message);
1972}
1973
1974void
1975makedir(name)
1976	char *name;
1977{
1978
1979	LOGCMD("mkdir", name);
1980	if (mkdir(name, 0777) < 0)
1981		perror_reply(550, name);
1982	else
1983		replydirname(name, "directory created.");
1984}
1985
1986void
1987removedir(name)
1988	char *name;
1989{
1990
1991	LOGCMD("rmdir", name);
1992	if (rmdir(name) < 0)
1993		perror_reply(550, name);
1994	else
1995		ack("RMD");
1996}
1997
1998void
1999pwd()
2000{
2001	char path[MAXPATHLEN];
2002
2003	if (getcwd(path, sizeof path) == (char *)NULL)
2004		reply(550, "Can't get current directory: %s.", strerror(errno));
2005	else
2006		replydirname(path, "is current directory.");
2007}
2008
2009char *
2010renamefrom(name)
2011	char *name;
2012{
2013	struct stat st;
2014
2015	if (stat(name, &st) < 0) {
2016		perror_reply(550, name);
2017		return ((char *)0);
2018	}
2019	reply(350, "File exists, ready for destination name");
2020	return (name);
2021}
2022
2023void
2024renamecmd(from, to)
2025	char *from, *to;
2026{
2027
2028	LOGCMD2("rename", from, to);
2029	if (rename(from, to) < 0)
2030		perror_reply(550, "rename");
2031	else
2032		ack("RNTO");
2033}
2034
2035static void
2036dolog(sa)
2037	struct sockaddr *sa;
2038{
2039	char hbuf[sizeof(remotehost)];
2040
2041	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2042	(void) strncpy(remotehost, hbuf, sizeof(remotehost)-1);
2043
2044	remotehost[sizeof(remotehost)-1] = '\0';
2045#ifdef HASSETPROCTITLE
2046	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2047	setproctitle("%s", proctitle);
2048#endif /* HASSETPROCTITLE */
2049
2050	if (logging)
2051		syslog(LOG_INFO, "connection from %s", remotehost);
2052}
2053
2054/*
2055 * Record logout in wtmp file
2056 * and exit with supplied status.
2057 */
2058void
2059dologout(status)
2060	int status;
2061{
2062	sigset_t allsigs;
2063
2064	transflag = 0;
2065
2066	if (logged_in) {
2067		sigfillset(&allsigs);
2068		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2069		(void) seteuid((uid_t)0);
2070		ftpdlogwtmp(ttyline, "", "");
2071		if (doutmp)
2072			logout(utmp.ut_line);
2073#if defined(KERBEROS)
2074		if (!notickets && krbtkfile_env)
2075			unlink(krbtkfile_env);
2076#endif
2077	}
2078	/* beware of flushing buffers after a SIGPIPE */
2079	_exit(status);
2080}
2081
2082static void
2083myoob(signo)
2084	int signo;
2085{
2086	char *cp;
2087	int save_errno = errno;
2088
2089	/* only process if transfer occurring */
2090	if (!transflag)
2091		return;
2092	cp = tmpline;
2093	if (getline(cp, 7, stdin) == NULL) {
2094		reply(221, "You could at least say goodbye.");
2095		dologout(0);
2096	}
2097	upper(cp);
2098	if (strcmp(cp, "ABOR\r\n") == 0) {
2099		tmpline[0] = '\0';
2100		reply(426, "Transfer aborted. Data connection closed.");
2101		reply(226, "Abort successful");
2102		longjmp(urgcatch, 1);
2103	}
2104	if (strcmp(cp, "STAT\r\n") == 0) {
2105		tmpline[0] = '\0';
2106		if (file_size != (off_t) -1)
2107			reply(213, "Status: %qd of %qd bytes transferred",
2108			    byte_count, file_size);
2109		else
2110			reply(213, "Status: %qd bytes transferred", byte_count);
2111	}
2112	errno = save_errno;
2113}
2114
2115/*
2116 * Note: a response of 425 is not mentioned as a possible response to
2117 *	the PASV command in RFC959. However, it has been blessed as
2118 *	a legitimate response by Jon Postel in a telephone conversation
2119 *	with Rick Adams on 25 Jan 89.
2120 */
2121void
2122passive()
2123{
2124	int len, on;
2125	u_char *p, *a;
2126
2127	if (pw == NULL) {
2128		reply(530, "Please login with USER and PASS");
2129		return;
2130	}
2131	if (pdata >= 0)
2132		close(pdata);
2133	/*
2134	 * XXX
2135	 * At this point, it would be nice to have an algorithm that
2136	 * inserted a growing delay in an attack scenario.  Such a thing
2137	 * would look like continual passive sockets being opened, but
2138	 * nothing serious being done with them.  They're not used to
2139	 * move data; the entire attempt is just to use tcp FIN_WAIT
2140	 * resources.
2141	 */
2142	pdata = socket(AF_INET, SOCK_STREAM, 0);
2143	if (pdata < 0) {
2144		perror_reply(425, "Can't open passive connection");
2145		return;
2146	}
2147
2148#ifdef IP_PORTRANGE
2149	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2150	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2151	    (char *)&on, sizeof(on)) < 0)
2152		goto pasv_error;
2153#endif
2154
2155	pasv_addr = ctrl_addr;
2156	pasv_addr.su_sin.sin_port = 0;
2157	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2158		 pasv_addr.su_len) < 0)
2159		goto pasv_error;
2160
2161	len = sizeof(pasv_addr);
2162	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2163		goto pasv_error;
2164	if (listen(pdata, 1) < 0)
2165		goto pasv_error;
2166	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2167	p = (u_char *) &pasv_addr.su_sin.sin_port;
2168
2169	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2170	    a[1], a[2], a[3], p[0], p[1]);
2171	return;
2172
2173pasv_error:
2174	(void) seteuid((uid_t)pw->pw_uid);
2175	(void) close(pdata);
2176	pdata = -1;
2177	perror_reply(425, "Can't open passive connection");
2178	return;
2179}
2180
2181/*
2182 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2183 * 229 Entering Extended Passive Mode (|||port|)
2184 */
2185void
2186long_passive(char *cmd, int pf)
2187{
2188	int len, on;
2189	register u_char *p, *a;
2190
2191	if (!logged_in) {
2192		syslog(LOG_NOTICE, "long passive but not logged in");
2193		reply(503, "Login with USER first.");
2194		return;
2195	}
2196
2197	if (pf != PF_UNSPEC) {
2198		if (ctrl_addr.su_family != pf) {
2199			switch (ctrl_addr.su_family) {
2200			case AF_INET:
2201				pf = 1;
2202				break;
2203			case AF_INET6:
2204				pf = 2;
2205				break;
2206			default:
2207				pf = 0;
2208				break;
2209			}
2210			/*
2211			 * XXX
2212			 * only EPRT/EPSV ready clients will understand this
2213			 */
2214			if (strcmp(cmd, "EPSV") == 0 && pf) {
2215				reply(522, "Network protocol mismatch, "
2216				    "use (%d)", pf);
2217			} else
2218				reply(501, "Network protocol mismatch"); /*XXX*/
2219
2220			return;
2221		}
2222	}
2223
2224	if (pdata >= 0)
2225		close(pdata);
2226	/*
2227	 * XXX
2228	 * At this point, it would be nice to have an algorithm that
2229	 * inserted a growing delay in an attack scenario.  Such a thing
2230	 * would look like continual passive sockets being opened, but
2231	 * nothing serious being done with them.  They not used to move
2232	 * data; the entire attempt is just to use tcp FIN_WAIT
2233	 * resources.
2234	 */
2235	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2236	if (pdata < 0) {
2237		perror_reply(425, "Can't open passive connection");
2238		return;
2239	}
2240
2241	switch (ctrl_addr.su_family) {
2242	case AF_INET:
2243#ifdef IP_PORTRANGE
2244		on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2245		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2246		    (char *)&on, sizeof(on)) < 0)
2247			goto pasv_error;
2248#endif
2249		break;
2250	case AF_INET6:
2251#ifdef IPV6_PORTRANGE
2252		on = high_data_ports ? IPV6_PORTRANGE_HIGH
2253				     : IPV6_PORTRANGE_DEFAULT;
2254		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2255		    (char *)&on, sizeof(on)) < 0)
2256			goto pasv_error;
2257#endif
2258		break;
2259	}
2260
2261	pasv_addr = ctrl_addr;
2262	pasv_addr.su_port = 0;
2263	(void) seteuid((uid_t) 0);
2264	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2265		(void) seteuid((uid_t) pw->pw_uid);
2266		goto pasv_error;
2267	}
2268	(void) seteuid((uid_t) pw->pw_uid);
2269	len = pasv_addr.su_len;
2270	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2271		goto pasv_error;
2272	if (listen(pdata, 1) < 0)
2273		goto pasv_error;
2274	p = (u_char *) &pasv_addr.su_port;
2275
2276	if (strcmp(cmd, "LPSV") == 0) {
2277		switch (pasv_addr.su_family) {
2278		case AF_INET:
2279			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2280			reply(228,
2281			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2282			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2283			return;
2284		case AF_INET6:
2285			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2286			reply(228,
2287			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2288			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2289				6, 16, a[0], a[1], a[2], a[3], a[4],
2290				a[5], a[6], a[7], a[8], a[9], a[10],
2291				a[11], a[12], a[13], a[14], a[15], 2,
2292				2, p[0], p[1]);
2293			return;
2294		}
2295	} else if (strcmp(cmd, "EPSV") == 0) {
2296		switch (pasv_addr.su_family) {
2297		case AF_INET:
2298		case AF_INET6:
2299			reply(229, "Entering Extended Passive Mode (|||%u|)",
2300			    ntohs(pasv_addr.su_port));
2301			return;
2302		}
2303	} else {
2304		/* more proper error code? */
2305	}
2306
2307  pasv_error:
2308	(void) close(pdata);
2309	pdata = -1;
2310	perror_reply(425, "Can't open passive connection");
2311	return;
2312}
2313
2314/*
2315 * Generate unique name for file with basename "local".
2316 * The file named "local" is already known to exist.
2317 * Generates failure reply on error.
2318 */
2319static int
2320guniquefd(local, nam)
2321	char *local;
2322	char **nam;
2323{
2324	static char new[MAXPATHLEN];
2325	struct stat st;
2326	int count, len, fd;
2327	char *cp;
2328
2329	cp = strrchr(local, '/');
2330	if (cp)
2331		*cp = '\0';
2332	if (stat(cp ? local : ".", &st) < 0) {
2333		perror_reply(553, cp ? local : ".");
2334		return (-1);
2335	}
2336	if (cp)
2337		*cp = '/';
2338	(void) strncpy(new, local, sizeof(new)-1);
2339	new[sizeof(new)-1] = '\0';
2340	len = strlen(new);
2341	if (len+2+1 >= sizeof(new)-1)
2342		return (-1);
2343	cp = new + len;
2344	*cp++ = '.';
2345	for (count = 1; count < 100; count++) {
2346		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2347		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2348		if (fd == -1)
2349			continue;
2350		if (nam)
2351			*nam = new;
2352		return (fd);
2353	}
2354	reply(452, "Unique file name cannot be created.");
2355	return (-1);
2356}
2357
2358/*
2359 * Format and send reply containing system error number.
2360 */
2361void
2362perror_reply(code, string)
2363	int code;
2364	char *string;
2365{
2366
2367	reply(code, "%s: %s.", string, strerror(errno));
2368}
2369
2370static char *onefile[] = {
2371	"",
2372	0
2373};
2374
2375void
2376send_file_list(whichf)
2377	char *whichf;
2378{
2379	struct stat st;
2380	DIR *dirp = NULL;
2381	struct dirent *dir;
2382	FILE *dout = NULL;
2383	char **dirlist, *dirname;
2384	int simple = 0;
2385	int freeglob = 0;
2386	glob_t gl;
2387
2388	if (strpbrk(whichf, "~{[*?") != NULL) {
2389		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2390
2391		memset(&gl, 0, sizeof(gl));
2392		freeglob = 1;
2393		if (glob(whichf, flags, 0, &gl)) {
2394			reply(550, "not found");
2395			goto out;
2396		} else if (gl.gl_pathc == 0) {
2397			errno = ENOENT;
2398			perror_reply(550, whichf);
2399			goto out;
2400		}
2401		dirlist = gl.gl_pathv;
2402	} else {
2403		onefile[0] = whichf;
2404		dirlist = onefile;
2405		simple = 1;
2406	}
2407
2408	if (setjmp(urgcatch)) {
2409		transflag = 0;
2410		goto out;
2411	}
2412	while ((dirname = *dirlist++)) {
2413		if (stat(dirname, &st) < 0) {
2414			/*
2415			 * If user typed "ls -l", etc, and the client
2416			 * used NLST, do what the user meant.
2417			 */
2418			if (dirname[0] == '-' && *dirlist == NULL &&
2419			    transflag == 0) {
2420				retrieve("/bin/ls %s", dirname);
2421				goto out;
2422			}
2423			perror_reply(550, whichf);
2424			if (dout != NULL) {
2425				(void) fclose(dout);
2426				transflag = 0;
2427				data = -1;
2428				pdata = -1;
2429			}
2430			goto out;
2431		}
2432
2433		if (S_ISREG(st.st_mode)) {
2434			if (dout == NULL) {
2435				dout = dataconn("file list", (off_t)-1, "w");
2436				if (dout == NULL)
2437					goto out;
2438				transflag++;
2439			}
2440			fprintf(dout, "%s%s\n", dirname,
2441				type == TYPE_A ? "\r" : "");
2442			byte_count += strlen(dirname) + 1;
2443			continue;
2444		} else if (!S_ISDIR(st.st_mode))
2445			continue;
2446
2447		if ((dirp = opendir(dirname)) == NULL)
2448			continue;
2449
2450		while ((dir = readdir(dirp)) != NULL) {
2451			char nbuf[MAXPATHLEN];
2452
2453			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2454				continue;
2455			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2456			    dir->d_namlen == 2)
2457				continue;
2458
2459			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2460				 dir->d_name);
2461
2462			/*
2463			 * We have to do a stat to insure it's
2464			 * not a directory or special file.
2465			 */
2466			if (simple || (stat(nbuf, &st) == 0 &&
2467			    S_ISREG(st.st_mode))) {
2468				if (dout == NULL) {
2469					dout = dataconn("file list", (off_t)-1,
2470						"w");
2471					if (dout == NULL)
2472						goto out;
2473					transflag++;
2474				}
2475				if (nbuf[0] == '.' && nbuf[1] == '/')
2476					fprintf(dout, "%s%s\n", &nbuf[2],
2477						type == TYPE_A ? "\r" : "");
2478				else
2479					fprintf(dout, "%s%s\n", nbuf,
2480						type == TYPE_A ? "\r" : "");
2481				byte_count += strlen(nbuf) + 1;
2482			}
2483		}
2484		(void) closedir(dirp);
2485	}
2486
2487	if (dout == NULL)
2488		reply(550, "No files found.");
2489	else if (ferror(dout) != 0)
2490		perror_reply(550, "Data connection");
2491	else
2492		reply(226, "Transfer complete.");
2493
2494	transflag = 0;
2495	if (dout != NULL)
2496		(void) fclose(dout);
2497	else {
2498		if (pdata >= 0)
2499			close(pdata);
2500	}
2501	data = -1;
2502	pdata = -1;
2503out:
2504	if (freeglob) {
2505		freeglob = 0;
2506		globfree(&gl);
2507	}
2508}
2509
2510static void
2511reapchild(signo)
2512	int signo;
2513{
2514	int save_errno = errno;
2515
2516	while (wait3(NULL, WNOHANG, NULL) > 0)
2517		;
2518	errno = save_errno;
2519}
2520
2521void
2522logxfer(name, size, start)
2523	char *name;
2524	off_t size;
2525	time_t start;
2526{
2527	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2528	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2529	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2530	char *vpw;
2531	time_t now;
2532
2533	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2534		time(&now);
2535
2536		vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1);
2537		if (vpw == NULL)
2538			return;
2539
2540		snprintf(path, sizeof path, "%s/%s", dir, name);
2541		if (realpath(path, rpath) == NULL) {
2542			strncpy(rpath, path, sizeof rpath-1);
2543			rpath[sizeof rpath-1] = '\0';
2544		}
2545		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2546
2547		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2548		strvis(vpw, (guest) ? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2549
2550		snprintf(buf, sizeof(buf),
2551		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2552		    ctime(&now), now - start + (now == start),
2553		    vremotehost, (long long) size, vpath,
2554		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2555		    'o', ((guest) ? 'a' : 'r'),
2556		    vpw, 0 /* none yet */,
2557		    ((guest) ? "*" : pw->pw_name), dhostname);
2558		write(statfd, buf, strlen(buf));
2559		free(vpw);
2560	}
2561}
2562
2563#if defined(TCPWRAPPERS)
2564static int
2565check_host(sa)
2566	struct sockaddr *sa;
2567{
2568	struct sockaddr_in *sin;
2569	struct hostent *hp;
2570	char *addr;
2571
2572	if (sa->sa_family != AF_INET)
2573		return 1;	/*XXX*/
2574
2575	sin = (struct sockaddr_in *)sa;
2576	hp = gethostbyaddr((char *)&sin->sin_addr,
2577	    sizeof(struct in_addr), AF_INET);
2578	addr = inet_ntoa(sin->sin_addr);
2579	if (hp) {
2580		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2581			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2582			    hp->h_name, addr);
2583			return (0);
2584		}
2585	} else {
2586		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2587			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2588			return (0);
2589		}
2590	}
2591	return (1);
2592}
2593#endif	/* TCPWRAPPERS */
2594