ftpd.c revision 1.88
1/*	$OpenBSD: ftpd.c,v 1.88 2001/01/09 05:07:01 itojun 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
629	if (debug)
630		syslog(LOG_DEBUG, "lost connection");
631	dologout(1);
632}
633
634static void
635sigquit(signo)
636	int signo;
637{
638	syslog(LOG_ERR, "got signal %s", strerror(signo));
639
640	dologout(1);
641}
642
643/*
644 * Helper function for sgetpwnam().
645 */
646static char *
647sgetsave(s)
648	char *s;
649{
650	char *new = malloc((unsigned) strlen(s) + 1);
651
652	if (new == NULL) {
653		perror_reply(421, "Local resource failure: malloc");
654		dologout(1);
655		/* NOTREACHED */
656	}
657	(void) strcpy(new, s);
658	return (new);
659}
660
661/*
662 * Save the result of a getpwnam.  Used for USER command, since
663 * the data returned must not be clobbered by any other command
664 * (e.g., globbing).
665 */
666static struct passwd *
667sgetpwnam(name)
668	char *name;
669{
670	static struct passwd save;
671	struct passwd *p;
672
673	if ((p = getpwnam(name)) == NULL)
674		return (p);
675	if (save.pw_name) {
676		free(save.pw_name);
677		memset(save.pw_passwd, 0, strlen(save.pw_passwd));
678		free(save.pw_passwd);
679		free(save.pw_class);
680		free(save.pw_gecos);
681		free(save.pw_dir);
682		free(save.pw_shell);
683	}
684	save = *p;
685	save.pw_name = sgetsave(p->pw_name);
686	save.pw_passwd = sgetsave(p->pw_passwd);
687	save.pw_class = sgetsave(p->pw_class);
688	save.pw_gecos = sgetsave(p->pw_gecos);
689	save.pw_dir = sgetsave(p->pw_dir);
690	save.pw_shell = sgetsave(p->pw_shell);
691	return (&save);
692}
693
694static int login_attempts;	/* number of failed login attempts */
695static int askpasswd;		/* had user command, ask for passwd */
696static char curname[16];	/* current USER name */
697
698/*
699 * USER command.
700 * Sets global passwd pointer pw if named account exists and is acceptable;
701 * sets askpasswd if a PASS command is expected.  If logged in previously,
702 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
703 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
704 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
705 * requesting login privileges.  Disallow anyone who does not have a standard
706 * shell as returned by getusershell().  Disallow anyone mentioned in the file
707 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
708 */
709void
710user(name)
711	char *name;
712{
713	char *cp, *shell;
714
715	if (lc) {
716		login_close(lc);
717		lc = NULL;
718	}
719
720	if (logged_in) {
721		if (guest) {
722			reply(530, "Can't change user from guest login.");
723			return;
724		} else if (dochroot) {
725			reply(530, "Can't change user from chroot user.");
726			return;
727		}
728		end_login();
729	}
730
731	guest = 0;
732	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
733		if (checkuser(_PATH_FTPUSERS, "ftp") ||
734		    checkuser(_PATH_FTPUSERS, "anonymous"))
735			reply(530, "User %s access denied.", name);
736		else if ((pw = sgetpwnam("ftp")) != NULL) {
737			guest = 1;
738			askpasswd = 1;
739			lc = login_getclass(pw->pw_class);
740			reply(331,
741			    "Guest login ok, type your name as password.");
742		} else
743			reply(530, "User %s unknown.", name);
744		if (!askpasswd && logging)
745			syslog(LOG_NOTICE,
746			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
747		return;
748	}
749	if (anon_only && !checkuser(_PATH_FTPCHROOT, name)) {
750		reply(530, "Sorry, only anonymous ftp allowed.");
751		return;
752	}
753
754	if ((pw = sgetpwnam(name))) {
755		if ((shell = pw->pw_shell) == NULL || *shell == 0)
756			shell = _PATH_BSHELL;
757		while ((cp = getusershell()) != NULL)
758			if (strcmp(cp, shell) == 0)
759				break;
760		endusershell();
761
762		if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
763			reply(530, "User %s access denied.", name);
764			if (logging)
765				syslog(LOG_NOTICE,
766				    "FTP LOGIN REFUSED FROM %s, %s",
767				    remotehost, name);
768			pw = (struct passwd *) NULL;
769			return;
770		}
771		lc = login_getclass(pw->pw_class);
772	}
773	if (logging) {
774		strncpy(curname, name, sizeof(curname)-1);
775		curname[sizeof(curname)-1] = '\0';
776	}
777#ifdef SKEY
778	if (!skey_haskey(name)) {
779		char *myskey, *skey_keyinfo __P((char *name));
780
781		myskey = skey_keyinfo(name);
782		reply(331, "Password [ %s ] for %s required.",
783		    myskey ? myskey : "error getting challenge", name);
784	} else
785#endif
786		reply(331, "Password required for %s.", name);
787
788	askpasswd = 1;
789	/*
790	 * Delay before reading passwd after first failed
791	 * attempt to slow down passwd-guessing programs.
792	 */
793	if (login_attempts)
794		sleep((unsigned) login_attempts);
795}
796
797/*
798 * Check if a user is in the file "fname"
799 */
800static int
801checkuser(fname, name)
802	char *fname;
803	char *name;
804{
805	FILE *fp;
806	int found = 0;
807	char *p, line[BUFSIZ];
808
809	if ((fp = fopen(fname, "r")) != NULL) {
810		while (fgets(line, sizeof(line), fp) != NULL)
811			if ((p = strchr(line, '\n')) != NULL) {
812				*p = '\0';
813				if (line[0] == '#')
814					continue;
815				if (strcmp(line, name) == 0) {
816					found = 1;
817					break;
818				}
819			}
820		(void) fclose(fp);
821	}
822	return (found);
823}
824
825/*
826 * Terminate login as previous user, if any, resetting state;
827 * used when USER command is given or login fails.
828 */
829static void
830end_login()
831{
832	sigset_t allsigs;
833	sigfillset (&allsigs);
834	sigprocmask (SIG_BLOCK, &allsigs, NULL);
835	(void) seteuid((uid_t)0);
836	if (logged_in) {
837		ftpdlogwtmp(ttyline, "", "");
838		if (doutmp)
839			logout(utmp.ut_line);
840	}
841	pw = NULL;
842	/* umask is restored in ftpcmd.y */
843	setusercontext(NULL, getpwuid(0), (uid_t)0,
844	    LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
845	logged_in = 0;
846	guest = 0;
847	dochroot = 0;
848}
849
850void
851pass(passwd)
852	char *passwd;
853{
854	int rval, flags;
855	FILE *fp;
856	static char homedir[MAXPATHLEN];
857	char *dir, rootdir[MAXPATHLEN];
858	sigset_t allsigs;
859
860	if (logged_in || askpasswd == 0) {
861		reply(503, "Login with USER first.");
862		return;
863	}
864	askpasswd = 0;
865	if (!guest) {		/* "ftp" is only account allowed no password */
866		if (pw == NULL) {
867			useconds_t us;
868
869			/* Sleep between 1 and 3 seconds to emulate a crypt. */
870			us = arc4random() % 3000000;
871			usleep(us);
872			rval = 1;	/* failure below */
873			goto skip;
874		}
875#if defined(KERBEROS)
876		rval = klogin(pw, "", hostname, passwd);
877		if (rval == 0)
878			goto skip;
879#endif
880#ifdef SKEY
881		if (skey_haskey(pw->pw_name) == 0 &&
882		   (skey_passcheck(pw->pw_name, passwd) != -1)) {
883			rval = 0;
884			goto skip;
885		}
886#endif
887		/* the strcmp does not catch null passwords! */
888		if (strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) ||
889		    *pw->pw_passwd == '\0') {
890			rval = 1;	 /* failure */
891			goto skip;
892		}
893		rval = 0;
894
895skip:
896		/*
897		 * If rval == 1, the user failed the authentication check
898		 * above.  If rval == 0, either Kerberos or local authentication
899		 * succeeded.
900		 */
901		if (rval) {
902			reply(530, "Login incorrect.");
903			if (logging)
904				syslog(LOG_NOTICE,
905				    "FTP LOGIN FAILED FROM %s, %s",
906				    remotehost, curname);
907			pw = NULL;
908			if (login_attempts++ >= 5) {
909				syslog(LOG_NOTICE,
910				    "repeated login failures from %s",
911				    remotehost);
912				exit(0);
913			}
914			return;
915		}
916	} else {
917		/* Save anonymous' password. */
918		guestpw = strdup(passwd);
919		if (guestpw == (char *)NULL)
920			fatal("Out of memory");
921	}
922	login_attempts = 0;		/* this time successful */
923	if (setegid((gid_t)pw->pw_gid) < 0) {
924		reply(550, "Can't set gid.");
925		return;
926	}
927	/* set umask via setusercontext() unless -u flag was given. */
928	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
929	if (umaskchange)
930		flags |= LOGIN_SETUMASK;
931	else
932		(void) umask(defumask);
933	setusercontext(lc, pw, (uid_t)0, flags);
934
935	/* open wtmp before chroot */
936	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
937
938	/* open utmp before chroot */
939	if (doutmp) {
940		memset((void *)&utmp, 0, sizeof(utmp));
941		(void)time(&utmp.ut_time);
942		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
943		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
944		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
945		login(&utmp);
946	}
947
948	/* open stats file before chroot */
949	if (guest && (stats == 1) && (statfd < 0))
950		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
951			stats = 0;
952
953	logged_in = 1;
954
955	dochroot = login_getcapbool(lc, "ftp-chroot", 0) ||
956	    checkuser(_PATH_FTPCHROOT, pw->pw_name);
957	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
958		char *newdir;
959
960		newdir = copy_dir(dir, pw);
961		if (newdir == NULL) {
962			perror_reply(421, "Local resource failure: malloc");
963			dologout(1);
964			/* NOTREACHED */
965		}
966		free(pw->pw_dir);
967		pw->pw_dir = newdir;
968	}
969	if (guest || dochroot) {
970		if (multihome && guest) {
971			struct stat ts;
972
973			/* Compute root directory. */
974			snprintf(rootdir, sizeof(rootdir), "%s/%s",
975				  pw->pw_dir, dhostname);
976			if (stat(rootdir, &ts) < 0) {
977				snprintf(rootdir, sizeof(rootdir), "%s/%s",
978					  pw->pw_dir, hostname);
979			}
980		} else
981			strcpy(rootdir, pw->pw_dir);
982	}
983	if (guest) {
984		/*
985		 * We MUST do a chdir() after the chroot. Otherwise
986		 * the old current directory will be accessible as "."
987		 * outside the new root!
988		 */
989		if (chroot(rootdir) < 0 || chdir("/") < 0) {
990			reply(550, "Can't set guest privileges.");
991			goto bad;
992		}
993		strcpy(pw->pw_dir, "/");
994		if (setenv("HOME", "/", 1) == -1) {
995			reply(550, "Can't setup environment.");
996			goto bad;
997		}
998	} else if (dochroot) {
999		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1000			reply(550, "Can't change root.");
1001			goto bad;
1002		}
1003		strcpy(pw->pw_dir, "/");
1004		if (setenv("HOME", "/", 1) == -1) {
1005			reply(550, "Can't setup environment.");
1006			goto bad;
1007		}
1008	} else if (chdir(pw->pw_dir) < 0) {
1009		if (chdir("/") < 0) {
1010			reply(530, "User %s: can't change directory to %s.",
1011			    pw->pw_name, pw->pw_dir);
1012			goto bad;
1013		} else
1014			lreply(230, "No directory! Logging in with home=/");
1015	}
1016	if (seteuid((uid_t)pw->pw_uid) < 0) {
1017		reply(550, "Can't set uid.");
1018		goto bad;
1019	}
1020	sigfillset(&allsigs);
1021	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1022
1023	/*
1024	 * Set home directory so that use of ~ (tilde) works correctly.
1025	 */
1026	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1027		if (setenv("HOME", homedir, 1) == -1) {
1028			reply(550, "Can't setup environment.");
1029			goto bad;
1030		}
1031	}
1032
1033	/*
1034	 * Display a login message, if it exists.
1035	 * N.B. reply(230,) must follow the message.
1036	 */
1037	if ((fp = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
1038		char *cp, line[LINE_MAX];
1039
1040		while (fgets(line, sizeof(line), fp) != NULL) {
1041			if ((cp = strchr(line, '\n')) != NULL)
1042				*cp = '\0';
1043			lreply(230, "%s", line);
1044		}
1045		(void) fflush(stdout);
1046		(void) fclose(fp);
1047	}
1048	if (guest) {
1049		if (ident != NULL)
1050			free(ident);
1051		ident = strdup(passwd);
1052		if (ident == NULL)
1053			fatal("Ran out of memory.");
1054		reply(230, "Guest login ok, access restrictions apply.");
1055#ifdef HASSETPROCTITLE
1056		snprintf(proctitle, sizeof(proctitle),
1057		    "%s: anonymous/%.*s", remotehost,
1058		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1059		    sizeof(": anonymous/")), passwd);
1060		setproctitle("%s", proctitle);
1061#endif /* HASSETPROCTITLE */
1062		if (logging)
1063			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1064			    remotehost, passwd);
1065	} else {
1066		reply(230, "User %s logged in.", pw->pw_name);
1067#ifdef HASSETPROCTITLE
1068		snprintf(proctitle, sizeof(proctitle),
1069		    "%s: %s", remotehost, pw->pw_name);
1070		setproctitle("%s", proctitle);
1071#endif /* HASSETPROCTITLE */
1072		if (logging)
1073			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1074			    remotehost, pw->pw_name);
1075	}
1076	login_close(lc);
1077	lc = NULL;
1078	return;
1079bad:
1080	/* Forget all about it... */
1081	login_close(lc);
1082	lc = NULL;
1083	end_login();
1084}
1085
1086void
1087retrieve(cmd, name)
1088	char *cmd, *name;
1089{
1090	FILE *fin, *dout;
1091	struct stat st;
1092	int (*closefunc) __P((FILE *));
1093	time_t start;
1094
1095	if (cmd == 0) {
1096		fin = fopen(name, "r"), closefunc = fclose;
1097		st.st_size = 0;
1098	} else {
1099		char line[BUFSIZ];
1100
1101		(void) snprintf(line, sizeof(line), cmd, name);
1102		name = line;
1103		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1104		st.st_size = -1;
1105		st.st_blksize = BUFSIZ;
1106	}
1107	if (fin == NULL) {
1108		if (errno != 0) {
1109			perror_reply(550, name);
1110			if (cmd == 0) {
1111				LOGCMD("get", name);
1112			}
1113		}
1114		return;
1115	}
1116	byte_count = -1;
1117	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1118		reply(550, "%s: not a plain file.", name);
1119		goto done;
1120	}
1121	if (restart_point) {
1122		if (type == TYPE_A) {
1123			off_t i, n;
1124			int c;
1125
1126			n = restart_point;
1127			i = 0;
1128			while (i++ < n) {
1129				if ((c=getc(fin)) == EOF) {
1130					perror_reply(550, name);
1131					goto done;
1132				}
1133				if (c == '\n')
1134					i++;
1135			}
1136		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1137			perror_reply(550, name);
1138			goto done;
1139		}
1140	}
1141	dout = dataconn(name, st.st_size, "w");
1142	if (dout == NULL)
1143		goto done;
1144	time(&start);
1145	send_data(fin, dout, st.st_blksize, st.st_size,
1146		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1147	if ((cmd == 0) && stats)
1148		logxfer(name, byte_count, start);
1149	(void) fclose(dout);
1150	data = -1;
1151done:
1152	if (pdata >= 0)
1153		(void) close(pdata);
1154	pdata = -1;
1155	if (cmd == 0)
1156		LOGBYTES("get", name, byte_count);
1157	(*closefunc)(fin);
1158}
1159
1160void
1161store(name, mode, unique)
1162	char *name, *mode;
1163	int unique;
1164{
1165	FILE *fout, *din;
1166	int (*closefunc) __P((FILE *));
1167	struct stat st;
1168	int fd;
1169
1170	if (restart_point && *mode != 'a')
1171		mode = "r+";
1172
1173	if (unique && stat(name, &st) == 0) {
1174		char *nam;
1175
1176		fd = guniquefd(name, &nam);
1177		if (fd == -1) {
1178			LOGCMD(*mode == 'w' ? "put" : "append", name);
1179			return;
1180		}
1181		name = nam;
1182		fout = fdopen(fd, mode);
1183	} else
1184		fout = fopen(name, mode);
1185
1186	closefunc = fclose;
1187	if (fout == NULL) {
1188		perror_reply(553, name);
1189		LOGCMD(*mode == 'w' ? "put" : "append", name);
1190		return;
1191	}
1192	byte_count = -1;
1193	if (restart_point) {
1194		if (type == TYPE_A) {
1195			off_t i, n;
1196			int c;
1197
1198			n = restart_point;
1199			i = 0;
1200			while (i++ < n) {
1201				if ((c=getc(fout)) == EOF) {
1202					perror_reply(550, name);
1203					goto done;
1204				}
1205				if (c == '\n')
1206					i++;
1207			}
1208			/*
1209			 * We must do this seek to "current" position
1210			 * because we are changing from reading to
1211			 * writing.
1212			 */
1213			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1214				perror_reply(550, name);
1215				goto done;
1216			}
1217		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1218			perror_reply(550, name);
1219			goto done;
1220		}
1221	}
1222	din = dataconn(name, (off_t)-1, "r");
1223	if (din == NULL)
1224		goto done;
1225	if (receive_data(din, fout) == 0) {
1226		if (unique)
1227			reply(226, "Transfer complete (unique file name:%s).",
1228			    name);
1229		else
1230			reply(226, "Transfer complete.");
1231	}
1232	(void) fclose(din);
1233	data = -1;
1234	pdata = -1;
1235done:
1236	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1237	(*closefunc)(fout);
1238}
1239
1240static FILE *
1241getdatasock(mode)
1242	char *mode;
1243{
1244	int on = 1, s, t, tries;
1245	sigset_t allsigs;
1246
1247	if (data >= 0)
1248		return (fdopen(data, mode));
1249	sigfillset(&allsigs);
1250	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1251	(void) seteuid((uid_t)0);
1252	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1253	if (s < 0)
1254		goto bad;
1255	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1256	    (char *) &on, sizeof(on)) < 0)
1257		goto bad;
1258	/* anchor socket to avoid multi-homing problems */
1259	data_source = ctrl_addr;
1260	data_source.su_port = htons(20); /* ftp-data port */
1261	for (tries = 1; ; tries++) {
1262		if (bind(s, (struct sockaddr *)&data_source,
1263		    data_source.su_len) >= 0)
1264			break;
1265		if (errno != EADDRINUSE || tries > 10)
1266			goto bad;
1267		sleep(tries);
1268	}
1269	(void) seteuid((uid_t)pw->pw_uid);
1270	sigfillset(&allsigs);
1271	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1272
1273#ifdef IP_TOS
1274	if (ctrl_addr.su_family == AF_INET) {
1275		on = IPTOS_THROUGHPUT;
1276		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1277		    sizeof(int)) < 0)
1278			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1279	}
1280#endif
1281#ifdef TCP_NOPUSH
1282	/*
1283	 * Turn off push flag to keep sender TCP from sending short packets
1284	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1285	 * to set the send buffer size as well, but that may not be desirable
1286	 * in heavy-load situations.
1287	 */
1288	on = 1;
1289	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1290		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1291#endif
1292#ifdef SO_SNDBUF
1293	on = 65536;
1294	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1295		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1296#endif
1297
1298	return (fdopen(s, mode));
1299bad:
1300	/* Return the real value of errno (close may change it) */
1301	t = errno;
1302	(void) seteuid((uid_t)pw->pw_uid);
1303	sigfillset (&allsigs);
1304	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1305	(void) close(s);
1306	errno = t;
1307	return (NULL);
1308}
1309
1310static FILE *
1311dataconn(name, size, mode)
1312	char *name;
1313	off_t size;
1314	char *mode;
1315{
1316	char sizebuf[32];
1317	FILE *file;
1318	int retry = 0;
1319	in_port_t *p;
1320	char *fa, *ha;
1321	int alen;
1322
1323	file_size = size;
1324	byte_count = 0;
1325	if (size != (off_t) -1) {
1326		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1327				size);
1328	} else
1329		sizebuf[0] = '\0';
1330	if (pdata >= 0) {
1331		union sockunion from;
1332		int s, fromlen = sizeof(from);
1333
1334		signal (SIGALRM, toolong);
1335		(void) alarm ((unsigned) timeout);
1336		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1337		(void) alarm (0);
1338		if (s < 0) {
1339			reply(425, "Can't open data connection.");
1340			(void) close(pdata);
1341			pdata = -1;
1342			return (NULL);
1343		}
1344		switch (from.su_family) {
1345		case AF_INET:
1346			p = (in_port_t *)&from.su_sin.sin_port;
1347			fa = (u_char *)&from.su_sin.sin_addr;
1348			ha = (u_char *)&his_addr.su_sin.sin_addr;
1349			alen = sizeof(struct in_addr);
1350			break;
1351		case AF_INET6:
1352			p = (in_port_t *)&from.su_sin6.sin6_port;
1353			fa = (u_char *)&from.su_sin6.sin6_addr;
1354			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1355			alen = sizeof(struct in6_addr);
1356			break;
1357		default:
1358			perror_reply(425, "Can't build data connection");
1359			(void) close(pdata);
1360			(void) close(s);
1361			pdata = -1;
1362			return (NULL);
1363		}
1364		if (from.su_family != his_addr.su_family ||
1365		    ntohs(*p) < IPPORT_RESERVED) {
1366			perror_reply(425, "Can't build data connection");
1367			(void) close(pdata);
1368			(void) close(s);
1369			pdata = -1;
1370			return (NULL);
1371		}
1372		if (portcheck && memcmp(fa, ha, alen) != 0) {
1373			perror_reply(435, "Can't build data connection");
1374			(void) close(pdata);
1375			(void) close(s);
1376			pdata = -1;
1377			return (NULL);
1378		}
1379		(void) close(pdata);
1380		pdata = s;
1381		reply(150, "Opening %s mode data connection for '%s'%s.",
1382		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1383		return (fdopen(pdata, mode));
1384	}
1385	if (data >= 0) {
1386		reply(125, "Using existing data connection for '%s'%s.",
1387		    name, sizebuf);
1388		usedefault = 1;
1389		return (fdopen(data, mode));
1390	}
1391	if (usedefault)
1392		data_dest = his_addr;
1393	usedefault = 1;
1394	file = getdatasock(mode);
1395	if (file == NULL) {
1396		char hbuf[MAXHOSTNAMELEN], pbuf[10];
1397
1398		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1399		    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1400		    NI_NUMERICHOST | NI_NUMERICSERV);
1401		reply(425, "Can't create data socket (%s,%s): %s.",
1402		    hbuf, pbuf, strerror(errno));
1403		return (NULL);
1404	}
1405	data = fileno(file);
1406
1407	/*
1408	 * attempt to connect to reserved port on client machine;
1409	 * this looks like an attack
1410	 */
1411	switch (data_dest.su_family) {
1412	case AF_INET:
1413		p = (in_port_t *)&data_dest.su_sin.sin_port;
1414		fa = (u_char *)&data_dest.su_sin.sin_addr;
1415		ha = (u_char *)&his_addr.su_sin.sin_addr;
1416		alen = sizeof(struct in_addr);
1417		break;
1418	case AF_INET6:
1419		p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1420		fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1421		ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1422		alen = sizeof(struct in6_addr);
1423		break;
1424	default:
1425		perror_reply(425, "Can't build data connection");
1426		(void) fclose(file);
1427		pdata = -1;
1428		return (NULL);
1429	}
1430	if (data_dest.su_family != his_addr.su_family ||
1431	    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) {	/* XXX */
1432		perror_reply(425, "Can't build data connection");
1433		(void) fclose(file);
1434		data = -1;
1435		return NULL;
1436	}
1437	if (portcheck && memcmp(fa, ha, alen) != 0) {
1438		perror_reply(435, "Can't build data connection");
1439		(void) fclose(file);
1440		data = -1;
1441		return NULL;
1442	}
1443	while (connect(data, (struct sockaddr *)&data_dest,
1444	    data_dest.su_len) < 0) {
1445		if (errno == EADDRINUSE && retry < swaitmax) {
1446			sleep((unsigned) swaitint);
1447			retry += swaitint;
1448			continue;
1449		}
1450		perror_reply(425, "Can't build data connection");
1451		(void) fclose(file);
1452		data = -1;
1453		return (NULL);
1454	}
1455	reply(150, "Opening %s mode data connection for '%s'%s.",
1456	    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1457	return (file);
1458}
1459
1460/*
1461 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1462 * encapsulation of the data subject to Mode, Structure, and Type.
1463 *
1464 * NB: Form isn't handled.
1465 */
1466static void
1467send_data(instr, outstr, blksize, filesize, isreg)
1468	FILE *instr, *outstr;
1469	off_t blksize;
1470	off_t filesize;
1471	int isreg;
1472{
1473	int c, cnt, filefd, netfd;
1474	char *buf, *bp;
1475	size_t len;
1476
1477	transflag++;
1478	if (setjmp(urgcatch)) {
1479		transflag = 0;
1480		return;
1481	}
1482	switch (type) {
1483
1484	case TYPE_A:
1485		while ((c = getc(instr)) != EOF) {
1486			byte_count++;
1487			if (c == '\n') {
1488				if (ferror(outstr))
1489					goto data_err;
1490				(void) putc('\r', outstr);
1491			}
1492			(void) putc(c, outstr);
1493		}
1494		fflush(outstr);
1495		transflag = 0;
1496		if (ferror(instr))
1497			goto file_err;
1498		if (ferror(outstr))
1499			goto data_err;
1500		reply(226, "Transfer complete.");
1501		return;
1502
1503	case TYPE_I:
1504	case TYPE_L:
1505		/*
1506		 * isreg is only set if we are not doing restart and we
1507		 * are sending a regular file
1508		 */
1509		netfd = fileno(outstr);
1510		filefd = fileno(instr);
1511
1512		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1513			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1514				   (off_t)0);
1515			if (!buf) {
1516				syslog(LOG_WARNING, "mmap(%lu): %m",
1517				    (unsigned long)filesize);
1518				goto oldway;
1519			}
1520			bp = buf;
1521			len = filesize;
1522			do {
1523				cnt = write(netfd, bp, len);
1524				len -= cnt;
1525				bp += cnt;
1526				if (cnt > 0) byte_count += cnt;
1527			} while(cnt > 0 && len > 0);
1528
1529			transflag = 0;
1530			munmap(buf, (size_t)filesize);
1531			if (cnt < 0)
1532				goto data_err;
1533			reply(226, "Transfer complete.");
1534			return;
1535		}
1536
1537oldway:
1538		if ((buf = malloc((u_int)blksize)) == NULL) {
1539			transflag = 0;
1540			perror_reply(451, "Local resource failure: malloc");
1541			return;
1542		}
1543
1544		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1545		    write(netfd, buf, cnt) == cnt)
1546			byte_count += cnt;
1547		transflag = 0;
1548		(void)free(buf);
1549		if (cnt != 0) {
1550			if (cnt < 0)
1551				goto file_err;
1552			goto data_err;
1553		}
1554		reply(226, "Transfer complete.");
1555		return;
1556	default:
1557		transflag = 0;
1558		reply(550, "Unimplemented TYPE %d in send_data", type);
1559		return;
1560	}
1561
1562data_err:
1563	transflag = 0;
1564	perror_reply(426, "Data connection");
1565	return;
1566
1567file_err:
1568	transflag = 0;
1569	perror_reply(551, "Error on input file");
1570}
1571
1572/*
1573 * Transfer data from peer to "outstr" using the appropriate encapulation of
1574 * the data subject to Mode, Structure, and Type.
1575 *
1576 * N.B.: Form isn't handled.
1577 */
1578static int
1579receive_data(instr, outstr)
1580	FILE *instr, *outstr;
1581{
1582	int c;
1583	int cnt, bare_lfs = 0;
1584	char buf[BUFSIZ];
1585
1586	transflag++;
1587	if (setjmp(urgcatch)) {
1588		transflag = 0;
1589		return (-1);
1590	}
1591	switch (type) {
1592
1593	case TYPE_I:
1594	case TYPE_L:
1595		signal (SIGALRM, lostconn);
1596
1597		do {
1598			(void) alarm ((unsigned) timeout);
1599			cnt = read(fileno(instr), buf, sizeof(buf));
1600			(void) alarm (0);
1601
1602			if (cnt > 0) {
1603				if (write(fileno(outstr), buf, cnt) != cnt)
1604					goto file_err;
1605				byte_count += cnt;
1606			}
1607		} while (cnt > 0);
1608		if (cnt < 0)
1609			goto data_err;
1610		transflag = 0;
1611		return (0);
1612
1613	case TYPE_E:
1614		reply(553, "TYPE E not implemented.");
1615		transflag = 0;
1616		return (-1);
1617
1618	case TYPE_A:
1619		while ((c = getc(instr)) != EOF) {
1620			byte_count++;
1621			if (c == '\n')
1622				bare_lfs++;
1623			while (c == '\r') {
1624				if (ferror(outstr))
1625					goto data_err;
1626				if ((c = getc(instr)) != '\n') {
1627					(void) putc ('\r', outstr);
1628					if (c == '\0' || c == EOF)
1629						goto contin2;
1630				}
1631			}
1632			(void) putc(c, outstr);
1633	contin2:	;
1634		}
1635		fflush(outstr);
1636		if (ferror(instr))
1637			goto data_err;
1638		if (ferror(outstr))
1639			goto file_err;
1640		transflag = 0;
1641		if (bare_lfs) {
1642			lreply(226,
1643			    "WARNING! %d bare linefeeds received in ASCII mode",
1644			    bare_lfs);
1645			printf("   File may not have transferred correctly.\r\n");
1646		}
1647		return (0);
1648	default:
1649		reply(550, "Unimplemented TYPE %d in receive_data", type);
1650		transflag = 0;
1651		return (-1);
1652	}
1653
1654data_err:
1655	transflag = 0;
1656	perror_reply(426, "Data Connection");
1657	return (-1);
1658
1659file_err:
1660	transflag = 0;
1661	perror_reply(452, "Error writing file");
1662	return (-1);
1663}
1664
1665void
1666statfilecmd(filename)
1667	char *filename;
1668{
1669	FILE *fin;
1670	int c;
1671	int atstart;
1672	char line[LINE_MAX];
1673
1674	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1675	fin = ftpd_popen(line, "r");
1676	lreply(211, "status of %s:", filename);
1677	atstart = 1;
1678	while ((c = getc(fin)) != EOF) {
1679		if (c == '\n') {
1680			if (ferror(stdout)){
1681				perror_reply(421, "control connection");
1682				(void) ftpd_pclose(fin);
1683				dologout(1);
1684				/* NOTREACHED */
1685			}
1686			if (ferror(fin)) {
1687				perror_reply(551, filename);
1688				(void) ftpd_pclose(fin);
1689				return;
1690			}
1691			(void) putc('\r', stdout);
1692		}
1693		if (atstart && isdigit(c))
1694			(void) putc(' ', stdout);
1695		(void) putc(c, stdout);
1696		atstart = (c == '\n');
1697	}
1698	(void) ftpd_pclose(fin);
1699	reply(211, "End of Status");
1700}
1701
1702void
1703statcmd()
1704{
1705	union sockunion *su;
1706	u_char *a, *p;
1707	char hbuf[MAXHOSTNAMELEN];
1708	int ispassive;
1709
1710	lreply(211, "%s FTP server status:", hostname, version);
1711	printf("     %s\r\n", version);
1712	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1713	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1714	printf("     Connected to %s", remotehost);
1715	if (strcmp(remotehost, hbuf) != 0)
1716		printf(" (%s)", hbuf);
1717	printf("\r\n");
1718	if (logged_in) {
1719		if (guest)
1720			printf("     Logged in anonymously\r\n");
1721		else
1722			printf("     Logged in as %s\r\n", pw->pw_name);
1723	} else if (askpasswd)
1724		printf("     Waiting for password\r\n");
1725	else
1726		printf("     Waiting for user name\r\n");
1727	printf("     TYPE: %s", typenames[type]);
1728	if (type == TYPE_A || type == TYPE_E)
1729		printf(", FORM: %s", formnames[form]);
1730	if (type == TYPE_L)
1731#if NBBY == 8
1732		printf(" %d", NBBY);
1733#else
1734		printf(" %d", bytesize);	/* need definition! */
1735#endif
1736	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1737	    strunames[stru], modenames[mode]);
1738	ispassive = 0;
1739	if (data != -1)
1740		printf("     Data connection open\r\n");
1741	else if (pdata != -1) {
1742		printf("     in Passive mode\r\n");
1743		su = (union sockunion *)&pasv_addr;
1744		ispassive++;
1745		goto printaddr;
1746	} else if (usedefault == 0) {
1747		su = (union sockunion *)&data_dest;
1748printaddr:
1749		/* PASV/PORT */
1750		if (su->su_family == AF_INET) {
1751			if (ispassive)
1752				printf("211- PASV ");
1753			else
1754				printf("211- PORT ");
1755			a = (u_char *) &su->su_sin.sin_addr;
1756			p = (u_char *) &su->su_sin.sin_port;
1757			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1758			    a[0], a[1], a[2], a[3],
1759			    p[0], p[1]);
1760		}
1761
1762		/* LPSV/LPRT */
1763	    {
1764		int alen, af, i;
1765
1766		alen = 0;
1767		switch (su->su_family) {
1768		case AF_INET:
1769			a = (u_char *) &su->su_sin.sin_addr;
1770			p = (u_char *) &su->su_sin.sin_port;
1771			alen = sizeof(su->su_sin.sin_addr);
1772			af = 4;
1773			break;
1774		case AF_INET6:
1775			a = (u_char *) &su->su_sin6.sin6_addr;
1776			p = (u_char *) &su->su_sin6.sin6_port;
1777			alen = sizeof(su->su_sin6.sin6_addr);
1778			af = 6;
1779			break;
1780		default:
1781			af = 0;
1782			break;
1783		}
1784		if (af) {
1785			if (ispassive)
1786				printf("211- LPSV ");
1787			else
1788				printf("211- LPRT ");
1789			printf("(%u,%u", af, alen);
1790			for (i = 0; i < alen; i++)
1791				printf(",%u", a[i]);
1792			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1793		}
1794	    }
1795
1796		/* EPRT/EPSV */
1797epsvonly:
1798	    {
1799		u_char af;
1800
1801		switch (su->su_family) {
1802		case AF_INET:
1803			af = 1;
1804			break;
1805		case AF_INET6:
1806			af = 2;
1807			break;
1808		default:
1809			af = 0;
1810			break;
1811		}
1812		if (af) {
1813			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1814			if (getnameinfo((struct sockaddr *)su, su->su_len,
1815			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1816			    NI_NUMERICHOST) == 0) {
1817				if (ispassive)
1818					printf("211- EPSV ");
1819				else
1820					printf("211- EPRT ");
1821				printf("(|%u|%s|%s|)\r\n",
1822					af, hbuf, pbuf);
1823			}
1824		}
1825	    }
1826	} else
1827		printf("     No data connection\r\n");
1828	reply(211, "End of status");
1829}
1830
1831void
1832fatal(s)
1833	char *s;
1834{
1835
1836	reply(451, "Error in server: %s\n", s);
1837	reply(221, "Closing connection due to server error.");
1838	dologout(0);
1839	/* NOTREACHED */
1840}
1841
1842void
1843#ifdef __STDC__
1844reply(int n, const char *fmt, ...)
1845#else
1846reply(n, fmt, va_alist)
1847	int n;
1848	char *fmt;
1849	va_dcl
1850#endif
1851{
1852	va_list ap;
1853#ifdef __STDC__
1854	va_start(ap, fmt);
1855#else
1856	va_start(ap);
1857#endif
1858	(void)printf("%d ", n);
1859	(void)vprintf(fmt, ap);
1860	(void)printf("\r\n");
1861	(void)fflush(stdout);
1862	if (debug) {
1863		syslog(LOG_DEBUG, "<--- %d ", n);
1864		vsyslog(LOG_DEBUG, fmt, ap);
1865	}
1866}
1867
1868void
1869#ifdef __STDC__
1870lreply(int n, const char *fmt, ...)
1871#else
1872lreply(n, fmt, va_alist)
1873	int n;
1874	char *fmt;
1875	va_dcl
1876#endif
1877{
1878	va_list ap;
1879#ifdef __STDC__
1880	va_start(ap, fmt);
1881#else
1882	va_start(ap);
1883#endif
1884	(void)printf("%d- ", n);
1885	(void)vprintf(fmt, ap);
1886	(void)printf("\r\n");
1887	(void)fflush(stdout);
1888	if (debug) {
1889		syslog(LOG_DEBUG, "<--- %d- ", n);
1890		vsyslog(LOG_DEBUG, fmt, ap);
1891	}
1892}
1893
1894static void
1895ack(s)
1896	char *s;
1897{
1898
1899	reply(250, "%s command successful.", s);
1900}
1901
1902void
1903nack(s)
1904	char *s;
1905{
1906
1907	reply(502, "%s command not implemented.", s);
1908}
1909
1910/* ARGSUSED */
1911void
1912yyerror(s)
1913	char *s;
1914{
1915	char *cp;
1916
1917	if ((cp = strchr(cbuf,'\n')))
1918		*cp = '\0';
1919	reply(500, "'%s': command not understood.", cbuf);
1920}
1921
1922void
1923delete(name)
1924	char *name;
1925{
1926	struct stat st;
1927
1928	LOGCMD("delete", name);
1929	if (stat(name, &st) < 0) {
1930		perror_reply(550, name);
1931		return;
1932	}
1933	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1934		if (rmdir(name) < 0) {
1935			perror_reply(550, name);
1936			return;
1937		}
1938		goto done;
1939	}
1940	if (unlink(name) < 0) {
1941		perror_reply(550, name);
1942		return;
1943	}
1944done:
1945	ack("DELE");
1946}
1947
1948void
1949cwd(path)
1950	char *path;
1951{
1952	FILE *message;
1953
1954	if (chdir(path) < 0)
1955		perror_reply(550, path);
1956	else {
1957		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
1958			char *cp, line[LINE_MAX];
1959
1960			while (fgets(line, sizeof(line), message) != NULL) {
1961				if ((cp = strchr(line, '\n')) != NULL)
1962					*cp = '\0';
1963				lreply(250, "%s", line);
1964			}
1965			(void) fflush(stdout);
1966			(void) fclose(message);
1967		}
1968		ack("CWD");
1969	}
1970}
1971
1972void
1973replydirname(name, message)
1974	const char *name, *message;
1975{
1976	char *p, *ep;
1977	char npath[MAXPATHLEN];
1978
1979	p = npath;
1980	ep = &npath[sizeof(npath) - 1];
1981	while (*name) {
1982		if (*name == '"') {
1983			if (ep - p < 2)
1984				break;
1985			*p++ = *name++;
1986			*p++ = '"';
1987		} else {
1988			if (ep - p < 1)
1989				break;
1990			*p++ = *name++;
1991		}
1992	}
1993	*p = '\0';
1994	reply(257, "\"%s\" %s", npath, message);
1995}
1996
1997void
1998makedir(name)
1999	char *name;
2000{
2001
2002	LOGCMD("mkdir", name);
2003	if (mkdir(name, 0777) < 0)
2004		perror_reply(550, name);
2005	else
2006		replydirname(name, "directory created.");
2007}
2008
2009void
2010removedir(name)
2011	char *name;
2012{
2013
2014	LOGCMD("rmdir", name);
2015	if (rmdir(name) < 0)
2016		perror_reply(550, name);
2017	else
2018		ack("RMD");
2019}
2020
2021void
2022pwd()
2023{
2024	char path[MAXPATHLEN];
2025
2026	if (getcwd(path, sizeof path) == (char *)NULL)
2027		reply(550, "Can't get current directory: %s.", strerror(errno));
2028	else
2029		replydirname(path, "is current directory.");
2030}
2031
2032char *
2033renamefrom(name)
2034	char *name;
2035{
2036	struct stat st;
2037
2038	if (stat(name, &st) < 0) {
2039		perror_reply(550, name);
2040		return ((char *)0);
2041	}
2042	reply(350, "File exists, ready for destination name");
2043	return (name);
2044}
2045
2046void
2047renamecmd(from, to)
2048	char *from, *to;
2049{
2050
2051	LOGCMD2("rename", from, to);
2052	if (rename(from, to) < 0)
2053		perror_reply(550, "rename");
2054	else
2055		ack("RNTO");
2056}
2057
2058static void
2059dolog(sa)
2060	struct sockaddr *sa;
2061{
2062	char hbuf[sizeof(remotehost)];
2063
2064	getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0);
2065	(void) strncpy(remotehost, hbuf, sizeof(remotehost)-1);
2066
2067	remotehost[sizeof(remotehost)-1] = '\0';
2068#ifdef HASSETPROCTITLE
2069	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2070	setproctitle("%s", proctitle);
2071#endif /* HASSETPROCTITLE */
2072
2073	if (logging)
2074		syslog(LOG_INFO, "connection from %s", remotehost);
2075}
2076
2077/*
2078 * Record logout in wtmp file
2079 * and exit with supplied status.
2080 */
2081void
2082dologout(status)
2083	int status;
2084{
2085	sigset_t allsigs;
2086
2087	transflag = 0;
2088
2089	if (logged_in) {
2090		sigfillset(&allsigs);
2091		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2092		(void) seteuid((uid_t)0);
2093		ftpdlogwtmp(ttyline, "", "");
2094		if (doutmp)
2095			logout(utmp.ut_line);
2096#if defined(KERBEROS)
2097		if (!notickets && krbtkfile_env)
2098			unlink(krbtkfile_env);
2099#endif
2100	}
2101	/* beware of flushing buffers after a SIGPIPE */
2102	_exit(status);
2103}
2104
2105static void
2106myoob(signo)
2107	int signo;
2108{
2109	char *cp;
2110	int save_errno = errno;
2111
2112	/* only process if transfer occurring */
2113	if (!transflag)
2114		return;
2115	cp = tmpline;
2116	if (getline(cp, 7, stdin) == NULL) {
2117		reply(221, "You could at least say goodbye.");
2118		dologout(0);
2119	}
2120	upper(cp);
2121	if (strcmp(cp, "ABOR\r\n") == 0) {
2122		tmpline[0] = '\0';
2123		reply(426, "Transfer aborted. Data connection closed.");
2124		reply(226, "Abort successful");
2125		longjmp(urgcatch, 1);
2126	}
2127	if (strcmp(cp, "STAT\r\n") == 0) {
2128		tmpline[0] = '\0';
2129		if (file_size != (off_t) -1)
2130			reply(213, "Status: %qd of %qd bytes transferred",
2131			    byte_count, file_size);
2132		else
2133			reply(213, "Status: %qd bytes transferred", byte_count);
2134	}
2135	errno = save_errno;
2136}
2137
2138/*
2139 * Note: a response of 425 is not mentioned as a possible response to
2140 *	the PASV command in RFC959. However, it has been blessed as
2141 *	a legitimate response by Jon Postel in a telephone conversation
2142 *	with Rick Adams on 25 Jan 89.
2143 */
2144void
2145passive()
2146{
2147	int len, on;
2148	u_char *p, *a;
2149
2150	if (pw == NULL) {
2151		reply(530, "Please login with USER and PASS");
2152		return;
2153	}
2154	if (pdata >= 0)
2155		close(pdata);
2156	/*
2157	 * XXX
2158	 * At this point, it would be nice to have an algorithm that
2159	 * inserted a growing delay in an attack scenario.  Such a thing
2160	 * would look like continual passive sockets being opened, but
2161	 * nothing serious being done with them.  They're not used to
2162	 * move data; the entire attempt is just to use tcp FIN_WAIT
2163	 * resources.
2164	 */
2165	pdata = socket(AF_INET, SOCK_STREAM, 0);
2166	if (pdata < 0) {
2167		perror_reply(425, "Can't open passive connection");
2168		return;
2169	}
2170
2171#ifdef IP_PORTRANGE
2172	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2173	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2174	    (char *)&on, sizeof(on)) < 0)
2175		goto pasv_error;
2176#endif
2177
2178	pasv_addr = ctrl_addr;
2179	pasv_addr.su_sin.sin_port = 0;
2180	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2181		 pasv_addr.su_len) < 0)
2182		goto pasv_error;
2183
2184	len = sizeof(pasv_addr);
2185	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2186		goto pasv_error;
2187	if (listen(pdata, 1) < 0)
2188		goto pasv_error;
2189	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2190	p = (u_char *) &pasv_addr.su_sin.sin_port;
2191
2192	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2193	    a[1], a[2], a[3], p[0], p[1]);
2194	return;
2195
2196pasv_error:
2197	(void) seteuid((uid_t)pw->pw_uid);
2198	(void) close(pdata);
2199	pdata = -1;
2200	perror_reply(425, "Can't open passive connection");
2201	return;
2202}
2203
2204/*
2205 * convert protocol identifier to/from AF
2206 */
2207int
2208lpsvproto2af(int proto)
2209{
2210
2211	switch (proto) {
2212	case 4:	return AF_INET;
2213#ifdef INET6
2214	case 6:	return AF_INET6;
2215#endif
2216	default: return -1;
2217	}
2218}
2219
2220int
2221af2lpsvproto(int af)
2222{
2223
2224	switch (af) {
2225	case AF_INET:	return 4;
2226#ifdef INET6
2227	case AF_INET6:	return 6;
2228#endif
2229	default:	return -1;
2230	}
2231}
2232
2233int
2234epsvproto2af(int proto)
2235{
2236
2237	switch (proto) {
2238	case 1:	return AF_INET;
2239#ifdef INET6
2240	case 2:	return AF_INET6;
2241#endif
2242	default: return -1;
2243	}
2244}
2245
2246int
2247af2epsvproto(int af)
2248{
2249
2250	switch (af) {
2251	case AF_INET:	return 1;
2252#ifdef INET6
2253	case AF_INET6:	return 2;
2254#endif
2255	default:	return -1;
2256	}
2257}
2258
2259/*
2260 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2261 * 229 Entering Extended Passive Mode (|||port|)
2262 */
2263void
2264long_passive(char *cmd, int pf)
2265{
2266	int len, on;
2267	register u_char *p, *a;
2268
2269	if (!logged_in) {
2270		syslog(LOG_NOTICE, "long passive but not logged in");
2271		reply(503, "Login with USER first.");
2272		return;
2273	}
2274
2275	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2276		/*
2277		 * XXX
2278		 * only EPRT/EPSV ready clients will understand this
2279		 */
2280		if (strcmp(cmd, "EPSV") != 0)
2281			reply(501, "Network protocol mismatch"); /*XXX*/
2282		else
2283			epsv_protounsupp("Network protocol mismatch");
2284
2285		return;
2286	}
2287
2288	if (pdata >= 0)
2289		close(pdata);
2290	/*
2291	 * XXX
2292	 * At this point, it would be nice to have an algorithm that
2293	 * inserted a growing delay in an attack scenario.  Such a thing
2294	 * would look like continual passive sockets being opened, but
2295	 * nothing serious being done with them.  They not used to move
2296	 * data; the entire attempt is just to use tcp FIN_WAIT
2297	 * resources.
2298	 */
2299	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2300	if (pdata < 0) {
2301		perror_reply(425, "Can't open passive connection");
2302		return;
2303	}
2304
2305	switch (ctrl_addr.su_family) {
2306	case AF_INET:
2307#ifdef IP_PORTRANGE
2308		on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
2309		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2310		    (char *)&on, sizeof(on)) < 0)
2311			goto pasv_error;
2312#endif
2313		break;
2314	case AF_INET6:
2315#ifdef IPV6_PORTRANGE
2316		on = high_data_ports ? IPV6_PORTRANGE_HIGH
2317				     : IPV6_PORTRANGE_DEFAULT;
2318		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2319		    (char *)&on, sizeof(on)) < 0)
2320			goto pasv_error;
2321#endif
2322		break;
2323	}
2324
2325	pasv_addr = ctrl_addr;
2326	pasv_addr.su_port = 0;
2327	(void) seteuid((uid_t) 0);
2328	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2329		(void) seteuid((uid_t) pw->pw_uid);
2330		goto pasv_error;
2331	}
2332	(void) seteuid((uid_t) pw->pw_uid);
2333	len = pasv_addr.su_len;
2334	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2335		goto pasv_error;
2336	if (listen(pdata, 1) < 0)
2337		goto pasv_error;
2338	p = (u_char *) &pasv_addr.su_port;
2339
2340	if (strcmp(cmd, "LPSV") == 0) {
2341		switch (pasv_addr.su_family) {
2342		case AF_INET:
2343			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2344			reply(228,
2345			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2346			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2347			return;
2348		case AF_INET6:
2349			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2350			reply(228,
2351			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2352			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2353				6, 16, a[0], a[1], a[2], a[3], a[4],
2354				a[5], a[6], a[7], a[8], a[9], a[10],
2355				a[11], a[12], a[13], a[14], a[15],
2356				2, p[0], p[1]);
2357			return;
2358		}
2359	} else if (strcmp(cmd, "EPSV") == 0) {
2360		switch (pasv_addr.su_family) {
2361		case AF_INET:
2362		case AF_INET6:
2363			reply(229, "Entering Extended Passive Mode (|||%u|)",
2364			    ntohs(pasv_addr.su_port));
2365			return;
2366		}
2367	} else {
2368		/* more proper error code? */
2369	}
2370
2371  pasv_error:
2372	(void) close(pdata);
2373	pdata = -1;
2374	perror_reply(425, "Can't open passive connection");
2375	return;
2376}
2377
2378/*
2379 * EPRT |proto|addr|port|
2380 */
2381int
2382extended_port(const char *arg)
2383{
2384	char *tmp = NULL;
2385	char *result[3];
2386	char *p, *q;
2387	char delim;
2388	struct addrinfo hints;
2389	struct addrinfo *res = NULL;
2390	int i;
2391	unsigned long proto;
2392
2393	if (epsvall) {
2394		reply(501, "EPRT disallowed after EPSV ALL");
2395		return -1;
2396	}
2397
2398	usedefault = 0;
2399	if (pdata >= 0) {
2400		(void) close(pdata);
2401		pdata = -1;
2402	}
2403
2404	tmp = strdup(arg);
2405	if (!tmp) {
2406		fatal("not enough core.");
2407		/*NOTREACHED*/
2408	}
2409	p = tmp;
2410	delim = p[0];
2411	p++;
2412	memset(result, 0, sizeof(result));
2413	for (i = 0; i < 3; i++) {
2414		q = strchr(p, delim);
2415		if (!q || *q != delim)
2416			goto parsefail;
2417		*q++ = '\0';
2418		result[i] = p;
2419		p = q;
2420	}
2421
2422	/* some more sanity check */
2423	p = NULL;
2424	(void)strtoul(result[2], &p, 10);
2425	if (!*result[2] || *p)
2426		goto protounsupp;
2427	p = NULL;
2428	proto = strtoul(result[0], &p, 10);
2429	if (!*result[0] || *p)
2430		goto protounsupp;
2431
2432	memset(&hints, 0, sizeof(hints));
2433	hints.ai_family = epsvproto2af((int)proto);
2434	if (hints.ai_family < 0)
2435		goto protounsupp;
2436	hints.ai_socktype = SOCK_STREAM;
2437	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2438	if (getaddrinfo(result[1], result[2], &hints, &res))
2439		goto parsefail;
2440	if (res->ai_next)
2441		goto parsefail;
2442	if (sizeof(data_dest) < res->ai_addrlen)
2443		goto parsefail;
2444	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2445	if (his_addr.su_family == AF_INET6 &&
2446	    data_dest.su_family == AF_INET6) {
2447		/* XXX more sanity checks! */
2448		data_dest.su_sin6.sin6_scope_id =
2449		    his_addr.su_sin6.sin6_scope_id;
2450	}
2451	if (pdata >= 0) {
2452		(void) close(pdata);
2453		pdata = -1;
2454	}
2455	reply(200, "EPRT command successful.");
2456
2457	if (tmp)
2458		free(tmp);
2459	if (res)
2460		freeaddrinfo(res);
2461	return 0;
2462
2463parsefail:
2464	reply(500, "Invalid argument, rejected.");
2465	usedefault = 1;
2466	if (tmp)
2467		free(tmp);
2468	if (res)
2469		freeaddrinfo(res);
2470	return -1;
2471
2472protounsupp:
2473	epsv_protounsupp("Protocol not supported");
2474	usedefault = 1;
2475	if (tmp)
2476		free(tmp);
2477	if (res)
2478		freeaddrinfo(res);
2479	return -1;
2480}
2481
2482/*
2483 * 522 Protocol not supported (proto,...)
2484 * as we assume address family for control and data connections are the same,
2485 * we do not return the list of address families we support - instead, we
2486 * return the address family of the control connection.
2487 */
2488void
2489epsv_protounsupp(const char *message)
2490{
2491	int proto;
2492
2493	proto = af2epsvproto(ctrl_addr.su_family);
2494	if (proto < 0)
2495		reply(501, "%s", message);	/*XXX*/
2496	else
2497		reply(522, "%s, use (%d)", message, proto);
2498}
2499
2500/*
2501 * Generate unique name for file with basename "local".
2502 * The file named "local" is already known to exist.
2503 * Generates failure reply on error.
2504 */
2505static int
2506guniquefd(local, nam)
2507	char *local;
2508	char **nam;
2509{
2510	static char new[MAXPATHLEN];
2511	struct stat st;
2512	int count, len, fd;
2513	char *cp;
2514
2515	cp = strrchr(local, '/');
2516	if (cp)
2517		*cp = '\0';
2518	if (stat(cp ? local : ".", &st) < 0) {
2519		perror_reply(553, cp ? local : ".");
2520		return (-1);
2521	}
2522	if (cp)
2523		*cp = '/';
2524	(void) strncpy(new, local, sizeof(new)-1);
2525	new[sizeof(new)-1] = '\0';
2526	len = strlen(new);
2527	if (len+2+1 >= sizeof(new)-1)
2528		return (-1);
2529	cp = new + len;
2530	*cp++ = '.';
2531	for (count = 1; count < 100; count++) {
2532		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2533		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2534		if (fd == -1)
2535			continue;
2536		if (nam)
2537			*nam = new;
2538		return (fd);
2539	}
2540	reply(452, "Unique file name cannot be created.");
2541	return (-1);
2542}
2543
2544/*
2545 * Format and send reply containing system error number.
2546 */
2547void
2548perror_reply(code, string)
2549	int code;
2550	char *string;
2551{
2552
2553	reply(code, "%s: %s.", string, strerror(errno));
2554}
2555
2556static char *onefile[] = {
2557	"",
2558	0
2559};
2560
2561void
2562send_file_list(whichf)
2563	char *whichf;
2564{
2565	struct stat st;
2566	DIR *dirp = NULL;
2567	struct dirent *dir;
2568	FILE *dout = NULL;
2569	char **dirlist, *dirname;
2570	int simple = 0;
2571	int freeglob = 0;
2572	glob_t gl;
2573
2574	if (strpbrk(whichf, "~{[*?") != NULL) {
2575		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2576
2577		memset(&gl, 0, sizeof(gl));
2578		freeglob = 1;
2579		if (glob(whichf, flags, 0, &gl)) {
2580			reply(550, "not found");
2581			goto out;
2582		} else if (gl.gl_pathc == 0) {
2583			errno = ENOENT;
2584			perror_reply(550, whichf);
2585			goto out;
2586		}
2587		dirlist = gl.gl_pathv;
2588	} else {
2589		onefile[0] = whichf;
2590		dirlist = onefile;
2591		simple = 1;
2592	}
2593
2594	if (setjmp(urgcatch)) {
2595		transflag = 0;
2596		goto out;
2597	}
2598	while ((dirname = *dirlist++)) {
2599		if (stat(dirname, &st) < 0) {
2600			/*
2601			 * If user typed "ls -l", etc, and the client
2602			 * used NLST, do what the user meant.
2603			 */
2604			if (dirname[0] == '-' && *dirlist == NULL &&
2605			    transflag == 0) {
2606				retrieve("/bin/ls %s", dirname);
2607				goto out;
2608			}
2609			perror_reply(550, whichf);
2610			if (dout != NULL) {
2611				(void) fclose(dout);
2612				transflag = 0;
2613				data = -1;
2614				pdata = -1;
2615			}
2616			goto out;
2617		}
2618
2619		if (S_ISREG(st.st_mode)) {
2620			if (dout == NULL) {
2621				dout = dataconn("file list", (off_t)-1, "w");
2622				if (dout == NULL)
2623					goto out;
2624				transflag++;
2625			}
2626			fprintf(dout, "%s%s\n", dirname,
2627				type == TYPE_A ? "\r" : "");
2628			byte_count += strlen(dirname) + 1;
2629			continue;
2630		} else if (!S_ISDIR(st.st_mode))
2631			continue;
2632
2633		if ((dirp = opendir(dirname)) == NULL)
2634			continue;
2635
2636		while ((dir = readdir(dirp)) != NULL) {
2637			char nbuf[MAXPATHLEN];
2638
2639			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2640				continue;
2641			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2642			    dir->d_namlen == 2)
2643				continue;
2644
2645			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2646				 dir->d_name);
2647
2648			/*
2649			 * We have to do a stat to insure it's
2650			 * not a directory or special file.
2651			 */
2652			if (simple || (stat(nbuf, &st) == 0 &&
2653			    S_ISREG(st.st_mode))) {
2654				if (dout == NULL) {
2655					dout = dataconn("file list", (off_t)-1,
2656						"w");
2657					if (dout == NULL)
2658						goto out;
2659					transflag++;
2660				}
2661				if (nbuf[0] == '.' && nbuf[1] == '/')
2662					fprintf(dout, "%s%s\n", &nbuf[2],
2663						type == TYPE_A ? "\r" : "");
2664				else
2665					fprintf(dout, "%s%s\n", nbuf,
2666						type == TYPE_A ? "\r" : "");
2667				byte_count += strlen(nbuf) + 1;
2668			}
2669		}
2670		(void) closedir(dirp);
2671	}
2672
2673	if (dout == NULL)
2674		reply(550, "No files found.");
2675	else if (ferror(dout) != 0)
2676		perror_reply(550, "Data connection");
2677	else
2678		reply(226, "Transfer complete.");
2679
2680	transflag = 0;
2681	if (dout != NULL)
2682		(void) fclose(dout);
2683	else {
2684		if (pdata >= 0)
2685			close(pdata);
2686	}
2687	data = -1;
2688	pdata = -1;
2689out:
2690	if (freeglob) {
2691		freeglob = 0;
2692		globfree(&gl);
2693	}
2694}
2695
2696static void
2697reapchild(signo)
2698	int signo;
2699{
2700	int save_errno = errno;
2701
2702	while (wait3(NULL, WNOHANG, NULL) > 0)
2703		;
2704	errno = save_errno;
2705}
2706
2707void
2708logxfer(name, size, start)
2709	char *name;
2710	off_t size;
2711	time_t start;
2712{
2713	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2714	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2715	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2716	char *vpw;
2717	time_t now;
2718
2719	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2720		time(&now);
2721
2722		vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1);
2723		if (vpw == NULL)
2724			return;
2725
2726		snprintf(path, sizeof path, "%s/%s", dir, name);
2727		if (realpath(path, rpath) == NULL) {
2728			strncpy(rpath, path, sizeof rpath-1);
2729			rpath[sizeof rpath-1] = '\0';
2730		}
2731		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2732
2733		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2734		strvis(vpw, (guest) ? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2735
2736		snprintf(buf, sizeof(buf),
2737		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2738		    ctime(&now), now - start + (now == start),
2739		    vremotehost, (long long) size, vpath,
2740		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2741		    'o', ((guest) ? 'a' : 'r'),
2742		    vpw, 0 /* none yet */,
2743		    ((guest) ? "*" : pw->pw_name), dhostname);
2744		write(statfd, buf, strlen(buf));
2745		free(vpw);
2746	}
2747}
2748
2749#if defined(TCPWRAPPERS)
2750static int
2751check_host(sa)
2752	struct sockaddr *sa;
2753{
2754	struct sockaddr_in *sin;
2755	struct hostent *hp;
2756	char *addr;
2757
2758	if (sa->sa_family != AF_INET)
2759		return 1;	/*XXX*/
2760
2761	sin = (struct sockaddr_in *)sa;
2762	hp = gethostbyaddr((char *)&sin->sin_addr,
2763	    sizeof(struct in_addr), AF_INET);
2764	addr = inet_ntoa(sin->sin_addr);
2765	if (hp) {
2766		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2767			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2768			    hp->h_name, addr);
2769			return (0);
2770		}
2771	} else {
2772		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2773			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2774			return (0);
2775		}
2776	}
2777	return (1);
2778}
2779#endif	/* TCPWRAPPERS */
2780
2781/*
2782 * Allocate space and return a copy of the specified dir.
2783 * If 'dir' begins with a tilde (~), expand it.
2784 */
2785char *
2786copy_dir(dir, pw)
2787	char *dir;
2788	struct passwd *pw;
2789{
2790	char *cp;
2791	char *newdir;
2792	char *user = NULL;
2793	size_t dirsiz;
2794
2795	/* Nothing to expand */
2796	if (dir[0] !=  '~')
2797		return (strdup(dir));
2798
2799	/* "dir" is of form ~user/some/dir, lookup user. */
2800	if (dir[1] != '/' && dir[1] != '\0') {
2801		if ((cp = strchr(dir + 1, '/')) == NULL)
2802		    cp = dir + strlen(dir);
2803		if ((user = malloc(cp - dir)) == NULL)
2804			return (NULL);
2805		strlcpy(user, dir + 1, cp - dir);
2806
2807		/* Only do lookup if it is a different user. */
2808		if (strcmp(user, pw->pw_name) != 0) {
2809			if ((pw = getpwnam(user)) == NULL) {
2810				/* No such user, interpret literally */
2811				free(user);
2812				return(strdup(dir));
2813			}
2814		}
2815	}
2816
2817	/*
2818	 * If there is no directory separator (/) then it is just pw_dir.
2819	 * Otherwise, replace ~foo with  pw_dir.
2820	 */
2821	if ((cp = strchr(dir + 1, '/')) == NULL) {
2822		newdir = strdup(pw->pw_dir);
2823	} else {
2824		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2825		if ((newdir = malloc(dirsiz)) == NULL)
2826			return (NULL);
2827		strcpy(newdir, pw->pw_dir);
2828		strcat(newdir, cp);
2829	}
2830
2831	if (user)
2832		free(user);
2833	return(newdir);
2834}
2835