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