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