ftpd.c revision 1.68
1/*	$OpenBSD: ftpd.c,v 1.68 2000/01/18 18:26:38 millert 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	char line[LINE_MAX];
1621
1622	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1623	fin = ftpd_popen(line, "r");
1624	lreply(211, "status of %s:", filename);
1625	while ((c = getc(fin)) != EOF) {
1626		if (c == '\n') {
1627			if (ferror(stdout)){
1628				perror_reply(421, "control connection");
1629				(void) ftpd_pclose(fin);
1630				dologout(1);
1631				/* NOTREACHED */
1632			}
1633			if (ferror(fin)) {
1634				perror_reply(551, filename);
1635				(void) ftpd_pclose(fin);
1636				return;
1637			}
1638			(void) putc('\r', stdout);
1639		}
1640		(void) putc(c, stdout);
1641	}
1642	(void) ftpd_pclose(fin);
1643	reply(211, "End of Status");
1644}
1645
1646void
1647statcmd()
1648{
1649	union sockunion *su;
1650	u_char *a, *p;
1651	char hbuf[MAXHOSTNAMELEN];
1652	int ispassive;
1653
1654	lreply(211, "%s FTP server status:", hostname, version);
1655	printf("     %s\r\n", version);
1656	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1657	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1658	printf("     Connected to %s", remotehost);
1659	if (strcmp(remotehost, hbuf) != 0)
1660		printf(" (%s)", hbuf);
1661	printf("\r\n");
1662	if (logged_in) {
1663		if (guest)
1664			printf("     Logged in anonymously\r\n");
1665		else
1666			printf("     Logged in as %s\r\n", pw->pw_name);
1667	} else if (askpasswd)
1668		printf("     Waiting for password\r\n");
1669	else
1670		printf("     Waiting for user name\r\n");
1671	printf("     TYPE: %s", typenames[type]);
1672	if (type == TYPE_A || type == TYPE_E)
1673		printf(", FORM: %s", formnames[form]);
1674	if (type == TYPE_L)
1675#if NBBY == 8
1676		printf(" %d", NBBY);
1677#else
1678		printf(" %d", bytesize);	/* need definition! */
1679#endif
1680	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1681	    strunames[stru], modenames[mode]);
1682	ispassive = 0;
1683	if (data != -1)
1684		printf("     Data connection open\r\n");
1685	else if (pdata != -1) {
1686		printf("     in Passive mode");
1687		su = (union sockunion *)&pasv_addr;
1688		ispassive++;
1689		goto printaddr;
1690	} else if (usedefault == 0) {
1691		su = (union sockunion *)&data_dest;
1692printaddr:
1693		/* PASV/PORT */
1694		if (su->su_family == AF_INET) {
1695			if (ispassive)
1696				printf("211- PASV ");
1697			else
1698				printf("211- PORT ");
1699			a = (u_char *) &su->su_sin.sin_addr;
1700			p = (u_char *) &su->su_sin.sin_port;
1701			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1702			    a[0], a[1], a[2], a[3],
1703			    p[0], p[1]);
1704		}
1705
1706		/* LPSV/LPRT */
1707	    {
1708		int alen, af, i;
1709
1710		alen = 0;
1711		switch (su->su_family) {
1712		case AF_INET:
1713			a = (u_char *) &su->su_sin.sin_addr;
1714			p = (u_char *) &su->su_sin.sin_port;
1715			alen = sizeof(su->su_sin.sin_addr);
1716			af = 4;
1717			break;
1718		case AF_INET6:
1719			a = (u_char *) &su->su_sin6.sin6_addr;
1720			p = (u_char *) &su->su_sin6.sin6_port;
1721			alen = sizeof(su->su_sin6.sin6_addr);
1722			af = 6;
1723			break;
1724		default:
1725			af = 0;
1726			break;
1727		}
1728		if (af) {
1729			if (ispassive)
1730				printf("211- LPSV ");
1731			else
1732				printf("211- LPRT ");
1733			printf("(%u,%u", af, alen);
1734			for (i = 0; i < alen; i++)
1735				printf("%u,", a[alen]);
1736			printf("%u,%u,%u)\r\n", 2, p[0], p[1]);
1737		}
1738	    }
1739
1740		/* EPRT/EPSV */
1741epsvonly:
1742	    {
1743		u_char af;
1744
1745		switch (su->su_family) {
1746		case AF_INET:
1747			af = 1;
1748			break;
1749		case AF_INET6:
1750			af = 2;
1751			break;
1752		default:
1753			af = 0;
1754			break;
1755		}
1756		if (af) {
1757			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1758			if (getnameinfo((struct sockaddr *)su, su->su_len,
1759			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1760			    NI_NUMERICHOST) == 0) {
1761				if (ispassive)
1762					printf("211 - EPSV ");
1763				else
1764					printf("211 - EPRT ");
1765				printf("(|%u|%s|%s|)\r\n",
1766					af, hbuf, pbuf);
1767			}
1768		}
1769	    }
1770	} else
1771		printf("     No data connection\r\n");
1772	reply(211, "End of status");
1773}
1774
1775void
1776fatal(s)
1777	char *s;
1778{
1779
1780	reply(451, "Error in server: %s\n", s);
1781	reply(221, "Closing connection due to server error.");
1782	dologout(0);
1783	/* NOTREACHED */
1784}
1785
1786void
1787#ifdef __STDC__
1788reply(int n, const char *fmt, ...)
1789#else
1790reply(n, fmt, va_alist)
1791	int n;
1792	char *fmt;
1793	va_dcl
1794#endif
1795{
1796	va_list ap;
1797#ifdef __STDC__
1798	va_start(ap, fmt);
1799#else
1800	va_start(ap);
1801#endif
1802	(void)printf("%d ", n);
1803	(void)vprintf(fmt, ap);
1804	(void)printf("\r\n");
1805	(void)fflush(stdout);
1806	if (debug) {
1807		syslog(LOG_DEBUG, "<--- %d ", n);
1808		vsyslog(LOG_DEBUG, fmt, ap);
1809	}
1810}
1811
1812void
1813#ifdef __STDC__
1814lreply(int n, const char *fmt, ...)
1815#else
1816lreply(n, fmt, va_alist)
1817	int n;
1818	char *fmt;
1819	va_dcl
1820#endif
1821{
1822	va_list ap;
1823#ifdef __STDC__
1824	va_start(ap, fmt);
1825#else
1826	va_start(ap);
1827#endif
1828	(void)printf("%d- ", n);
1829	(void)vprintf(fmt, ap);
1830	(void)printf("\r\n");
1831	(void)fflush(stdout);
1832	if (debug) {
1833		syslog(LOG_DEBUG, "<--- %d- ", n);
1834		vsyslog(LOG_DEBUG, fmt, ap);
1835	}
1836}
1837
1838static void
1839ack(s)
1840	char *s;
1841{
1842
1843	reply(250, "%s command successful.", s);
1844}
1845
1846void
1847nack(s)
1848	char *s;
1849{
1850
1851	reply(502, "%s command not implemented.", s);
1852}
1853
1854/* ARGSUSED */
1855void
1856yyerror(s)
1857	char *s;
1858{
1859	char *cp;
1860
1861	if ((cp = strchr(cbuf,'\n')))
1862		*cp = '\0';
1863	reply(500, "'%s': command not understood.", cbuf);
1864}
1865
1866void
1867delete(name)
1868	char *name;
1869{
1870	struct stat st;
1871
1872	LOGCMD("delete", name);
1873	if (stat(name, &st) < 0) {
1874		perror_reply(550, name);
1875		return;
1876	}
1877	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1878		if (rmdir(name) < 0) {
1879			perror_reply(550, name);
1880			return;
1881		}
1882		goto done;
1883	}
1884	if (unlink(name) < 0) {
1885		perror_reply(550, name);
1886		return;
1887	}
1888done:
1889	ack("DELE");
1890}
1891
1892void
1893cwd(path)
1894	char *path;
1895{
1896	FILE *message;
1897
1898	if (chdir(path) < 0)
1899		perror_reply(550, path);
1900	else {
1901		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
1902			char *cp, line[LINE_MAX];
1903
1904			while (fgets(line, sizeof(line), message) != NULL) {
1905				if ((cp = strchr(line, '\n')) != NULL)
1906					*cp = '\0';
1907				lreply(250, "%s", line);
1908			}
1909			(void) fflush(stdout);
1910			(void) fclose(message);
1911		}
1912		ack("CWD");
1913	}
1914}
1915
1916void
1917replydirname(name, message)
1918	const char *name, *message;
1919{
1920	char npath[MAXPATHLEN];
1921	int i;
1922
1923	for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
1924		npath[i] = *name;
1925		if (*name == '"')
1926			npath[++i] = '"';
1927	}
1928	npath[i] = '\0';
1929	reply(257, "\"%s\" %s", npath, message);
1930}
1931
1932void
1933makedir(name)
1934	char *name;
1935{
1936
1937	LOGCMD("mkdir", name);
1938	if (mkdir(name, 0777) < 0)
1939		perror_reply(550, name);
1940	else
1941		replydirname(name, "directory created.");
1942}
1943
1944void
1945removedir(name)
1946	char *name;
1947{
1948
1949	LOGCMD("rmdir", name);
1950	if (rmdir(name) < 0)
1951		perror_reply(550, name);
1952	else
1953		ack("RMD");
1954}
1955
1956void
1957pwd()
1958{
1959	char path[MAXPATHLEN];
1960
1961	if (getcwd(path, sizeof path) == (char *)NULL)
1962		reply(550, "Can't get current directory: %s.", strerror(errno));
1963	else
1964		replydirname(path, "is current directory.");
1965}
1966
1967char *
1968renamefrom(name)
1969	char *name;
1970{
1971	struct stat st;
1972
1973	if (stat(name, &st) < 0) {
1974		perror_reply(550, name);
1975		return ((char *)0);
1976	}
1977	reply(350, "File exists, ready for destination name");
1978	return (name);
1979}
1980
1981void
1982renamecmd(from, to)
1983	char *from, *to;
1984{
1985
1986	LOGCMD2("rename", from, to);
1987	if (rename(from, to) < 0)
1988		perror_reply(550, "rename");
1989	else
1990		ack("RNTO");
1991}
1992
1993static void
1994dolog(sa)
1995	struct sockaddr *sa;
1996{
1997	char hbuf[sizeof(remotehost)];
1998
1999	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2000	(void) strncpy(remotehost, hbuf, sizeof(remotehost)-1);
2001
2002	remotehost[sizeof(remotehost)-1] = '\0';
2003#ifdef HASSETPROCTITLE
2004	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2005	setproctitle(proctitle);
2006#endif /* HASSETPROCTITLE */
2007
2008	if (logging)
2009		syslog(LOG_INFO, "connection from %s", remotehost);
2010}
2011
2012/*
2013 * Record logout in wtmp file
2014 * and exit with supplied status.
2015 */
2016void
2017dologout(status)
2018	int status;
2019{
2020	sigset_t allsigs;
2021
2022	transflag = 0;
2023
2024	if (logged_in) {
2025		sigfillset(&allsigs);
2026		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2027		(void) seteuid((uid_t)0);
2028		ftpdlogwtmp(ttyline, "", "");
2029		if (doutmp)
2030			logout(utmp.ut_line);
2031#if defined(KERBEROS)
2032		if (!notickets && krbtkfile_env)
2033			unlink(krbtkfile_env);
2034#endif
2035	}
2036	/* beware of flushing buffers after a SIGPIPE */
2037	_exit(status);
2038}
2039
2040static void
2041myoob(signo)
2042	int signo;
2043{
2044	char *cp;
2045	int save_errno = errno;
2046
2047	/* only process if transfer occurring */
2048	if (!transflag)
2049		return;
2050	cp = tmpline;
2051	if (getline(cp, 7, stdin) == NULL) {
2052		reply(221, "You could at least say goodbye.");
2053		dologout(0);
2054	}
2055	upper(cp);
2056	if (strcmp(cp, "ABOR\r\n") == 0) {
2057		tmpline[0] = '\0';
2058		reply(426, "Transfer aborted. Data connection closed.");
2059		reply(226, "Abort successful");
2060		longjmp(urgcatch, 1);
2061	}
2062	if (strcmp(cp, "STAT\r\n") == 0) {
2063		tmpline[0] = '\0';
2064		if (file_size != (off_t) -1)
2065			reply(213, "Status: %qd of %qd bytes transferred",
2066			    byte_count, file_size);
2067		else
2068			reply(213, "Status: %qd bytes transferred", byte_count);
2069	}
2070	errno = save_errno;
2071}
2072
2073/*
2074 * Note: a response of 425 is not mentioned as a possible response to
2075 *	the PASV command in RFC959. However, it has been blessed as
2076 *	a legitimate response by Jon Postel in a telephone conversation
2077 *	with Rick Adams on 25 Jan 89.
2078 */
2079void
2080passive()
2081{
2082	int len, on;
2083	u_char *p, *a;
2084
2085	if (pw == NULL) {
2086		reply(530, "Please login with USER and PASS");
2087		return;
2088	}
2089	if (pdata >= 0)
2090		close(pdata);
2091	/*
2092	 * XXX
2093	 * At this point, it would be nice to have an algorithm that
2094	 * inserted a growing delay in an attack scenario.  Such a thing
2095	 * would look like continual passive sockets being opened, but
2096	 * nothing serious being done with them.  They're not used to
2097	 * move data; the entire attempt is just to use tcp FIN_WAIT
2098	 * resources.
2099	 */
2100	pdata = socket(AF_INET, SOCK_STREAM, 0);
2101	if (pdata < 0) {
2102		perror_reply(425, "Can't open passive connection");
2103		return;
2104	}
2105
2106#ifdef IP_PORTRANGE
2107	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2108	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2109	    (char *)&on, sizeof(on)) < 0)
2110		goto pasv_error;
2111#endif
2112
2113	pasv_addr = ctrl_addr;
2114	pasv_addr.su_sin.sin_port = 0;
2115	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2116		 pasv_addr.su_len) < 0)
2117		goto pasv_error;
2118
2119	len = sizeof(pasv_addr);
2120	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2121		goto pasv_error;
2122	if (listen(pdata, 1) < 0)
2123		goto pasv_error;
2124	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2125	p = (u_char *) &pasv_addr.su_sin.sin_port;
2126
2127	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2128	    a[1], a[2], a[3], p[0], p[1]);
2129	return;
2130
2131pasv_error:
2132	(void) seteuid((uid_t)pw->pw_uid);
2133	(void) close(pdata);
2134	pdata = -1;
2135	perror_reply(425, "Can't open passive connection");
2136	return;
2137}
2138
2139/*
2140 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2141 * 229 Entering Extended Passive Mode (|||port|)
2142 */
2143void
2144long_passive(char *cmd, int pf)
2145{
2146	int len;
2147	register u_char *p, *a;
2148
2149	if (!logged_in) {
2150		syslog(LOG_NOTICE, "long passive but not logged in");
2151		reply(503, "Login with USER first.");
2152		return;
2153	}
2154
2155	if (pf != PF_UNSPEC) {
2156		if (ctrl_addr.su_family != pf) {
2157			switch (ctrl_addr.su_family) {
2158			case AF_INET:
2159				pf = 1;
2160				break;
2161			case AF_INET6:
2162				pf = 2;
2163				break;
2164			default:
2165				pf = 0;
2166				break;
2167			}
2168			/*
2169			 * XXX
2170			 * only EPRT/EPSV ready clients will understand this
2171			 */
2172			if (strcmp(cmd, "EPSV") == 0 && pf) {
2173				reply(522, "Network protocol mismatch, "
2174				    "use (%d)", pf);
2175			} else
2176				reply(501, "Network protocol mismatch"); /*XXX*/
2177
2178			return;
2179		}
2180	}
2181
2182	if (pdata >= 0)
2183		close(pdata);
2184	/*
2185	 * XXX
2186	 * At this point, it would be nice to have an algorithm that
2187	 * inserted a growing delay in an attack scenario.  Such a thing
2188	 * would look like continual passive sockets being opened, but
2189	 * nothing serious being done with them.  They not used to move
2190	 * data; the entire attempt is just to use tcp FIN_WAIT
2191	 * resources.
2192	 */
2193	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2194	if (pdata < 0) {
2195		perror_reply(425, "Can't open passive connection");
2196		return;
2197	}
2198	pasv_addr = ctrl_addr;
2199	pasv_addr.su_port = 0;
2200	(void) seteuid((uid_t) 0);
2201	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2202		(void) seteuid((uid_t) pw->pw_uid);
2203		goto pasv_error;
2204	}
2205	(void) seteuid((uid_t) pw->pw_uid);
2206	len = pasv_addr.su_len;
2207	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2208		goto pasv_error;
2209	if (listen(pdata, 1) < 0)
2210		goto pasv_error;
2211	p = (u_char *) &pasv_addr.su_port;
2212
2213	if (strcmp(cmd, "LPSV") == 0) {
2214		switch (pasv_addr.su_family) {
2215		case AF_INET:
2216			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2217			reply(228,
2218			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2219			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2220			return;
2221		case AF_INET6:
2222			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2223			reply(228,
2224			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2225			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2226				6, 16, a[0], a[1], a[2], a[3], a[4],
2227				a[5], a[6], a[7], a[8], a[9], a[10],
2228				a[11], a[12], a[13], a[14], a[15], 2,
2229				2, p[0], p[1]);
2230			return;
2231		}
2232	} else if (strcmp(cmd, "EPSV") == 0) {
2233		switch (pasv_addr.su_family) {
2234		case AF_INET:
2235		case AF_INET6:
2236			reply(229, "Entering Extended Passive Mode (|||%u|)",
2237			    ntohs(pasv_addr.su_port));
2238			return;
2239		}
2240	} else {
2241		/* more proper error code? */
2242	}
2243
2244  pasv_error:
2245	(void) close(pdata);
2246	pdata = -1;
2247	perror_reply(425, "Can't open passive connection");
2248	return;
2249}
2250
2251/*
2252 * Generate unique name for file with basename "local".
2253 * The file named "local" is already known to exist.
2254 * Generates failure reply on error.
2255 */
2256static int
2257guniquefd(local, nam)
2258	char *local;
2259	char **nam;
2260{
2261	static char new[MAXPATHLEN];
2262	struct stat st;
2263	int count, len, fd;
2264	char *cp;
2265
2266	cp = strrchr(local, '/');
2267	if (cp)
2268		*cp = '\0';
2269	if (stat(cp ? local : ".", &st) < 0) {
2270		perror_reply(553, cp ? local : ".");
2271		return (-1);
2272	}
2273	if (cp)
2274		*cp = '/';
2275	(void) strncpy(new, local, sizeof(new)-1);
2276	new[sizeof(new)-1] = '\0';
2277	len = strlen(new);
2278	if (len+2+1 >= sizeof(new)-1)
2279		return (-1);
2280	cp = new + len;
2281	*cp++ = '.';
2282	for (count = 1; count < 100; count++) {
2283		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2284		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2285		if (fd == -1)
2286			continue;
2287		if (nam)
2288			*nam = new;
2289		return (fd);
2290	}
2291	reply(452, "Unique file name cannot be created.");
2292	return (-1);
2293}
2294
2295/*
2296 * Format and send reply containing system error number.
2297 */
2298void
2299perror_reply(code, string)
2300	int code;
2301	char *string;
2302{
2303
2304	reply(code, "%s: %s.", string, strerror(errno));
2305}
2306
2307static char *onefile[] = {
2308	"",
2309	0
2310};
2311
2312void
2313send_file_list(whichf)
2314	char *whichf;
2315{
2316	struct stat st;
2317	DIR *dirp = NULL;
2318	struct dirent *dir;
2319	FILE *dout = NULL;
2320	char **dirlist, *dirname;
2321	int simple = 0;
2322	int freeglob = 0;
2323	glob_t gl;
2324
2325	if (strpbrk(whichf, "~{[*?") != NULL) {
2326		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2327
2328		memset(&gl, 0, sizeof(gl));
2329		freeglob = 1;
2330		if (glob(whichf, flags, 0, &gl)) {
2331			reply(550, "not found");
2332			goto out;
2333		} else if (gl.gl_pathc == 0) {
2334			errno = ENOENT;
2335			perror_reply(550, whichf);
2336			goto out;
2337		}
2338		dirlist = gl.gl_pathv;
2339	} else {
2340		onefile[0] = whichf;
2341		dirlist = onefile;
2342		simple = 1;
2343	}
2344
2345	if (setjmp(urgcatch)) {
2346		transflag = 0;
2347		goto out;
2348	}
2349	while ((dirname = *dirlist++)) {
2350		if (stat(dirname, &st) < 0) {
2351			/*
2352			 * If user typed "ls -l", etc, and the client
2353			 * used NLST, do what the user meant.
2354			 */
2355			if (dirname[0] == '-' && *dirlist == NULL &&
2356			    transflag == 0) {
2357				retrieve("/bin/ls %s", dirname);
2358				goto out;
2359			}
2360			perror_reply(550, whichf);
2361			if (dout != NULL) {
2362				(void) fclose(dout);
2363				transflag = 0;
2364				data = -1;
2365				pdata = -1;
2366			}
2367			goto out;
2368		}
2369
2370		if (S_ISREG(st.st_mode)) {
2371			if (dout == NULL) {
2372				dout = dataconn("file list", (off_t)-1, "w");
2373				if (dout == NULL)
2374					goto out;
2375				transflag++;
2376			}
2377			fprintf(dout, "%s%s\n", dirname,
2378				type == TYPE_A ? "\r" : "");
2379			byte_count += strlen(dirname) + 1;
2380			continue;
2381		} else if (!S_ISDIR(st.st_mode))
2382			continue;
2383
2384		if ((dirp = opendir(dirname)) == NULL)
2385			continue;
2386
2387		while ((dir = readdir(dirp)) != NULL) {
2388			char nbuf[MAXPATHLEN];
2389
2390			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2391				continue;
2392			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2393			    dir->d_namlen == 2)
2394				continue;
2395
2396			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2397				 dir->d_name);
2398
2399			/*
2400			 * We have to do a stat to insure it's
2401			 * not a directory or special file.
2402			 */
2403			if (simple || (stat(nbuf, &st) == 0 &&
2404			    S_ISREG(st.st_mode))) {
2405				if (dout == NULL) {
2406					dout = dataconn("file list", (off_t)-1,
2407						"w");
2408					if (dout == NULL)
2409						goto out;
2410					transflag++;
2411				}
2412				if (nbuf[0] == '.' && nbuf[1] == '/')
2413					fprintf(dout, "%s%s\n", &nbuf[2],
2414						type == TYPE_A ? "\r" : "");
2415				else
2416					fprintf(dout, "%s%s\n", nbuf,
2417						type == TYPE_A ? "\r" : "");
2418				byte_count += strlen(nbuf) + 1;
2419			}
2420		}
2421		(void) closedir(dirp);
2422	}
2423
2424	if (dout == NULL)
2425		reply(550, "No files found.");
2426	else if (ferror(dout) != 0)
2427		perror_reply(550, "Data connection");
2428	else
2429		reply(226, "Transfer complete.");
2430
2431	transflag = 0;
2432	if (dout != NULL)
2433		(void) fclose(dout);
2434	data = -1;
2435	pdata = -1;
2436out:
2437	if (freeglob) {
2438		freeglob = 0;
2439		globfree(&gl);
2440	}
2441}
2442
2443static void
2444reapchild(signo)
2445	int signo;
2446{
2447	int save_errno = errno;
2448
2449	while (wait3(NULL, WNOHANG, NULL) > 0)
2450		;
2451	errno = save_errno;
2452}
2453
2454void
2455logxfer(name, size, start)
2456	char *name;
2457	off_t size;
2458	time_t start;
2459{
2460	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2461	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2462	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2463	char *vpw;
2464	time_t now;
2465
2466	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2467		time(&now);
2468
2469		vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1);
2470		if (vpw == NULL)
2471			return;
2472
2473		snprintf(path, sizeof path, "%s/%s", dir, name);
2474		if (realpath(path, rpath) == NULL) {
2475			strncpy(rpath, path, sizeof rpath-1);
2476			rpath[sizeof rpath-1] = '\0';
2477		}
2478		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2479
2480		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2481		strvis(vpw, (guest) ? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2482
2483		snprintf(buf, sizeof(buf),
2484		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2485		    ctime(&now), now - start + (now == start),
2486		    vremotehost, (long long) size, vpath,
2487		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2488		    'o', ((guest) ? 'a' : 'r'),
2489		    vpw, 0 /* none yet */,
2490		    ((guest) ? "*" : pw->pw_name), dhostname);
2491		write(statfd, buf, strlen(buf));
2492		free(vpw);
2493	}
2494}
2495
2496#if defined(TCPWRAPPERS)
2497static int
2498check_host(sa)
2499	struct sockaddr *sa;
2500{
2501	struct sockaddr_in *sin;
2502	struct hostent *hp;
2503	char *addr;
2504
2505	if (sa->sa_family != AF_INET)
2506		return 1;	/*XXX*/
2507
2508	sin = (struct sockaddr_in *)sa;
2509	hp = gethostbyaddr((char *)&sin->sin_addr,
2510	    sizeof(struct in_addr), AF_INET);
2511	addr = inet_ntoa(sin->sin_addr);
2512	if (hp) {
2513		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2514			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2515			    hp->h_name, addr);
2516			return (0);
2517		}
2518	} else {
2519		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2520			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2521			return (0);
2522		}
2523	}
2524	return (1);
2525}
2526#endif	/* TCPWRAPPERS */
2527