ftpd.c revision 1.20
1/*	$OpenBSD: ftpd.c,v 1.20 1996/09/22 09:49:58 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		free(save.pw_passwd);
533		free(save.pw_gecos);
534		free(save.pw_dir);
535		free(save.pw_shell);
536	}
537	save = *p;
538	save.pw_name = sgetsave(p->pw_name);
539	save.pw_passwd = sgetsave(p->pw_passwd);
540	save.pw_gecos = sgetsave(p->pw_gecos);
541	save.pw_dir = sgetsave(p->pw_dir);
542	save.pw_shell = sgetsave(p->pw_shell);
543	return (&save);
544}
545
546static int login_attempts;	/* number of failed login attempts */
547static int askpasswd;		/* had user command, ask for passwd */
548static char curname[16];	/* current USER name */
549
550/*
551 * USER command.
552 * Sets global passwd pointer pw if named account exists and is acceptable;
553 * sets askpasswd if a PASS command is expected.  If logged in previously,
554 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
555 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
556 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
557 * requesting login privileges.  Disallow anyone who does not have a standard
558 * shell as returned by getusershell().  Disallow anyone mentioned in the file
559 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
560 */
561void
562user(name)
563	char *name;
564{
565	char *cp, *shell;
566
567	if (logged_in) {
568		if (guest) {
569			reply(530, "Can't change user from guest login.");
570			return;
571		} else if (dochroot) {
572			reply(530, "Can't change user from chroot user.");
573			return;
574		}
575		end_login();
576	}
577
578	guest = 0;
579	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
580		if (checkuser(_PATH_FTPUSERS, "ftp") ||
581		    checkuser(_PATH_FTPUSERS, "anonymous"))
582			reply(530, "User %s access denied.", name);
583		else if ((pw = sgetpwnam("ftp")) != NULL) {
584			guest = 1;
585			askpasswd = 1;
586			reply(331,
587			    "Guest login ok, type your name as password.");
588		} else
589			reply(530, "User %s unknown.", name);
590		if (!askpasswd && logging)
591			syslog(LOG_NOTICE,
592			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
593		return;
594	}
595	if (pw = sgetpwnam(name)) {
596		if ((shell = pw->pw_shell) == NULL || *shell == 0)
597			shell = _PATH_BSHELL;
598		while ((cp = getusershell()) != NULL)
599			if (strcmp(cp, shell) == 0)
600				break;
601		endusershell();
602
603		if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
604			reply(530, "User %s access denied.", name);
605			if (logging)
606				syslog(LOG_NOTICE,
607				    "FTP LOGIN REFUSED FROM %s, %s",
608				    remotehost, name);
609			pw = (struct passwd *) NULL;
610			return;
611		}
612	}
613	if (logging) {
614		strncpy(curname, name, sizeof(curname)-1);
615		curname[sizeof(curname)-1] = '\0';
616	}
617#ifdef SKEY
618	if (!skey_haskey(name)) {
619		char *myskey, *skey_keyinfo __P((char *name));
620
621		myskey = skey_keyinfo(name);
622		reply(331, "Password [%s] for %s required.",
623		    myskey ? myskey : "error getting challenge", name);
624	} else
625#endif
626		reply(331, "Password required for %s.", name);
627
628	askpasswd = 1;
629	/*
630	 * Delay before reading passwd after first failed
631	 * attempt to slow down passwd-guessing programs.
632	 */
633	if (login_attempts)
634		sleep((unsigned) login_attempts);
635}
636
637/*
638 * Check if a user is in the file "fname"
639 */
640static int
641checkuser(fname, name)
642	char *fname;
643	char *name;
644{
645	FILE *fd;
646	int found = 0;
647	char *p, line[BUFSIZ];
648
649	if ((fd = fopen(fname, "r")) != NULL) {
650		while (fgets(line, sizeof(line), fd) != NULL)
651			if ((p = strchr(line, '\n')) != NULL) {
652				*p = '\0';
653				if (line[0] == '#')
654					continue;
655				if (strcmp(line, name) == 0) {
656					found = 1;
657					break;
658				}
659			}
660		(void) fclose(fd);
661	}
662	return (found);
663}
664
665/*
666 * Terminate login as previous user, if any, resetting state;
667 * used when USER command is given or login fails.
668 */
669static void
670end_login()
671{
672
673	(void) seteuid((uid_t)0);
674	if (logged_in) {
675		logwtmp(ttyline, "", "");
676		if (doutmp)
677			logout(utmp.ut_line);
678	}
679	pw = NULL;
680	logged_in = 0;
681	guest = 0;
682	dochroot = 0;
683}
684
685void
686pass(passwd)
687	char *passwd;
688{
689	int rval;
690	FILE *fd;
691	static char homedir[MAXPATHLEN];
692	char rootdir[MAXPATHLEN];
693
694	if (logged_in || askpasswd == 0) {
695		reply(503, "Login with USER first.");
696		return;
697	}
698	askpasswd = 0;
699	if (!guest) {		/* "ftp" is only account allowed no password */
700		if (pw == NULL) {
701			rval = 1;	/* failure below */
702			goto skip;
703		}
704#if defined(KERBEROS)
705		rval = klogin(pw, "", hostname, passwd);
706		if (rval == 0)
707			goto skip;
708#endif
709#ifdef SKEY
710		if (skey_haskey(pw->pw_name) == 0 &&
711		   (skey_passcheck(pw->pw_name, passwd) != -1)) {
712			rval = 0;
713			goto skip;
714		}
715#endif
716		/* the strcmp does not catch null passwords! */
717		if (pw == NULL || *pw->pw_passwd == '\0' ||
718		    strcmp(crypt(passwd, (pw ? pw->pw_passwd : "xx")), pw->pw_passwd)) {
719			rval = 1;	 /* failure */
720			goto skip;
721		}
722		rval = 0;
723
724skip:
725		/*
726		 * If rval == 1, the user failed the authentication check
727		 * above.  If rval == 0, either Kerberos or local authentication
728		 * succeeded.
729		 */
730		if (rval) {
731			reply(530, "Login incorrect.");
732			if (logging)
733				syslog(LOG_NOTICE,
734				    "FTP LOGIN FAILED FROM %s, %s",
735				    remotehost, curname);
736			pw = NULL;
737			if (login_attempts++ >= 5) {
738				syslog(LOG_NOTICE,
739				    "repeated login failures from %s",
740				    remotehost);
741				exit(0);
742			}
743			return;
744		}
745	} else {
746		/* Save anonymous' password. */
747		guestpw = strdup(passwd);
748		if (guestpw == (char *)NULL)
749			fatal("Out of memory");
750	}
751	login_attempts = 0;		/* this time successful */
752	if (setegid((gid_t)pw->pw_gid) < 0) {
753		reply(550, "Can't set gid.");
754		return;
755	}
756	(void) initgroups(pw->pw_name, pw->pw_gid);
757
758	/* open wtmp before chroot */
759	logwtmp(ttyline, pw->pw_name, remotehost);
760
761	/* open utmp before chroot */
762	if (doutmp) {
763		memset((void *)&utmp, 0, sizeof(utmp));
764		(void)time(&utmp.ut_time);
765		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
766		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
767		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
768		login(&utmp);
769	}
770
771	/* open stats file before chroot */
772	if (guest && (stats == 1) && (statfd < 0))
773		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
774			stats = 0;
775
776	logged_in = 1;
777
778	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
779	if (guest || dochroot) {
780		if (multihome) {
781			struct stat ts;
782
783			/* Compute root directory. */
784			snprintf (rootdir, sizeof(rootdir), "%s/%s",
785				  pw->pw_dir, dhostname);
786			if (stat(rootdir, &ts) < 0) {
787				snprintf (rootdir, sizeof(rootdir), "%s/%s",
788					  pw->pw_dir, hostname);
789			}
790		} else
791			strcpy (rootdir, pw->pw_dir);
792	}
793	if (guest) {
794		/*
795		 * We MUST do a chdir() after the chroot. Otherwise
796		 * the old current directory will be accessible as "."
797		 * outside the new root!
798		 */
799		if (chroot(rootdir) < 0 || chdir("/") < 0) {
800			reply(550, "Can't set guest privileges.");
801			goto bad;
802		}
803		strcpy(pw->pw_dir, "/");
804		setenv("HOME", "/", 1);
805	} else if (dochroot) {
806		if (chroot(rootdir) < 0 || chdir("/") < 0) {
807			reply(550, "Can't change root.");
808			goto bad;
809		}
810		strcpy(pw->pw_dir, "/");
811		setenv("HOME", "/", 1);
812	} else if (chdir(pw->pw_dir) < 0) {
813		if (chdir("/") < 0) {
814			reply(530, "User %s: can't change directory to %s.",
815			    pw->pw_name, pw->pw_dir);
816			goto bad;
817		} else
818			lreply(230, "No directory! Logging in with home=/");
819	}
820	if (seteuid((uid_t)pw->pw_uid) < 0) {
821		reply(550, "Can't set uid.");
822		goto bad;
823	}
824
825	/*
826	 * Set home directory so that use of ~ (tilde) works correctly.
827	 */
828	if (getcwd(homedir, MAXPATHLEN) != NULL)
829		setenv("HOME", homedir, 1);
830
831	/*
832	 * Display a login message, if it exists.
833	 * N.B. reply(230,) must follow the message.
834	 */
835	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
836		char *cp, line[LINE_MAX];
837
838		while (fgets(line, sizeof(line), fd) != NULL) {
839			if ((cp = strchr(line, '\n')) != NULL)
840				*cp = '\0';
841			lreply(230, "%s", line);
842		}
843		(void) fflush(stdout);
844		(void) fclose(fd);
845	}
846	if (guest) {
847		if (ident != NULL)
848			free(ident);
849		ident = strdup(passwd);
850		if (ident == (char *)NULL)
851			fatal("Ran out of memory.");
852		reply(230, "Guest login ok, access restrictions apply.");
853#ifdef HASSETPROCTITLE
854		snprintf(proctitle, sizeof(proctitle),
855		    "%s: anonymous/%.*s", remotehost,
856		    sizeof(proctitle) - sizeof(remotehost) -
857		    sizeof(": anonymous/"), passwd);
858		setproctitle(proctitle);
859#endif /* HASSETPROCTITLE */
860		if (logging)
861			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
862			    remotehost, passwd);
863	} else {
864		reply(230, "User %s logged in.", pw->pw_name);
865#ifdef HASSETPROCTITLE
866		snprintf(proctitle, sizeof(proctitle),
867		    "%s: %s", remotehost, pw->pw_name);
868		setproctitle(proctitle);
869#endif /* HASSETPROCTITLE */
870		if (logging)
871			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
872			    remotehost, pw->pw_name);
873	}
874	(void) umask(defumask);
875	return;
876bad:
877	/* Forget all about it... */
878	end_login();
879}
880
881void
882retrieve(cmd, name)
883	char *cmd, *name;
884{
885	FILE *fin, *dout;
886	struct stat st;
887	int (*closefunc) __P((FILE *));
888	time_t start;
889
890	if (cmd == 0) {
891		fin = fopen(name, "r"), closefunc = fclose;
892		st.st_size = 0;
893	} else {
894		char line[BUFSIZ];
895
896		(void) snprintf(line, sizeof(line), cmd, name);
897		name = line;
898		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
899		st.st_size = -1;
900		st.st_blksize = BUFSIZ;
901	}
902	if (fin == NULL) {
903		if (errno != 0) {
904			perror_reply(550, name);
905			if (cmd == 0) {
906				LOGCMD("get", name);
907			}
908		}
909		return;
910	}
911	byte_count = -1;
912	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
913		reply(550, "%s: not a plain file.", name);
914		goto done;
915	}
916	if (restart_point) {
917		if (type == TYPE_A) {
918			off_t i, n;
919			int c;
920
921			n = restart_point;
922			i = 0;
923			while (i++ < n) {
924				if ((c=getc(fin)) == EOF) {
925					perror_reply(550, name);
926					goto done;
927				}
928				if (c == '\n')
929					i++;
930			}
931		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
932			perror_reply(550, name);
933			goto done;
934		}
935	}
936	dout = dataconn(name, st.st_size, "w");
937	if (dout == NULL)
938		goto done;
939	time(&start);
940	send_data(fin, dout, st.st_blksize, st.st_size,
941		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
942	if ((cmd == 0) && stats)
943		logxfer(name, st.st_size, start);
944	(void) fclose(dout);
945	data = -1;
946	pdata = -1;
947done:
948	if (cmd == 0)
949		LOGBYTES("get", name, byte_count);
950	(*closefunc)(fin);
951}
952
953void
954store(name, mode, unique)
955	char *name, *mode;
956	int unique;
957{
958	FILE *fout, *din;
959	struct stat st;
960	int (*closefunc) __P((FILE *));
961
962	if (unique && stat(name, &st) == 0 &&
963	    (name = gunique(name)) == NULL) {
964		LOGCMD(*mode == 'w' ? "put" : "append", name);
965		return;
966	}
967
968	if (restart_point)
969		mode = "r+";
970	fout = fopen(name, mode);
971	closefunc = fclose;
972	if (fout == NULL) {
973		perror_reply(553, name);
974		LOGCMD(*mode == 'w' ? "put" : "append", name);
975		return;
976	}
977	byte_count = -1;
978	if (restart_point) {
979		if (type == TYPE_A) {
980			off_t i, n;
981			int c;
982
983			n = restart_point;
984			i = 0;
985			while (i++ < n) {
986				if ((c=getc(fout)) == EOF) {
987					perror_reply(550, name);
988					goto done;
989				}
990				if (c == '\n')
991					i++;
992			}
993			/*
994			 * We must do this seek to "current" position
995			 * because we are changing from reading to
996			 * writing.
997			 */
998			if (fseek(fout, 0L, L_INCR) < 0) {
999				perror_reply(550, name);
1000				goto done;
1001			}
1002		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
1003			perror_reply(550, name);
1004			goto done;
1005		}
1006	}
1007	din = dataconn(name, (off_t)-1, "r");
1008	if (din == NULL)
1009		goto done;
1010	if (receive_data(din, fout) == 0) {
1011		if (unique)
1012			reply(226, "Transfer complete (unique file name:%s).",
1013			    name);
1014		else
1015			reply(226, "Transfer complete.");
1016	}
1017	(void) fclose(din);
1018	data = -1;
1019	pdata = -1;
1020done:
1021	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1022	(*closefunc)(fout);
1023}
1024
1025static FILE *
1026getdatasock(mode)
1027	char *mode;
1028{
1029	int on = 1, s, t, tries;
1030
1031	if (data >= 0)
1032		return (fdopen(data, mode));
1033	(void) seteuid((uid_t)0);
1034	s = socket(AF_INET, SOCK_STREAM, 0);
1035	if (s < 0)
1036		goto bad;
1037	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1038	    (char *) &on, sizeof(on)) < 0)
1039		goto bad;
1040	/* anchor socket to avoid multi-homing problems */
1041	data_source.sin_len = sizeof(struct sockaddr_in);
1042	data_source.sin_family = AF_INET;
1043	data_source.sin_addr = ctrl_addr.sin_addr;
1044	for (tries = 1; ; tries++) {
1045		if (bind(s, (struct sockaddr *)&data_source,
1046		    sizeof(data_source)) >= 0)
1047			break;
1048		if (errno != EADDRINUSE || tries > 10)
1049			goto bad;
1050		sleep(tries);
1051	}
1052	(void) seteuid((uid_t)pw->pw_uid);
1053#ifdef IP_TOS
1054	on = IPTOS_THROUGHPUT;
1055	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1056		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1057#endif
1058#ifdef TCP_NOPUSH
1059	/*
1060	 * Turn off push flag to keep sender TCP from sending short packets
1061	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1062	 * to set the send buffer size as well, but that may not be desirable
1063	 * in heavy-load situations.
1064	 */
1065	on = 1;
1066	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1067		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1068#endif
1069#ifdef SO_SNDBUF
1070	on = 65536;
1071	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1072		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1073#endif
1074
1075	return (fdopen(s, mode));
1076bad:
1077	/* Return the real value of errno (close may change it) */
1078	t = errno;
1079	(void) seteuid((uid_t)pw->pw_uid);
1080	(void) close(s);
1081	errno = t;
1082	return (NULL);
1083}
1084
1085static FILE *
1086dataconn(name, size, mode)
1087	char *name;
1088	off_t size;
1089	char *mode;
1090{
1091	char sizebuf[32];
1092	FILE *file;
1093	int retry = 0, tos;
1094
1095	file_size = size;
1096	byte_count = 0;
1097	if (size != (off_t) -1) {
1098		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1099				size);
1100	} else
1101		sizebuf[0] = '\0';
1102	if (pdata >= 0) {
1103		struct sockaddr_in from;
1104		int s, fromlen = sizeof(from);
1105
1106		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1107		if (s < 0) {
1108			reply(425, "Can't open data connection.");
1109			(void) close(pdata);
1110			pdata = -1;
1111			return (NULL);
1112		}
1113		if (ntohs(from.sin_port) < IPPORT_RESERVED) {
1114			perror_reply(425, "Can't build data connection");
1115			(void) close(pdata);
1116			(void) close(s);
1117			pdata = -1;
1118			return (NULL);
1119		}
1120		if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) {
1121			perror_reply(435, "Can't build data connection");
1122			(void) close(pdata);
1123			(void) close(s);
1124			pdata = -1;
1125			return (NULL);
1126		}
1127		(void) close(pdata);
1128		pdata = s;
1129#ifdef IP_TOS
1130		tos = IPTOS_THROUGHPUT;
1131		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1132		    sizeof(int));
1133#endif
1134		reply(150, "Opening %s mode data connection for '%s'%s.",
1135		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1136		return (fdopen(pdata, mode));
1137	}
1138	if (data >= 0) {
1139		reply(125, "Using existing data connection for '%s'%s.",
1140		    name, sizebuf);
1141		usedefault = 1;
1142		return (fdopen(data, mode));
1143	}
1144	if (usedefault)
1145		data_dest = his_addr;
1146	usedefault = 1;
1147	file = getdatasock(mode);
1148	if (file == NULL) {
1149		reply(425, "Can't create data socket (%s,%d): %s.",
1150		    inet_ntoa(data_source.sin_addr),
1151		    ntohs(data_source.sin_port), strerror(errno));
1152		return (NULL);
1153	}
1154	data = fileno(file);
1155
1156	/*
1157	 * attempt to connect to reserved port on client machine;
1158	 * this looks like an attack
1159	 */
1160	if (ntohs(data_dest.sin_port) < IPPORT_RESERVED) {
1161		perror_reply(425, "Can't build data connection");
1162		(void) fclose(file);
1163		data = -1;
1164		return NULL;
1165	}
1166	if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) {
1167		perror_reply(435, "Can't build data connection");
1168		(void) fclose(file);
1169		data = -1;
1170		return NULL;
1171	}
1172	while (connect(data, (struct sockaddr *)&data_dest,
1173	    sizeof(data_dest)) < 0) {
1174		if (errno == EADDRINUSE && retry < swaitmax) {
1175			sleep((unsigned) swaitint);
1176			retry += swaitint;
1177			continue;
1178		}
1179		perror_reply(425, "Can't build data connection");
1180		(void) fclose(file);
1181		data = -1;
1182		return (NULL);
1183	}
1184	reply(150, "Opening %s mode data connection for '%s'%s.",
1185	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1186	return (file);
1187}
1188
1189/*
1190 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1191 * encapsulation of the data subject to Mode, Structure, and Type.
1192 *
1193 * NB: Form isn't handled.
1194 */
1195static void
1196send_data(instr, outstr, blksize, filesize, isreg)
1197	FILE *instr, *outstr;
1198	off_t blksize;
1199	off_t filesize;
1200	int isreg;
1201{
1202	int c, cnt, filefd, netfd;
1203	char *buf, *bp;
1204	size_t len;
1205
1206	transflag++;
1207	if (setjmp(urgcatch)) {
1208		transflag = 0;
1209		return;
1210	}
1211	switch (type) {
1212
1213	case TYPE_A:
1214		while ((c = getc(instr)) != EOF) {
1215			byte_count++;
1216			if (c == '\n') {
1217				if (ferror(outstr))
1218					goto data_err;
1219				(void) putc('\r', outstr);
1220			}
1221			(void) putc(c, outstr);
1222		}
1223		fflush(outstr);
1224		transflag = 0;
1225		if (ferror(instr))
1226			goto file_err;
1227		if (ferror(outstr))
1228			goto data_err;
1229		reply(226, "Transfer complete.");
1230		return;
1231
1232	case TYPE_I:
1233	case TYPE_L:
1234		/*
1235		 * isreg is only set if we are not doing restart and we
1236		 * are sending a regular file
1237		 */
1238		netfd = fileno(outstr);
1239		filefd = fileno(instr);
1240
1241		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1242			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1243				   (off_t)0);
1244			if (!buf) {
1245				syslog(LOG_WARNING, "mmap(%lu): %m",
1246				       (unsigned long)filesize);
1247				goto oldway;
1248			}
1249			bp = buf;
1250			len = filesize;
1251			do {
1252				cnt = write(netfd, bp, len);
1253				len -= cnt;
1254				bp += cnt;
1255				if (cnt > 0) byte_count += cnt;
1256			} while(cnt > 0 && len > 0);
1257
1258			transflag = 0;
1259			munmap(buf, (size_t)filesize);
1260			if (cnt < 0)
1261				goto data_err;
1262			reply(226, "Transfer complete.");
1263			return;
1264		}
1265
1266oldway:
1267		if ((buf = malloc((u_int)blksize)) == NULL) {
1268			transflag = 0;
1269			perror_reply(451, "Local resource failure: malloc");
1270			return;
1271		}
1272
1273		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1274		    write(netfd, buf, cnt) == cnt)
1275			byte_count += cnt;
1276		transflag = 0;
1277		(void)free(buf);
1278		if (cnt != 0) {
1279			if (cnt < 0)
1280				goto file_err;
1281			goto data_err;
1282		}
1283		reply(226, "Transfer complete.");
1284		return;
1285	default:
1286		transflag = 0;
1287		reply(550, "Unimplemented TYPE %d in send_data", type);
1288		return;
1289	}
1290
1291data_err:
1292	transflag = 0;
1293	perror_reply(426, "Data connection");
1294	return;
1295
1296file_err:
1297	transflag = 0;
1298	perror_reply(551, "Error on input file");
1299}
1300
1301/*
1302 * Transfer data from peer to "outstr" using the appropriate encapulation of
1303 * the data subject to Mode, Structure, and Type.
1304 *
1305 * N.B.: Form isn't handled.
1306 */
1307static int
1308receive_data(instr, outstr)
1309	FILE *instr, *outstr;
1310{
1311	int c;
1312	int cnt, bare_lfs = 0;
1313	char buf[BUFSIZ];
1314
1315	transflag++;
1316	if (setjmp(urgcatch)) {
1317		transflag = 0;
1318		return (-1);
1319	}
1320	switch (type) {
1321
1322	case TYPE_I:
1323	case TYPE_L:
1324		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1325			if (write(fileno(outstr), buf, cnt) != cnt)
1326				goto file_err;
1327			byte_count += cnt;
1328		}
1329		if (cnt < 0)
1330			goto data_err;
1331		transflag = 0;
1332		return (0);
1333
1334	case TYPE_E:
1335		reply(553, "TYPE E not implemented.");
1336		transflag = 0;
1337		return (-1);
1338
1339	case TYPE_A:
1340		while ((c = getc(instr)) != EOF) {
1341			byte_count++;
1342			if (c == '\n')
1343				bare_lfs++;
1344			while (c == '\r') {
1345				if (ferror(outstr))
1346					goto data_err;
1347				if ((c = getc(instr)) != '\n') {
1348					(void) putc ('\r', outstr);
1349					if (c == '\0' || c == EOF)
1350						goto contin2;
1351				}
1352			}
1353			(void) putc(c, outstr);
1354	contin2:	;
1355		}
1356		fflush(outstr);
1357		if (ferror(instr))
1358			goto data_err;
1359		if (ferror(outstr))
1360			goto file_err;
1361		transflag = 0;
1362		if (bare_lfs) {
1363			lreply(226,
1364		"WARNING! %d bare linefeeds received in ASCII mode",
1365			    bare_lfs);
1366		(void)printf("   File may not have transferred correctly.\r\n");
1367		}
1368		return (0);
1369	default:
1370		reply(550, "Unimplemented TYPE %d in receive_data", type);
1371		transflag = 0;
1372		return (-1);
1373	}
1374
1375data_err:
1376	transflag = 0;
1377	perror_reply(426, "Data Connection");
1378	return (-1);
1379
1380file_err:
1381	transflag = 0;
1382	perror_reply(452, "Error writing file");
1383	return (-1);
1384}
1385
1386void
1387statfilecmd(filename)
1388	char *filename;
1389{
1390	FILE *fin;
1391	int c;
1392	char line[LINE_MAX];
1393
1394	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1395	fin = ftpd_popen(line, "r");
1396	lreply(211, "status of %s:", filename);
1397	while ((c = getc(fin)) != EOF) {
1398		if (c == '\n') {
1399			if (ferror(stdout)){
1400				perror_reply(421, "control connection");
1401				(void) ftpd_pclose(fin);
1402				dologout(1);
1403				/* NOTREACHED */
1404			}
1405			if (ferror(fin)) {
1406				perror_reply(551, filename);
1407				(void) ftpd_pclose(fin);
1408				return;
1409			}
1410			(void) putc('\r', stdout);
1411		}
1412		(void) putc(c, stdout);
1413	}
1414	(void) ftpd_pclose(fin);
1415	reply(211, "End of Status");
1416}
1417
1418void
1419statcmd()
1420{
1421	struct sockaddr_in *sin;
1422	u_char *a, *p;
1423
1424	lreply(211, "%s FTP server status:", hostname, version);
1425	printf("     %s\r\n", version);
1426	printf("     Connected to %s", remotehost);
1427	if (!isdigit(remotehost[0]))
1428		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1429	printf("\r\n");
1430	if (logged_in) {
1431		if (guest)
1432			printf("     Logged in anonymously\r\n");
1433		else
1434			printf("     Logged in as %s\r\n", pw->pw_name);
1435	} else if (askpasswd)
1436		printf("     Waiting for password\r\n");
1437	else
1438		printf("     Waiting for user name\r\n");
1439	printf("     TYPE: %s", typenames[type]);
1440	if (type == TYPE_A || type == TYPE_E)
1441		printf(", FORM: %s", formnames[form]);
1442	if (type == TYPE_L)
1443#if NBBY == 8
1444		printf(" %d", NBBY);
1445#else
1446		printf(" %d", bytesize);	/* need definition! */
1447#endif
1448	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1449	    strunames[stru], modenames[mode]);
1450	if (data != -1)
1451		printf("     Data connection open\r\n");
1452	else if (pdata != -1) {
1453		printf("     in Passive mode");
1454		sin = &pasv_addr;
1455		goto printaddr;
1456	} else if (usedefault == 0) {
1457		printf("     PORT");
1458		sin = &data_dest;
1459printaddr:
1460		a = (u_char *) &sin->sin_addr;
1461		p = (u_char *) &sin->sin_port;
1462#define UC(b) (((int) b) & 0xff)
1463		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1464			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1465#undef UC
1466	} else
1467		printf("     No data connection\r\n");
1468	reply(211, "End of status");
1469}
1470
1471void
1472fatal(s)
1473	char *s;
1474{
1475
1476	reply(451, "Error in server: %s\n", s);
1477	reply(221, "Closing connection due to server error.");
1478	dologout(0);
1479	/* NOTREACHED */
1480}
1481
1482void
1483#if __STDC__
1484reply(int n, const char *fmt, ...)
1485#else
1486reply(n, fmt, va_alist)
1487	int n;
1488	char *fmt;
1489        va_dcl
1490#endif
1491{
1492	va_list ap;
1493#if __STDC__
1494	va_start(ap, fmt);
1495#else
1496	va_start(ap);
1497#endif
1498	(void)printf("%d ", n);
1499	(void)vprintf(fmt, ap);
1500	(void)printf("\r\n");
1501	(void)fflush(stdout);
1502	if (debug) {
1503		syslog(LOG_DEBUG, "<--- %d ", n);
1504		vsyslog(LOG_DEBUG, fmt, ap);
1505	}
1506}
1507
1508void
1509#if __STDC__
1510lreply(int n, const char *fmt, ...)
1511#else
1512lreply(n, fmt, va_alist)
1513	int n;
1514	char *fmt;
1515        va_dcl
1516#endif
1517{
1518	va_list ap;
1519#if __STDC__
1520	va_start(ap, fmt);
1521#else
1522	va_start(ap);
1523#endif
1524	(void)printf("%d- ", n);
1525	(void)vprintf(fmt, ap);
1526	(void)printf("\r\n");
1527	(void)fflush(stdout);
1528	if (debug) {
1529		syslog(LOG_DEBUG, "<--- %d- ", n);
1530		vsyslog(LOG_DEBUG, fmt, ap);
1531	}
1532}
1533
1534static void
1535ack(s)
1536	char *s;
1537{
1538
1539	reply(250, "%s command successful.", s);
1540}
1541
1542void
1543nack(s)
1544	char *s;
1545{
1546
1547	reply(502, "%s command not implemented.", s);
1548}
1549
1550/* ARGSUSED */
1551void
1552yyerror(s)
1553	char *s;
1554{
1555	char *cp;
1556
1557	if (cp = strchr(cbuf,'\n'))
1558		*cp = '\0';
1559	reply(500, "'%s': command not understood.", cbuf);
1560}
1561
1562void
1563delete(name)
1564	char *name;
1565{
1566	struct stat st;
1567
1568	LOGCMD("delete", name);
1569	if (stat(name, &st) < 0) {
1570		perror_reply(550, name);
1571		return;
1572	}
1573	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1574		if (rmdir(name) < 0) {
1575			perror_reply(550, name);
1576			return;
1577		}
1578		goto done;
1579	}
1580	if (unlink(name) < 0) {
1581		perror_reply(550, name);
1582		return;
1583	}
1584done:
1585	ack("DELE");
1586}
1587
1588void
1589cwd(path)
1590	char *path;
1591{
1592
1593	if (chdir(path) < 0)
1594		perror_reply(550, path);
1595	else
1596		ack("CWD");
1597}
1598
1599void
1600makedir(name)
1601	char *name;
1602{
1603
1604	LOGCMD("mkdir", name);
1605	if (mkdir(name, 0777) < 0)
1606		perror_reply(550, name);
1607	else
1608		reply(257, "MKD command successful.");
1609}
1610
1611void
1612removedir(name)
1613	char *name;
1614{
1615
1616	LOGCMD("rmdir", name);
1617	if (rmdir(name) < 0)
1618		perror_reply(550, name);
1619	else
1620		ack("RMD");
1621}
1622
1623void
1624pwd()
1625{
1626	char path[MAXPATHLEN + 1];
1627
1628	if (getwd(path) == (char *)NULL)
1629		reply(550, "%s.", path);
1630	else
1631		reply(257, "\"%s\" is current directory.", path);
1632}
1633
1634char *
1635renamefrom(name)
1636	char *name;
1637{
1638	struct stat st;
1639
1640	if (stat(name, &st) < 0) {
1641		perror_reply(550, name);
1642		return ((char *)0);
1643	}
1644	reply(350, "File exists, ready for destination name");
1645	return (name);
1646}
1647
1648void
1649renamecmd(from, to)
1650	char *from, *to;
1651{
1652
1653	LOGCMD2("rename", from, to);
1654	if (rename(from, to) < 0)
1655		perror_reply(550, "rename");
1656	else
1657		ack("RNTO");
1658}
1659
1660static void
1661dolog(sin)
1662	struct sockaddr_in *sin;
1663{
1664	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1665		sizeof(struct in_addr), AF_INET);
1666
1667	if (hp)
1668		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1);
1669	else
1670		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1671		    sizeof(remotehost)-1);
1672	remotehost[sizeof(remotehost)-1] = '\0';
1673#ifdef HASSETPROCTITLE
1674	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1675	setproctitle(proctitle);
1676#endif /* HASSETPROCTITLE */
1677
1678	if (logging)
1679		syslog(LOG_INFO, "connection from %s", remotehost);
1680}
1681
1682/*
1683 * Record logout in wtmp file
1684 * and exit with supplied status.
1685 */
1686void
1687dologout(status)
1688	int status;
1689{
1690
1691	if (logged_in) {
1692		(void) seteuid((uid_t)0);
1693		logwtmp(ttyline, "", "");
1694		if (doutmp)
1695			logout(utmp.ut_line);
1696#if defined(KERBEROS)
1697		if (!notickets && krbtkfile_env)
1698			unlink(krbtkfile_env);
1699#endif
1700	}
1701	/* beware of flushing buffers after a SIGPIPE */
1702	_exit(status);
1703}
1704
1705static void
1706myoob(signo)
1707	int signo;
1708{
1709	char *cp;
1710
1711	/* only process if transfer occurring */
1712	if (!transflag)
1713		return;
1714	cp = tmpline;
1715	if (getline(cp, 7, stdin) == NULL) {
1716		reply(221, "You could at least say goodbye.");
1717		dologout(0);
1718	}
1719	upper(cp);
1720	if (strcmp(cp, "ABOR\r\n") == 0) {
1721		tmpline[0] = '\0';
1722		reply(426, "Transfer aborted. Data connection closed.");
1723		reply(226, "Abort successful");
1724		longjmp(urgcatch, 1);
1725	}
1726	if (strcmp(cp, "STAT\r\n") == 0) {
1727		if (file_size != (off_t) -1)
1728			reply(213, "Status: %qd of %qd bytes transferred",
1729			    byte_count, file_size);
1730		else
1731			reply(213, "Status: %qd bytes transferred", byte_count);
1732	}
1733}
1734
1735/*
1736 * Note: a response of 425 is not mentioned as a possible response to
1737 *	the PASV command in RFC959. However, it has been blessed as
1738 *	a legitimate response by Jon Postel in a telephone conversation
1739 *	with Rick Adams on 25 Jan 89.
1740 */
1741void
1742passive()
1743{
1744	int len, on;
1745	u_short port;
1746	char *p, *a;
1747
1748	if (pw == NULL) {
1749		reply(530, "Please login with USER and PASS");
1750		return;
1751	}
1752	pdata = socket(AF_INET, SOCK_STREAM, 0);
1753	if (pdata < 0) {
1754		perror_reply(425, "Can't open passive connection");
1755		return;
1756	}
1757
1758#ifdef IP_PORTRANGE
1759	on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
1760	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
1761		       (char *)&on, sizeof(on)) < 0)
1762		goto pasv_error;
1763#endif
1764
1765	pasv_addr = ctrl_addr;
1766	pasv_addr.sin_port = 0;
1767	if (bind(pdata, (struct sockaddr *)&pasv_addr,
1768		 sizeof(pasv_addr)) < 0)
1769		goto pasv_error;
1770
1771	len = sizeof(pasv_addr);
1772	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1773		goto pasv_error;
1774	if (listen(pdata, 1) < 0)
1775		goto pasv_error;
1776	a = (char *) &pasv_addr.sin_addr;
1777	p = (char *) &pasv_addr.sin_port;
1778
1779#define UC(b) (((int) b) & 0xff)
1780
1781	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1782		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1783	return;
1784
1785pasv_error:
1786	(void) close(pdata);
1787	pdata = -1;
1788	perror_reply(425, "Can't open passive connection");
1789	return;
1790}
1791
1792/*
1793 * Generate unique name for file with basename "local".
1794 * The file named "local" is already known to exist.
1795 * Generates failure reply on error.
1796 */
1797static char *
1798gunique(local)
1799	char *local;
1800{
1801	static char new[MAXPATHLEN];
1802	struct stat st;
1803	int count, len;
1804	char *cp;
1805
1806	cp = strrchr(local, '/');
1807	if (cp)
1808		*cp = '\0';
1809	if (stat(cp ? local : ".", &st) < 0) {
1810		perror_reply(553, cp ? local : ".");
1811		return ((char *) 0);
1812	}
1813	if (cp)
1814		*cp = '/';
1815	(void) strncpy(new, local, sizeof(new)-1);
1816	new[sizeof(new)-1] = '\0';
1817	len = strlen(new);
1818	if (len+2+1 >= sizeof(new)-1)
1819		return (NULL);
1820	cp = new + len;
1821	*cp++ = '.';
1822	for (count = 1; count < 100; count++) {
1823		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
1824		if (stat(new, &st) < 0)
1825			return (new);
1826	}
1827	reply(452, "Unique file name cannot be created.");
1828	return (NULL);
1829}
1830
1831/*
1832 * Format and send reply containing system error number.
1833 */
1834void
1835perror_reply(code, string)
1836	int code;
1837	char *string;
1838{
1839
1840	reply(code, "%s: %s.", string, strerror(errno));
1841}
1842
1843static char *onefile[] = {
1844	"",
1845	0
1846};
1847
1848void
1849send_file_list(whichf)
1850	char *whichf;
1851{
1852	struct stat st;
1853	DIR *dirp = NULL;
1854	struct dirent *dir;
1855	FILE *dout = NULL;
1856	char **dirlist, *dirname;
1857	int simple = 0;
1858	int freeglob = 0;
1859	glob_t gl;
1860
1861	if (strpbrk(whichf, "~{[*?") != NULL) {
1862		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1863
1864		memset(&gl, 0, sizeof(gl));
1865		freeglob = 1;
1866		if (glob(whichf, flags, 0, &gl)) {
1867			reply(550, "not found");
1868			goto out;
1869		} else if (gl.gl_pathc == 0) {
1870			errno = ENOENT;
1871			perror_reply(550, whichf);
1872			goto out;
1873		}
1874		dirlist = gl.gl_pathv;
1875	} else {
1876		onefile[0] = whichf;
1877		dirlist = onefile;
1878		simple = 1;
1879	}
1880
1881	if (setjmp(urgcatch)) {
1882		transflag = 0;
1883		goto out;
1884	}
1885	while (dirname = *dirlist++) {
1886		if (stat(dirname, &st) < 0) {
1887			/*
1888			 * If user typed "ls -l", etc, and the client
1889			 * used NLST, do what the user meant.
1890			 */
1891			if (dirname[0] == '-' && *dirlist == NULL &&
1892			    transflag == 0) {
1893				retrieve("/bin/ls %s", dirname);
1894				goto out;
1895			}
1896			perror_reply(550, whichf);
1897			if (dout != NULL) {
1898				(void) fclose(dout);
1899				transflag = 0;
1900				data = -1;
1901				pdata = -1;
1902			}
1903			goto out;
1904		}
1905
1906		if (S_ISREG(st.st_mode)) {
1907			if (dout == NULL) {
1908				dout = dataconn("file list", (off_t)-1, "w");
1909				if (dout == NULL)
1910					goto out;
1911				transflag++;
1912			}
1913			fprintf(dout, "%s%s\n", dirname,
1914				type == TYPE_A ? "\r" : "");
1915			byte_count += strlen(dirname) + 1;
1916			continue;
1917		} else if (!S_ISDIR(st.st_mode))
1918			continue;
1919
1920		if ((dirp = opendir(dirname)) == NULL)
1921			continue;
1922
1923		while ((dir = readdir(dirp)) != NULL) {
1924			char nbuf[MAXPATHLEN];
1925
1926			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1927				continue;
1928			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1929			    dir->d_namlen == 2)
1930				continue;
1931
1932			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
1933				 dir->d_name);
1934
1935			/*
1936			 * We have to do a stat to insure it's
1937			 * not a directory or special file.
1938			 */
1939			if (simple || (stat(nbuf, &st) == 0 &&
1940			    S_ISREG(st.st_mode))) {
1941				if (dout == NULL) {
1942					dout = dataconn("file list", (off_t)-1,
1943						"w");
1944					if (dout == NULL)
1945						goto out;
1946					transflag++;
1947				}
1948				if (nbuf[0] == '.' && nbuf[1] == '/')
1949					fprintf(dout, "%s%s\n", &nbuf[2],
1950						type == TYPE_A ? "\r" : "");
1951				else
1952					fprintf(dout, "%s%s\n", nbuf,
1953						type == TYPE_A ? "\r" : "");
1954				byte_count += strlen(nbuf) + 1;
1955			}
1956		}
1957		(void) closedir(dirp);
1958	}
1959
1960	if (dout == NULL)
1961		reply(550, "No files found.");
1962	else if (ferror(dout) != 0)
1963		perror_reply(550, "Data connection");
1964	else
1965		reply(226, "Transfer complete.");
1966
1967	transflag = 0;
1968	if (dout != NULL)
1969		(void) fclose(dout);
1970	data = -1;
1971	pdata = -1;
1972out:
1973	if (freeglob) {
1974		freeglob = 0;
1975		globfree(&gl);
1976	}
1977}
1978
1979static void
1980reapchild(signo)
1981	int signo;
1982{
1983	while (wait3(NULL, WNOHANG, NULL) > 0);
1984}
1985
1986void
1987logxfer(name, size, start)
1988	char *name;
1989	off_t size;
1990	time_t start;
1991{
1992	char buf[2048];
1993	char path[MAXPATHLEN];
1994	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
1995	char *vname, *vpw;
1996	time_t now;
1997
1998	if ((statfd >= 0) && (getcwd(path, sizeof(path)) != NULL)) {
1999		time(&now);
2000
2001		vname = (char *)malloc(strlen(name)*4+1);
2002		if (vname == NULL)
2003			return;
2004		vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1);
2005		if (vpw == NULL) {
2006			free(vname);
2007			return;
2008		}
2009
2010		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2011		strvis(vpath, path, VIS_SAFE|VIS_NOSLASH);
2012		strvis(vname, name, VIS_SAFE|VIS_NOSLASH);
2013		strvis(vpw, (guest) ? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2014
2015		snprintf(buf, sizeof(buf),
2016			 "%.24s %d %s %qd %s/%s %c %s %c %c %s ftp %d %s %s\n",
2017			 ctime(&now), now - start + (now == start),
2018			 vremotehost, size, vpath, vname,
2019			 ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2020			 'o', ((guest) ? 'a' : 'r'),
2021			 vpw, 0 /* none yet */,
2022			 ((guest) ? "*" : pw->pw_name), dhostname);
2023		write(statfd, buf, strlen(buf));
2024		free(vname);
2025		free(vpw);
2026	}
2027}
2028