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