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