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