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