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