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