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