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