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