ftpd.c revision 60929
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
34#if 0
35#ifndef lint
36static char copyright[] =
37"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
38	The Regents of the University of California.  All rights reserved.\n";
39#endif /* not lint */
40#endif
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
45#endif
46static const char rcsid[] =
47  "$FreeBSD: head/libexec/ftpd/ftpd.c 60929 2000-05-25 19:30:18Z nsayer $";
48#endif /* not lint */
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#if !defined(NOPAM)
98#include <security/pam_appl.h>
99#endif
100
101#include "pathnames.h"
102#include "extern.h"
103
104#if __STDC__
105#include <stdarg.h>
106#else
107#include <varargs.h>
108#endif
109
110static char version[] = "Version 6.00LS";
111#undef main
112
113/* wrapper for KAME-special getnameinfo() */
114#ifndef NI_WITHSCOPEID
115#define	NI_WITHSCOPEID	0
116#endif
117
118extern	off_t restart_point;
119extern	char cbuf[];
120
121union sockunion server_addr;
122union sockunion ctrl_addr;
123union sockunion data_source;
124union sockunion data_dest;
125union sockunion his_addr;
126union sockunion pasv_addr;
127
128int	daemon_mode;
129int	data;
130jmp_buf	errcatch, urgcatch;
131int	logged_in;
132struct	passwd *pw;
133int	debug;
134int	timeout = 900;    /* timeout after 15 minutes of inactivity */
135int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
136int	logging;
137int	restricted_data_ports = 1;
138int	paranoid = 1;	  /* be extra careful about security */
139int	anon_only = 0;    /* Only anonymous ftp allowed */
140int	guest;
141int	dochroot;
142int	stats;
143int	statfd = -1;
144int	type;
145int	form;
146int	stru;			/* avoid C keyword */
147int	mode;
148int	usedefault = 1;		/* for data transfers */
149int	pdata = -1;		/* for passive mode */
150sig_atomic_t transflag;
151off_t	file_size;
152off_t	byte_count;
153#if !defined(CMASK) || CMASK == 0
154#undef CMASK
155#define CMASK 027
156#endif
157int	defumask = CMASK;		/* default umask value */
158char	tmpline[7];
159char	*hostname;
160#ifdef VIRTUAL_HOSTING
161char	*ftpuser;
162
163int	epsvall = 0;
164
165static struct ftphost {
166	struct ftphost	*next;
167	struct addrinfo *hostinfo;
168	char		*hostname;
169	char		*anonuser;
170	char		*statfile;
171	char		*welcome;
172	char		*loginmsg;
173} *thishost, *firsthost;
174
175#endif
176char	remotehost[MAXHOSTNAMELEN];
177char	*ident = NULL;
178
179static char ttyline[20];
180char	*tty = ttyline;		/* for klogin */
181
182#if !defined(NOPAM)
183static int	auth_pam __P((struct passwd**, const char*));
184#endif
185
186char	*pid_file = NULL;
187
188/*
189 * Timeout intervals for retrying connections
190 * to hosts that don't accept PORT cmds.  This
191 * is a kludge, but given the problems with TCP...
192 */
193#define	SWAITMAX	90	/* wait at most 90 seconds */
194#define	SWAITINT	5	/* interval between retries */
195
196int	swaitmax = SWAITMAX;
197int	swaitint = SWAITINT;
198
199#ifdef SETPROCTITLE
200#ifdef OLD_SETPROCTITLE
201char	**Argv = NULL;		/* pointer to argument vector */
202char	*LastArgv = NULL;	/* end of argv */
203#endif /* OLD_SETPROCTITLE */
204char	proctitle[LINE_MAX];	/* initial part of title */
205#endif /* SETPROCTITLE */
206
207#ifdef SKEY
208int	pwok = 0;
209char	addr_string[INET6_ADDRSTRLEN];	/* XXX */
210#endif
211
212#define LOGCMD(cmd, file) \
213	if (logging > 1) \
214	    syslog(LOG_INFO,"%s %s%s", cmd, \
215		*(file) == '/' ? "" : curdir(), file);
216#define LOGCMD2(cmd, file1, file2) \
217	 if (logging > 1) \
218	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
219		*(file1) == '/' ? "" : curdir(), file1, \
220		*(file2) == '/' ? "" : curdir(), file2);
221#define LOGBYTES(cmd, file, cnt) \
222	if (logging > 1) { \
223		if (cnt == (off_t)-1) \
224		    syslog(LOG_INFO,"%s %s%s", cmd, \
225			*(file) == '/' ? "" : curdir(), file); \
226		else \
227		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
228			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
229	}
230
231#ifdef VIRTUAL_HOSTING
232static void	 inithosts __P((void));
233static void	selecthost __P((union sockunion *));
234#endif
235static void	 ack __P((char *));
236static void	 myoob __P((int));
237static int	 checkuser __P((char *, char *, int));
238static FILE	*dataconn __P((char *, off_t, char *));
239static void	 dolog __P((struct sockaddr *));
240static char	*curdir __P((void));
241static void	 end_login __P((void));
242static FILE	*getdatasock __P((char *));
243static char	*gunique __P((char *));
244static void	 lostconn __P((int));
245static int	 receive_data __P((FILE *, FILE *));
246static void	 send_data __P((FILE *, FILE *, off_t, off_t, int));
247static struct passwd *
248		 sgetpwnam __P((char *));
249static char	*sgetsave __P((char *));
250static void	 reapchild __P((int));
251static void      logxfer __P((char *, long, long));
252
253static char *
254curdir()
255{
256	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */
257
258	if (getcwd(path, sizeof(path)-2) == NULL)
259		return ("");
260	if (path[1] != '\0')		/* special case for root dir. */
261		strcat(path, "/");
262	/* For guest account, skip / since it's chrooted */
263	return (guest ? path+1 : path);
264}
265
266int
267main(argc, argv, envp)
268	int argc;
269	char *argv[];
270	char **envp;
271{
272	int addrlen, ch, on = 1, tos;
273	char *cp, line[LINE_MAX];
274	FILE *fd;
275	int error;
276	char	*bindname = NULL;
277	int	family = AF_UNSPEC;
278	int	enable_v4 = 0;
279
280	tzset();		/* in case no timezone database in ~ftp */
281
282#ifdef OLD_SETPROCTITLE
283	/*
284	 *  Save start and extent of argv for setproctitle.
285	 */
286	Argv = argv;
287	while (*envp)
288		envp++;
289	LastArgv = envp[-1] + strlen(envp[-1]);
290#endif /* OLD_SETPROCTITLE */
291
292
293	while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:46")) != -1) {
294		switch (ch) {
295		case 'D':
296			daemon_mode++;
297			break;
298
299		case 'd':
300			debug++;
301			break;
302
303		case 'l':
304			logging++;	/* > 1 == extra logging */
305			break;
306
307		case 'R':
308			paranoid = 0;
309			break;
310
311		case 'S':
312			stats++;
313			break;
314
315		case 'T':
316			maxtimeout = atoi(optarg);
317			if (timeout > maxtimeout)
318				timeout = maxtimeout;
319			break;
320
321		case 't':
322			timeout = atoi(optarg);
323			if (maxtimeout < timeout)
324				maxtimeout = timeout;
325			break;
326
327		case 'U':
328			restricted_data_ports = 0;
329			break;
330
331		case 'a':
332			bindname = optarg;
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		case '4':
359			enable_v4 = 1;
360			if (family == AF_UNSPEC)
361				family = AF_INET;
362			break;
363
364		case '6':
365			family = AF_INET6;
366			break;
367
368		default:
369			warnx("unknown flag -%c ignored", optopt);
370			break;
371		}
372	}
373
374#ifdef VIRTUAL_HOSTING
375	inithosts();
376#endif
377	(void) freopen(_PATH_DEVNULL, "w", stderr);
378
379	/*
380	 * LOG_NDELAY sets up the logging connection immediately,
381	 * necessary for anonymous ftp's that chroot and can't do it later.
382	 */
383	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
384
385	if (daemon_mode) {
386		int ctl_sock, fd;
387		struct addrinfo hints, *res;
388
389		/*
390		 * Detach from parent.
391		 */
392		if (daemon(1, 1) < 0) {
393			syslog(LOG_ERR, "failed to become a daemon");
394			exit(1);
395		}
396		(void) signal(SIGCHLD, reapchild);
397		/* init bind_sa */
398		memset(&hints, 0, sizeof(hints));
399
400		hints.ai_family = family == AF_UNSPEC ? AF_INET : family;
401		hints.ai_socktype = SOCK_STREAM;
402		hints.ai_protocol = 0;
403		hints.ai_flags = AI_PASSIVE;
404		error = getaddrinfo(bindname, "ftp", &hints, &res);
405		if (error) {
406			if (family == AF_UNSPEC) {
407				hints.ai_family = AF_UNSPEC;
408				error = getaddrinfo(bindname, "ftp", &hints,
409						    &res);
410			}
411			if (error == 0 && res->ai_addr != NULL)
412				family = res->ai_addr->sa_family;
413		}
414		if (error) {
415			syslog(LOG_ERR, gai_strerror(error));
416			if (error == EAI_SYSTEM)
417				syslog(LOG_ERR, strerror(errno));
418			exit(1);
419		}
420		if (res->ai_addr == NULL) {
421			syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
422			exit(1);
423		}
424		/*
425		 * Open a socket, bind it to the FTP port, and start
426		 * listening.
427		 */
428		ctl_sock = socket(family, SOCK_STREAM, 0);
429		if (ctl_sock < 0) {
430			syslog(LOG_ERR, "control socket: %m");
431			exit(1);
432		}
433		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
434		    (char *)&on, sizeof(on)) < 0)
435			syslog(LOG_ERR, "control setsockopt: %m");
436#ifdef IPV6_BINDV6ONLY
437		if (family == AF_INET6 && enable_v4 == 0) {
438			if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
439				       (char *)&on, sizeof (on)) < 0)
440				syslog(LOG_ERR,
441				       "control setsockopt(IPV6_BINDV6ONLY): %m");
442		}
443#endif /* IPV6_BINDV6ONLY */
444		memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len);
445		if (bind(ctl_sock, (struct sockaddr *)&server_addr,
446			 server_addr.su_len) < 0) {
447			syslog(LOG_ERR, "control bind: %m");
448			exit(1);
449		}
450		if (listen(ctl_sock, 32) < 0) {
451			syslog(LOG_ERR, "control listen: %m");
452			exit(1);
453		}
454		/*
455		 * Atomically write process ID
456		 */
457		if (pid_file)
458		{
459			int fd;
460			char buf[20];
461
462			fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC
463				| O_NONBLOCK | O_EXLOCK, 0644);
464			if (fd < 0) {
465				if (errno == EAGAIN)
466					errx(1, "%s: file locked", pid_file);
467				else
468					err(1, "%s", pid_file);
469			}
470			snprintf(buf, sizeof(buf),
471				"%lu\n", (unsigned long) getpid());
472			if (write(fd, buf, strlen(buf)) < 0)
473				err(1, "%s: write", pid_file);
474			/* Leave the pid file open and locked */
475		}
476		/*
477		 * Loop forever accepting connection requests and forking off
478		 * children to handle them.
479		 */
480		while (1) {
481			addrlen = server_addr.su_len;
482			fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
483			if (fork() == 0) {
484				/* child */
485				(void) dup2(fd, 0);
486				(void) dup2(fd, 1);
487				close(ctl_sock);
488				break;
489			}
490			close(fd);
491		}
492	} else {
493		addrlen = sizeof(his_addr);
494		if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
495			syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
496			exit(1);
497		}
498	}
499
500	(void) signal(SIGCHLD, SIG_IGN);
501	(void) signal(SIGPIPE, lostconn);
502	if (signal(SIGURG, myoob) == SIG_ERR)
503		syslog(LOG_ERR, "signal: %m");
504
505#ifdef SKEY
506	getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
507		    addr_string, sizeof(addr_string) - 1, NULL, 0,
508		    NI_NUMERICHOST|NI_WITHSCOPEID);
509#endif
510	addrlen = sizeof(ctrl_addr);
511	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
512		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
513		exit(1);
514	}
515#ifdef VIRTUAL_HOSTING
516	/* select our identity from virtual host table */
517	selecthost(&ctrl_addr);
518#endif
519#ifdef IP_TOS
520	if (ctrl_addr.su_family == AF_INET)
521      {
522	tos = IPTOS_LOWDELAY;
523	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
524		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
525      }
526#endif
527	/*
528	 * Disable Nagle on the control channel so that we don't have to wait
529	 * for peer's ACK before issuing our next reply.
530	 */
531	if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
532		syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m");
533
534	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
535
536	/* set this here so klogin can use it... */
537	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
538
539	/* Try to handle urgent data inline */
540#ifdef SO_OOBINLINE
541	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
542		syslog(LOG_ERR, "setsockopt: %m");
543#endif
544
545#ifdef	F_SETOWN
546	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
547		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
548#endif
549	dolog((struct sockaddr *)&his_addr);
550	/*
551	 * Set up default state
552	 */
553	data = -1;
554	type = TYPE_A;
555	form = FORM_N;
556	stru = STRU_F;
557	mode = MODE_S;
558	tmpline[0] = '\0';
559
560	/* If logins are disabled, print out the message. */
561	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
562		while (fgets(line, sizeof(line), fd) != NULL) {
563			if ((cp = strchr(line, '\n')) != NULL)
564				*cp = '\0';
565			lreply(530, "%s", line);
566		}
567		(void) fflush(stdout);
568		(void) fclose(fd);
569		reply(530, "System not available.");
570		exit(0);
571	}
572#ifdef VIRTUAL_HOSTING
573	if ((fd = fopen(thishost->welcome, "r")) != NULL) {
574#else
575	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
576#endif
577		while (fgets(line, sizeof(line), fd) != NULL) {
578			if ((cp = strchr(line, '\n')) != NULL)
579				*cp = '\0';
580			lreply(220, "%s", line);
581		}
582		(void) fflush(stdout);
583		(void) fclose(fd);
584		/* reply(220,) must follow */
585	}
586#ifndef VIRTUAL_HOSTING
587	if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL)
588		fatal("Ran out of memory.");
589	(void) gethostname(hostname, MAXHOSTNAMELEN - 1);
590	hostname[MAXHOSTNAMELEN - 1] = '\0';
591#endif
592	reply(220, "%s FTP server (%s) ready.", hostname, version);
593	(void) setjmp(errcatch);
594	for (;;)
595		(void) yyparse();
596	/* NOTREACHED */
597}
598
599static void
600lostconn(signo)
601	int signo;
602{
603
604	if (debug)
605		syslog(LOG_DEBUG, "lost connection");
606	dologout(1);
607}
608
609#ifdef VIRTUAL_HOSTING
610/*
611 * read in virtual host tables (if they exist)
612 */
613
614static void
615inithosts()
616{
617	FILE *fp;
618	char *cp;
619	struct ftphost *hrp, *lhrp;
620	char line[1024];
621	struct addrinfo hints, *res, *ai;
622
623	/*
624	 * Fill in the default host information
625	 */
626	if (gethostname(line, sizeof(line)) < 0)
627		line[0] = '\0';
628	if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
629	    (hrp->hostname = strdup(line)) == NULL)
630		fatal("Ran out of memory.");
631	hrp->hostinfo = NULL;
632
633	memset(&hints, 0, sizeof(hints));
634	hints.ai_flags = AI_CANONNAME;
635	hints.ai_family = AF_UNSPEC;
636	getaddrinfo(hrp->hostname, NULL, &hints, &res);
637	if (res)
638		hrp->hostinfo = res;
639	hrp->statfile = _PATH_FTPDSTATFILE;
640	hrp->welcome  = _PATH_FTPWELCOME;
641	hrp->loginmsg = _PATH_FTPLOGINMESG;
642	hrp->anonuser = "ftp";
643	hrp->next = NULL;
644	thishost = firsthost = lhrp = hrp;
645	if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
646		int addrsize, error;
647		void *addr;
648		struct hostent *hp;
649
650		while (fgets(line, sizeof(line), fp) != NULL) {
651			int	i, hp_error;
652
653			if ((cp = strchr(line, '\n')) == NULL) {
654				/* ignore long lines */
655				while (fgets(line, sizeof(line), fp) != NULL &&
656					strchr(line, '\n') == NULL)
657					;
658				continue;
659			}
660			*cp = '\0';
661			cp = strtok(line, " \t");
662			/* skip comments and empty lines */
663			if (cp == NULL || line[0] == '#')
664				continue;
665
666			hints.ai_flags = 0;
667			hints.ai_family = AF_UNSPEC;
668			hints.ai_flags = AI_PASSIVE;
669			error = getaddrinfo(cp, NULL, &hints, &res);
670			if (error != NULL)
671				continue;
672			for (ai = res; ai != NULL && ai->ai_addr != NULL;
673			     ai = ai->ai_next)
674		      {
675
676			for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
677				struct addrinfo *hi;
678
679				for (hi = hrp->hostinfo; hi != NULL;
680				     hi = hi->ai_next)
681					if (hi->ai_addrlen == ai->ai_addrlen &&
682					    memcmp(hi->ai_addr,
683						   ai->ai_addr,
684						   ai->ai_addr->sa_len) == 0)
685						break;
686			}
687			if (hrp == NULL) {
688				if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
689					continue;
690				/* defaults */
691				hrp->statfile = _PATH_FTPDSTATFILE;
692				hrp->welcome  = _PATH_FTPWELCOME;
693				hrp->loginmsg = _PATH_FTPLOGINMESG;
694				hrp->anonuser = "ftp";
695				hrp->next     = NULL;
696				lhrp->next = hrp;
697				lhrp = hrp;
698			}
699			hrp->hostinfo = res;
700
701			/*
702			 * determine hostname to use.
703			 * force defined name if there is a valid alias
704			 * otherwise fallback to primary hostname
705			 */
706			/* XXX: getaddrinfo() can't do alias check */
707			switch(hrp->hostinfo->ai_family) {
708			case AF_INET:
709				addr = &((struct sockaddr_in *)&hrp->hostinfo->ai_addr)->sin_addr;
710				addrsize = sizeof(struct sockaddr_in);
711				break;
712			case AF_INET6:
713				addr = &((struct sockaddr_in6 *)&hrp->hostinfo->ai_addr)->sin6_addr;
714				addrsize = sizeof(struct sockaddr_in6);
715				break;
716			default:
717				/* should not reach here */
718				if (hrp->hostinfo != NULL)
719					freeaddrinfo(hrp->hostinfo);
720				free(hrp);
721				continue;
722				/* NOTREACHED */
723			}
724			if ((hp = getipnodebyaddr((char*)addr, addrsize,
725						  hrp->hostinfo->ai_family,
726						  &hp_error)) != NULL) {
727				if (strcmp(cp, hp->h_name) != 0) {
728					if (hp->h_aliases == NULL)
729						cp = hp->h_name;
730					else {
731						i = 0;
732						while (hp->h_aliases[i] &&
733						       strcmp(cp, hp->h_aliases[i]) != 0)
734							++i;
735						if (hp->h_aliases[i] == NULL)
736							cp = hp->h_name;
737					}
738				}
739			}
740			hrp->hostname = strdup(cp);
741			freehostent(hp);
742			/* ok, now we now peel off the rest */
743			i = 0;
744			while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
745				if (*cp != '-' && (cp = strdup(cp)) != NULL) {
746					switch (i) {
747					case 0:	/* anon user permissions */
748						hrp->anonuser = cp;
749						break;
750					case 1: /* statistics file */
751						hrp->statfile = cp;
752						break;
753					case 2: /* welcome message */
754						hrp->welcome  = cp;
755						break;
756					case 3: /* login message */
757						hrp->loginmsg = cp;
758						break;
759					}
760				}
761				++i;
762			}
763			/* XXX: re-initialization for getaddrinfo() loop */
764			cp = strtok(line, " \t");
765		      }
766		}
767		(void) fclose(fp);
768	}
769}
770
771static void
772selecthost(su)
773	union sockunion *su;
774{
775	struct ftphost	*hrp;
776	u_int16_t port;
777#ifdef INET6
778	struct in6_addr *mapped_in6 = NULL;
779#endif
780	struct addrinfo *hi;
781
782#ifdef INET6
783	/*
784	 * XXX IPv4 mapped IPv6 addr consideraton,
785	 * specified in rfc2373.
786	 */
787	if (su->su_family == AF_INET6 &&
788	    IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr))
789		mapped_in6 = &su->su_sin6.sin6_addr;
790#endif
791
792	hrp = thishost = firsthost;	/* default */
793	port = su->su_port;
794	su->su_port = 0;
795	while (hrp != NULL) {
796		for (hi = hrp->hostinfo; hi != NULL; hi = hi->ai_next)
797	      {
798		if (memcmp(su, hi->ai_addr, hi->ai_addrlen) == 0) {
799			thishost = hrp;
800			break;
801		}
802#ifdef INET6
803		/* XXX IPv4 mapped IPv6 addr consideraton */
804		if (hi->ai_addr->sa_family == AF_INET && mapped_in6 != NULL &&
805		    (memcmp(&mapped_in6->s6_addr[12],
806			    &((struct sockaddr_in *)hi->ai_addr)->sin_addr,
807			    sizeof(struct in_addr)) == 0)) {
808			thishost = hrp;
809			break;
810		}
811#endif
812	      }
813		hrp = hrp->next;
814	}
815	su->su_port = port;
816	/* setup static variables as appropriate */
817	hostname = thishost->hostname;
818	ftpuser = thishost->anonuser;
819}
820#endif
821
822/*
823 * Helper function for sgetpwnam().
824 */
825static char *
826sgetsave(s)
827	char *s;
828{
829	char *new = malloc((unsigned) strlen(s) + 1);
830
831	if (new == NULL) {
832		perror_reply(421, "Local resource failure: malloc");
833		dologout(1);
834		/* NOTREACHED */
835	}
836	(void) strcpy(new, s);
837	return (new);
838}
839
840/*
841 * Save the result of a getpwnam.  Used for USER command, since
842 * the data returned must not be clobbered by any other command
843 * (e.g., globbing).
844 */
845static struct passwd *
846sgetpwnam(name)
847	char *name;
848{
849	static struct passwd save;
850	struct passwd *p;
851
852	if ((p = getpwnam(name)) == NULL)
853		return (p);
854	if (save.pw_name) {
855		free(save.pw_name);
856		free(save.pw_passwd);
857		free(save.pw_gecos);
858		free(save.pw_dir);
859		free(save.pw_shell);
860	}
861	save = *p;
862	save.pw_name = sgetsave(p->pw_name);
863	save.pw_passwd = sgetsave(p->pw_passwd);
864	save.pw_gecos = sgetsave(p->pw_gecos);
865	save.pw_dir = sgetsave(p->pw_dir);
866	save.pw_shell = sgetsave(p->pw_shell);
867	return (&save);
868}
869
870static int login_attempts;	/* number of failed login attempts */
871static int askpasswd;		/* had user command, ask for passwd */
872static char curname[10];	/* current USER name */
873
874/*
875 * USER command.
876 * Sets global passwd pointer pw if named account exists and is acceptable;
877 * sets askpasswd if a PASS command is expected.  If logged in previously,
878 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
879 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
880 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
881 * requesting login privileges.  Disallow anyone who does not have a standard
882 * shell as returned by getusershell().  Disallow anyone mentioned in the file
883 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
884 */
885void
886user(name)
887	char *name;
888{
889	char *cp, *shell;
890
891	if (logged_in) {
892		if (guest) {
893			reply(530, "Can't change user from guest login.");
894			return;
895		} else if (dochroot) {
896			reply(530, "Can't change user from chroot user.");
897			return;
898		}
899		end_login();
900	}
901
902	guest = 0;
903	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
904		if (checkuser(_PATH_FTPUSERS, "ftp", 0) ||
905		    checkuser(_PATH_FTPUSERS, "anonymous", 0))
906			reply(530, "User %s access denied.", name);
907#ifdef VIRTUAL_HOSTING
908		else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
909#else
910		else if ((pw = sgetpwnam("ftp")) != NULL) {
911#endif
912			guest = 1;
913			askpasswd = 1;
914			reply(331,
915			"Guest login ok, send your email address as password.");
916		} else
917			reply(530, "User %s unknown.", name);
918		if (!askpasswd && logging)
919			syslog(LOG_NOTICE,
920			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
921		return;
922	}
923	if (anon_only != 0) {
924		reply(530, "Sorry, only anonymous ftp allowed.");
925		return;
926	}
927
928	if ((pw = sgetpwnam(name))) {
929		if ((shell = pw->pw_shell) == NULL || *shell == 0)
930			shell = _PATH_BSHELL;
931		while ((cp = getusershell()) != NULL)
932			if (strcmp(cp, shell) == 0)
933				break;
934		endusershell();
935
936		if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) {
937			reply(530, "User %s access denied.", name);
938			if (logging)
939				syslog(LOG_NOTICE,
940				    "FTP LOGIN REFUSED FROM %s, %s",
941				    remotehost, name);
942			pw = (struct passwd *) NULL;
943			return;
944		}
945	}
946	if (logging)
947		strncpy(curname, name, sizeof(curname)-1);
948#ifdef SKEY
949	pwok = skeyaccess(name, NULL, remotehost, addr_string);
950	reply(331, "%s", skey_challenge(name, pw, pwok));
951#else
952	reply(331, "Password required for %s.", name);
953#endif
954	askpasswd = 1;
955	/*
956	 * Delay before reading passwd after first failed
957	 * attempt to slow down passwd-guessing programs.
958	 */
959	if (login_attempts)
960		sleep((unsigned) login_attempts);
961}
962
963/*
964 * Check if a user is in the file "fname"
965 */
966static int
967checkuser(fname, name, pwset)
968	char *fname;
969	char *name;
970	int pwset;
971{
972	FILE *fd;
973	int found = 0;
974	char *p, line[BUFSIZ];
975
976	if ((fd = fopen(fname, "r")) != NULL) {
977		while (!found && fgets(line, sizeof(line), fd) != NULL)
978			if ((p = strchr(line, '\n')) != NULL) {
979				*p = '\0';
980				if (line[0] == '#')
981					continue;
982				/*
983				 * if first chr is '@', check group membership
984				 */
985				if (line[0] == '@') {
986					int i = 0;
987					struct group *grp;
988
989					if ((grp = getgrnam(line+1)) == NULL)
990						continue;
991					/*
992					 * Check user's default group
993					 */
994					if (pwset && grp->gr_gid == pw->pw_gid)
995						found = 1;
996					/*
997					 * Check supplementary groups
998					 */
999					while (!found && grp->gr_mem[i])
1000						found = strcmp(name,
1001							grp->gr_mem[i++])
1002							== 0;
1003				}
1004				/*
1005				 * Otherwise, just check for username match
1006				 */
1007				else
1008					found = strcmp(line, name) == 0;
1009			}
1010		(void) fclose(fd);
1011	}
1012	return (found);
1013}
1014
1015/*
1016 * Terminate login as previous user, if any, resetting state;
1017 * used when USER command is given or login fails.
1018 */
1019static void
1020end_login()
1021{
1022
1023	(void) seteuid((uid_t)0);
1024	if (logged_in)
1025		ftpd_logwtmp(ttyline, "", "");
1026	pw = NULL;
1027#ifdef	LOGIN_CAP
1028	setusercontext(NULL, getpwuid(0), (uid_t)0,
1029		       LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1030#endif
1031	logged_in = 0;
1032	guest = 0;
1033	dochroot = 0;
1034}
1035
1036#if !defined(NOPAM)
1037
1038/*
1039 * the following code is stolen from imap-uw PAM authentication module and
1040 * login.c
1041 */
1042#define COPY_STRING(s) (s ? strdup(s) : NULL)
1043
1044struct cred_t {
1045	const char *uname;		/* user name */
1046	const char *pass;		/* password */
1047};
1048typedef struct cred_t cred_t;
1049
1050static int
1051auth_conv(int num_msg, const struct pam_message **msg,
1052	  struct pam_response **resp, void *appdata)
1053{
1054	int i;
1055	cred_t *cred = (cred_t *) appdata;
1056	struct pam_response *reply =
1057			malloc(sizeof(struct pam_response) * num_msg);
1058
1059	for (i = 0; i < num_msg; i++) {
1060		switch (msg[i]->msg_style) {
1061		case PAM_PROMPT_ECHO_ON:	/* assume want user name */
1062			reply[i].resp_retcode = PAM_SUCCESS;
1063			reply[i].resp = COPY_STRING(cred->uname);
1064			/* PAM frees resp. */
1065			break;
1066		case PAM_PROMPT_ECHO_OFF:	/* assume want password */
1067			reply[i].resp_retcode = PAM_SUCCESS;
1068			reply[i].resp = COPY_STRING(cred->pass);
1069			/* PAM frees resp. */
1070			break;
1071		case PAM_TEXT_INFO:
1072		case PAM_ERROR_MSG:
1073			reply[i].resp_retcode = PAM_SUCCESS;
1074			reply[i].resp = NULL;
1075			break;
1076		default:			/* unknown message style */
1077			free(reply);
1078			return PAM_CONV_ERR;
1079		}
1080	}
1081
1082	*resp = reply;
1083	return PAM_SUCCESS;
1084}
1085
1086/*
1087 * Attempt to authenticate the user using PAM.  Returns 0 if the user is
1088 * authenticated, or 1 if not authenticated.  If some sort of PAM system
1089 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
1090 * function returns -1.  This can be used as an indication that we should
1091 * fall back to a different authentication mechanism.
1092 */
1093static int
1094auth_pam(struct passwd **ppw, const char *pass)
1095{
1096	pam_handle_t *pamh = NULL;
1097	const char *tmpl_user;
1098	const void *item;
1099	int rval;
1100	int e;
1101	cred_t auth_cred = { (*ppw)->pw_name, pass };
1102	struct pam_conv conv = { &auth_conv, &auth_cred };
1103
1104	e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh);
1105	if (e != PAM_SUCCESS) {
1106		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
1107		return -1;
1108	}
1109
1110	e = pam_authenticate(pamh, 0);
1111	switch (e) {
1112	case PAM_SUCCESS:
1113		/*
1114		 * With PAM we support the concept of a "template"
1115		 * user.  The user enters a login name which is
1116		 * authenticated by PAM, usually via a remote service
1117		 * such as RADIUS or TACACS+.  If authentication
1118		 * succeeds, a different but related "template" name
1119		 * is used for setting the credentials, shell, and
1120		 * home directory.  The name the user enters need only
1121		 * exist on the remote authentication server, but the
1122		 * template name must be present in the local password
1123		 * database.
1124		 *
1125		 * This is supported by two various mechanisms in the
1126		 * individual modules.  However, from the application's
1127		 * point of view, the template user is always passed
1128		 * back as a changed value of the PAM_USER item.
1129		 */
1130		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
1131		    PAM_SUCCESS) {
1132			tmpl_user = (const char *) item;
1133			if (strcmp((*ppw)->pw_name, tmpl_user) != 0)
1134				*ppw = getpwnam(tmpl_user);
1135		} else
1136			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
1137			    pam_strerror(pamh, e));
1138		rval = 0;
1139		break;
1140
1141	case PAM_AUTH_ERR:
1142	case PAM_USER_UNKNOWN:
1143	case PAM_MAXTRIES:
1144		rval = 1;
1145		break;
1146
1147	default:
1148		syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
1149		rval = -1;
1150		break;
1151	}
1152
1153	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
1154		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1155		rval = -1;
1156	}
1157	return rval;
1158}
1159
1160#endif /* !defined(NOPAM) */
1161
1162void
1163pass(passwd)
1164	char *passwd;
1165{
1166	int rval;
1167	FILE *fd;
1168#ifdef	LOGIN_CAP
1169	login_cap_t *lc = NULL;
1170#endif
1171
1172	if (logged_in || askpasswd == 0) {
1173		reply(503, "Login with USER first.");
1174		return;
1175	}
1176	askpasswd = 0;
1177	if (!guest) {		/* "ftp" is only account allowed no password */
1178		if (pw == NULL) {
1179			rval = 1;	/* failure below */
1180			goto skip;
1181		}
1182#if !defined(NOPAM)
1183		rval = auth_pam(&pw, passwd);
1184		if (rval >= 0)
1185			goto skip;
1186#endif
1187#ifdef SKEY
1188		rval = strcmp(skey_crypt(passwd, pw->pw_passwd, pw, pwok),
1189			      pw->pw_passwd);
1190		pwok = 0;
1191#else
1192		rval = strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd);
1193#endif
1194		/* The strcmp does not catch null passwords! */
1195		if (*pw->pw_passwd == '\0' ||
1196		    (pw->pw_expire && time(NULL) >= pw->pw_expire))
1197			rval = 1;	/* failure */
1198skip:
1199		/*
1200		 * If rval == 1, the user failed the authentication check
1201		 * above.  If rval == 0, either PAM or local authentication
1202		 * succeeded.
1203		 */
1204		if (rval) {
1205			reply(530, "Login incorrect.");
1206			if (logging)
1207				syslog(LOG_NOTICE,
1208				    "FTP LOGIN FAILED FROM %s, %s",
1209				    remotehost, curname);
1210			pw = NULL;
1211			if (login_attempts++ >= 5) {
1212				syslog(LOG_NOTICE,
1213				    "repeated login failures from %s",
1214				    remotehost);
1215				exit(0);
1216			}
1217			return;
1218		}
1219	}
1220	login_attempts = 0;		/* this time successful */
1221	if (setegid((gid_t)pw->pw_gid) < 0) {
1222		reply(550, "Can't set gid.");
1223		return;
1224	}
1225	/* May be overridden by login.conf */
1226	(void) umask(defumask);
1227#ifdef	LOGIN_CAP
1228	if ((lc = login_getpwclass(pw)) != NULL) {
1229		char	remote_ip[MAXHOSTNAMELEN];
1230
1231		getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1232			remote_ip, sizeof(remote_ip) - 1, NULL, 0,
1233			NI_NUMERICHOST|NI_WITHSCOPEID);
1234		remote_ip[sizeof(remote_ip) - 1] = 0;
1235		if (!auth_hostok(lc, remotehost, remote_ip)) {
1236			syslog(LOG_INFO|LOG_AUTH,
1237			    "FTP LOGIN FAILED (HOST) as %s: permission denied.",
1238			    pw->pw_name);
1239			reply(530, "Permission denied.\n");
1240			pw = NULL;
1241			return;
1242		}
1243		if (!auth_timeok(lc, time(NULL))) {
1244			reply(530, "Login not available right now.\n");
1245			pw = NULL;
1246			return;
1247		}
1248	}
1249	setusercontext(lc, pw, (uid_t)0,
1250		LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
1251		LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1252#else
1253	setlogin(pw->pw_name);
1254	(void) initgroups(pw->pw_name, pw->pw_gid);
1255#endif
1256
1257	/* open wtmp before chroot */
1258	ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
1259	logged_in = 1;
1260
1261	if (guest && stats && statfd < 0)
1262#ifdef VIRTUAL_HOSTING
1263		if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
1264#else
1265		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
1266#endif
1267			stats = 0;
1268
1269	dochroot =
1270#ifdef	LOGIN_CAP	/* Allow login.conf configuration as well */
1271		login_getcapbool(lc, "ftp-chroot", 0) ||
1272#endif
1273		checkuser(_PATH_FTPCHROOT, pw->pw_name, 1);
1274	if (guest) {
1275		/*
1276		 * We MUST do a chdir() after the chroot. Otherwise
1277		 * the old current directory will be accessible as "."
1278		 * outside the new root!
1279		 */
1280		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1281			reply(550, "Can't set guest privileges.");
1282			goto bad;
1283		}
1284	} else if (dochroot) {
1285		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1286			reply(550, "Can't change root.");
1287			goto bad;
1288		}
1289	} else if (chdir(pw->pw_dir) < 0) {
1290		if (chdir("/") < 0) {
1291			reply(530, "User %s: can't change directory to %s.",
1292			    pw->pw_name, pw->pw_dir);
1293			goto bad;
1294		} else
1295			lreply(230, "No directory! Logging in with home=/");
1296	}
1297	if (seteuid((uid_t)pw->pw_uid) < 0) {
1298		reply(550, "Can't set uid.");
1299		goto bad;
1300	}
1301
1302	/*
1303	 * Display a login message, if it exists.
1304	 * N.B. reply(230,) must follow the message.
1305	 */
1306#ifdef VIRTUAL_HOSTING
1307	if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
1308#else
1309	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
1310#endif
1311		char *cp, line[LINE_MAX];
1312
1313		while (fgets(line, sizeof(line), fd) != NULL) {
1314			if ((cp = strchr(line, '\n')) != NULL)
1315				*cp = '\0';
1316			lreply(230, "%s", line);
1317		}
1318		(void) fflush(stdout);
1319		(void) fclose(fd);
1320	}
1321	if (guest) {
1322		if (ident != NULL)
1323			free(ident);
1324		ident = strdup(passwd);
1325		if (ident == NULL)
1326			fatal("Ran out of memory.");
1327
1328		reply(230, "Guest login ok, access restrictions apply.");
1329#ifdef SETPROCTITLE
1330#ifdef VIRTUAL_HOSTING
1331		if (thishost != firsthost)
1332			snprintf(proctitle, sizeof(proctitle),
1333				 "%s: anonymous(%s)/%.*s", remotehost, hostname,
1334				 (int)(sizeof(proctitle) - sizeof(remotehost) -
1335				 sizeof(": anonymous/")), passwd);
1336		else
1337#endif
1338			snprintf(proctitle, sizeof(proctitle),
1339				 "%s: anonymous/%.*s", remotehost,
1340				 (int)(sizeof(proctitle) - sizeof(remotehost) -
1341				 sizeof(": anonymous/")), passwd);
1342		setproctitle("%s", proctitle);
1343#endif /* SETPROCTITLE */
1344		if (logging)
1345			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1346			    remotehost, passwd);
1347	} else {
1348	    if (dochroot)
1349		reply(230, "User %s logged in, access restrictions apply.",
1350			pw->pw_name);
1351	    else
1352		reply(230, "User %s logged in.", pw->pw_name);
1353
1354#ifdef SETPROCTITLE
1355		snprintf(proctitle, sizeof(proctitle),
1356			 "%s: %s", remotehost, pw->pw_name);
1357		setproctitle("%s", proctitle);
1358#endif /* SETPROCTITLE */
1359		if (logging)
1360			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1361			    remotehost, pw->pw_name);
1362	}
1363#ifdef	LOGIN_CAP
1364	login_close(lc);
1365#endif
1366	return;
1367bad:
1368	/* Forget all about it... */
1369#ifdef	LOGIN_CAP
1370	login_close(lc);
1371#endif
1372	end_login();
1373}
1374
1375void
1376retrieve(cmd, name)
1377	char *cmd, *name;
1378{
1379	FILE *fin, *dout;
1380	struct stat st;
1381	int (*closefunc) __P((FILE *));
1382	time_t start;
1383
1384	if (cmd == 0) {
1385		fin = fopen(name, "r"), closefunc = fclose;
1386		st.st_size = 0;
1387	} else {
1388		char line[BUFSIZ];
1389
1390		(void) snprintf(line, sizeof(line), cmd, name), name = line;
1391		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1392		st.st_size = -1;
1393		st.st_blksize = BUFSIZ;
1394	}
1395	if (fin == NULL) {
1396		if (errno != 0) {
1397			perror_reply(550, name);
1398			if (cmd == 0) {
1399				LOGCMD("get", name);
1400			}
1401		}
1402		return;
1403	}
1404	byte_count = -1;
1405	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1406		reply(550, "%s: not a plain file.", name);
1407		goto done;
1408	}
1409	if (restart_point) {
1410		if (type == TYPE_A) {
1411			off_t i, n;
1412			int c;
1413
1414			n = restart_point;
1415			i = 0;
1416			while (i++ < n) {
1417				if ((c=getc(fin)) == EOF) {
1418					perror_reply(550, name);
1419					goto done;
1420				}
1421				if (c == '\n')
1422					i++;
1423			}
1424		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
1425			perror_reply(550, name);
1426			goto done;
1427		}
1428	}
1429	dout = dataconn(name, st.st_size, "w");
1430	if (dout == NULL)
1431		goto done;
1432	time(&start);
1433	send_data(fin, dout, st.st_blksize, st.st_size,
1434		  restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
1435	if (cmd == 0 && guest && stats)
1436		logxfer(name, st.st_size, start);
1437	(void) fclose(dout);
1438	data = -1;
1439	pdata = -1;
1440done:
1441	if (cmd == 0)
1442		LOGBYTES("get", name, byte_count);
1443	(*closefunc)(fin);
1444}
1445
1446void
1447store(name, mode, unique)
1448	char *name, *mode;
1449	int unique;
1450{
1451	FILE *fout, *din;
1452	struct stat st;
1453	int (*closefunc) __P((FILE *));
1454
1455	if ((unique || guest) && stat(name, &st) == 0 &&
1456	    (name = gunique(name)) == NULL) {
1457		LOGCMD(*mode == 'w' ? "put" : "append", name);
1458		return;
1459	}
1460
1461	if (restart_point)
1462		mode = "r+";
1463	fout = fopen(name, mode);
1464	closefunc = fclose;
1465	if (fout == NULL) {
1466		perror_reply(553, name);
1467		LOGCMD(*mode == 'w' ? "put" : "append", name);
1468		return;
1469	}
1470	byte_count = -1;
1471	if (restart_point) {
1472		if (type == TYPE_A) {
1473			off_t i, n;
1474			int c;
1475
1476			n = restart_point;
1477			i = 0;
1478			while (i++ < n) {
1479				if ((c=getc(fout)) == EOF) {
1480					perror_reply(550, name);
1481					goto done;
1482				}
1483				if (c == '\n')
1484					i++;
1485			}
1486			/*
1487			 * We must do this seek to "current" position
1488			 * because we are changing from reading to
1489			 * writing.
1490			 */
1491			if (fseek(fout, 0L, L_INCR) < 0) {
1492				perror_reply(550, name);
1493				goto done;
1494			}
1495		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
1496			perror_reply(550, name);
1497			goto done;
1498		}
1499	}
1500	din = dataconn(name, (off_t)-1, "r");
1501	if (din == NULL)
1502		goto done;
1503	if (receive_data(din, fout) == 0) {
1504		if (unique)
1505			reply(226, "Transfer complete (unique file name:%s).",
1506			    name);
1507		else
1508			reply(226, "Transfer complete.");
1509	}
1510	(void) fclose(din);
1511	data = -1;
1512	pdata = -1;
1513done:
1514	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1515	(*closefunc)(fout);
1516}
1517
1518static FILE *
1519getdatasock(mode)
1520	char *mode;
1521{
1522	int on = 1, s, t, tries;
1523
1524	if (data >= 0)
1525		return (fdopen(data, mode));
1526	(void) seteuid((uid_t)0);
1527
1528	s = socket(data_dest.su_family, SOCK_STREAM, 0);
1529	if (s < 0)
1530		goto bad;
1531	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1532	    (char *) &on, sizeof(on)) < 0)
1533		goto bad;
1534	/* anchor socket to avoid multi-homing problems */
1535	data_source = ctrl_addr;
1536	data_source.su_port = htons(20); /* ftp-data port */
1537	for (tries = 1; ; tries++) {
1538		if (bind(s, (struct sockaddr *)&data_source,
1539		    data_source.su_len) >= 0)
1540			break;
1541		if (errno != EADDRINUSE || tries > 10)
1542			goto bad;
1543		sleep(tries);
1544	}
1545	(void) seteuid((uid_t)pw->pw_uid);
1546#ifdef IP_TOS
1547	if (data_source.su_family == AF_INET)
1548      {
1549	on = IPTOS_THROUGHPUT;
1550	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1551		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1552      }
1553#endif
1554#ifdef TCP_NOPUSH
1555	/*
1556	 * Turn off push flag to keep sender TCP from sending short packets
1557	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1558	 * to set the send buffer size as well, but that may not be desirable
1559	 * in heavy-load situations.
1560	 */
1561	on = 1;
1562	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1563		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1564#endif
1565#ifdef SO_SNDBUF
1566	on = 65536;
1567	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1568		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1569#endif
1570
1571	return (fdopen(s, mode));
1572bad:
1573	/* Return the real value of errno (close may change it) */
1574	t = errno;
1575	(void) seteuid((uid_t)pw->pw_uid);
1576	(void) close(s);
1577	errno = t;
1578	return (NULL);
1579}
1580
1581static FILE *
1582dataconn(name, size, mode)
1583	char *name;
1584	off_t size;
1585	char *mode;
1586{
1587	char sizebuf[32];
1588	FILE *file;
1589	int retry = 0, tos;
1590
1591	file_size = size;
1592	byte_count = 0;
1593	if (size != (off_t) -1)
1594		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size);
1595	else
1596		*sizebuf = '\0';
1597	if (pdata >= 0) {
1598		union sockunion from;
1599		int s, fromlen = ctrl_addr.su_len;
1600		struct timeval timeout;
1601		fd_set set;
1602
1603		FD_ZERO(&set);
1604		FD_SET(pdata, &set);
1605
1606		timeout.tv_usec = 0;
1607		timeout.tv_sec = 120;
1608
1609		if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
1610		    (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
1611			reply(425, "Can't open data connection.");
1612			(void) close(pdata);
1613			pdata = -1;
1614			return (NULL);
1615		}
1616		(void) close(pdata);
1617		pdata = s;
1618#ifdef IP_TOS
1619		if (from.su_family == AF_INET)
1620	      {
1621		tos = IPTOS_THROUGHPUT;
1622		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1623		    sizeof(int));
1624	      }
1625#endif
1626		reply(150, "Opening %s mode data connection for '%s'%s.",
1627		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1628		return (fdopen(pdata, mode));
1629	}
1630	if (data >= 0) {
1631		reply(125, "Using existing data connection for '%s'%s.",
1632		    name, sizebuf);
1633		usedefault = 1;
1634		return (fdopen(data, mode));
1635	}
1636	if (usedefault)
1637		data_dest = his_addr;
1638	usedefault = 1;
1639	file = getdatasock(mode);
1640	if (file == NULL) {
1641		char hostbuf[BUFSIZ], portbuf[BUFSIZ];
1642		getnameinfo((struct sockaddr *)&data_source,
1643			data_source.su_len, hostbuf, sizeof(hostbuf) - 1,
1644			portbuf, sizeof(portbuf),
1645			NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID);
1646		reply(425, "Can't create data socket (%s,%s): %s.",
1647			hostbuf, portbuf, strerror(errno));
1648		return (NULL);
1649	}
1650	data = fileno(file);
1651	while (connect(data, (struct sockaddr *)&data_dest,
1652	    data_dest.su_len) < 0) {
1653		if (errno == EADDRINUSE && retry < swaitmax) {
1654			sleep((unsigned) swaitint);
1655			retry += swaitint;
1656			continue;
1657		}
1658		perror_reply(425, "Can't build data connection");
1659		(void) fclose(file);
1660		data = -1;
1661		return (NULL);
1662	}
1663	reply(150, "Opening %s mode data connection for '%s'%s.",
1664	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1665	return (file);
1666}
1667
1668/*
1669 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1670 * encapsulation of the data subject to Mode, Structure, and Type.
1671 *
1672 * NB: Form isn't handled.
1673 */
1674static void
1675send_data(instr, outstr, blksize, filesize, isreg)
1676	FILE *instr, *outstr;
1677	off_t blksize;
1678	off_t filesize;
1679	int isreg;
1680{
1681	int c, cnt, filefd, netfd;
1682	char *buf, *bp;
1683	size_t len;
1684
1685	transflag++;
1686	if (setjmp(urgcatch)) {
1687		transflag = 0;
1688		return;
1689	}
1690	switch (type) {
1691
1692	case TYPE_A:
1693		while ((c = getc(instr)) != EOF) {
1694			byte_count++;
1695			if (c == '\n') {
1696				if (ferror(outstr))
1697					goto data_err;
1698				(void) putc('\r', outstr);
1699			}
1700			(void) putc(c, outstr);
1701		}
1702		fflush(outstr);
1703		transflag = 0;
1704		if (ferror(instr))
1705			goto file_err;
1706		if (ferror(outstr))
1707			goto data_err;
1708		reply(226, "Transfer complete.");
1709		return;
1710
1711	case TYPE_I:
1712	case TYPE_L:
1713		/*
1714		 * isreg is only set if we are not doing restart and we
1715		 * are sending a regular file
1716		 */
1717		netfd = fileno(outstr);
1718		filefd = fileno(instr);
1719
1720		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1721			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1722				   (off_t)0);
1723			if (buf == MAP_FAILED) {
1724				syslog(LOG_WARNING, "mmap(%lu): %m",
1725				       (unsigned long)filesize);
1726				goto oldway;
1727			}
1728			bp = buf;
1729			len = filesize;
1730			do {
1731				cnt = write(netfd, bp, len);
1732				len -= cnt;
1733				bp += cnt;
1734				if (cnt > 0) byte_count += cnt;
1735			} while(cnt > 0 && len > 0);
1736
1737			transflag = 0;
1738			munmap(buf, (size_t)filesize);
1739			if (cnt < 0)
1740				goto data_err;
1741			reply(226, "Transfer complete.");
1742			return;
1743		}
1744
1745oldway:
1746		if ((buf = malloc((u_int)blksize)) == NULL) {
1747			transflag = 0;
1748			perror_reply(451, "Local resource failure: malloc");
1749			return;
1750		}
1751
1752		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1753		    write(netfd, buf, cnt) == cnt)
1754			byte_count += cnt;
1755		transflag = 0;
1756		(void)free(buf);
1757		if (cnt != 0) {
1758			if (cnt < 0)
1759				goto file_err;
1760			goto data_err;
1761		}
1762		reply(226, "Transfer complete.");
1763		return;
1764	default:
1765		transflag = 0;
1766		reply(550, "Unimplemented TYPE %d in send_data", type);
1767		return;
1768	}
1769
1770data_err:
1771	transflag = 0;
1772	perror_reply(426, "Data connection");
1773	return;
1774
1775file_err:
1776	transflag = 0;
1777	perror_reply(551, "Error on input file");
1778}
1779
1780/*
1781 * Transfer data from peer to "outstr" using the appropriate encapulation of
1782 * the data subject to Mode, Structure, and Type.
1783 *
1784 * N.B.: Form isn't handled.
1785 */
1786static int
1787receive_data(instr, outstr)
1788	FILE *instr, *outstr;
1789{
1790	int c;
1791	int cnt, bare_lfs;
1792	char buf[BUFSIZ];
1793
1794	transflag++;
1795	if (setjmp(urgcatch)) {
1796		transflag = 0;
1797		return (-1);
1798	}
1799
1800	bare_lfs = 0;
1801
1802	switch (type) {
1803
1804	case TYPE_I:
1805	case TYPE_L:
1806		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1807			if (write(fileno(outstr), buf, cnt) != cnt)
1808				goto file_err;
1809			byte_count += cnt;
1810		}
1811		if (cnt < 0)
1812			goto data_err;
1813		transflag = 0;
1814		return (0);
1815
1816	case TYPE_E:
1817		reply(553, "TYPE E not implemented.");
1818		transflag = 0;
1819		return (-1);
1820
1821	case TYPE_A:
1822		while ((c = getc(instr)) != EOF) {
1823			byte_count++;
1824			if (c == '\n')
1825				bare_lfs++;
1826			while (c == '\r') {
1827				if (ferror(outstr))
1828					goto data_err;
1829				if ((c = getc(instr)) != '\n') {
1830					(void) putc ('\r', outstr);
1831					if (c == '\0' || c == EOF)
1832						goto contin2;
1833				}
1834			}
1835			(void) putc(c, outstr);
1836	contin2:	;
1837		}
1838		fflush(outstr);
1839		if (ferror(instr))
1840			goto data_err;
1841		if (ferror(outstr))
1842			goto file_err;
1843		transflag = 0;
1844		if (bare_lfs) {
1845			lreply(226,
1846		"WARNING! %d bare linefeeds received in ASCII mode",
1847			    bare_lfs);
1848		(void)printf("   File may not have transferred correctly.\r\n");
1849		}
1850		return (0);
1851	default:
1852		reply(550, "Unimplemented TYPE %d in receive_data", type);
1853		transflag = 0;
1854		return (-1);
1855	}
1856
1857data_err:
1858	transflag = 0;
1859	perror_reply(426, "Data Connection");
1860	return (-1);
1861
1862file_err:
1863	transflag = 0;
1864	perror_reply(452, "Error writing file");
1865	return (-1);
1866}
1867
1868void
1869statfilecmd(filename)
1870	char *filename;
1871{
1872	FILE *fin;
1873	int c;
1874	char line[LINE_MAX];
1875
1876	(void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename);
1877	fin = ftpd_popen(line, "r");
1878	lreply(211, "status of %s:", filename);
1879	while ((c = getc(fin)) != EOF) {
1880		if (c == '\n') {
1881			if (ferror(stdout)){
1882				perror_reply(421, "control connection");
1883				(void) ftpd_pclose(fin);
1884				dologout(1);
1885				/* NOTREACHED */
1886			}
1887			if (ferror(fin)) {
1888				perror_reply(551, filename);
1889				(void) ftpd_pclose(fin);
1890				return;
1891			}
1892			(void) putc('\r', stdout);
1893		}
1894		(void) putc(c, stdout);
1895	}
1896	(void) ftpd_pclose(fin);
1897	reply(211, "End of Status");
1898}
1899
1900void
1901statcmd()
1902{
1903	union sockunion *su;
1904	u_char *a, *p;
1905	char hname[INET6_ADDRSTRLEN];
1906	int ispassive;
1907
1908	lreply(211, "%s FTP server status:", hostname, version);
1909	printf("     %s\r\n", version);
1910	printf("     Connected to %s", remotehost);
1911	if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1912			 hname, sizeof(hname) - 1, NULL, 0,
1913			 NI_NUMERICHOST|NI_WITHSCOPEID)) {
1914		if (strcmp(hname, remotehost) != 0)
1915			printf(" (%s)", hname);
1916	}
1917	printf("\r\n");
1918	if (logged_in) {
1919		if (guest)
1920			printf("     Logged in anonymously\r\n");
1921		else
1922			printf("     Logged in as %s\r\n", pw->pw_name);
1923	} else if (askpasswd)
1924		printf("     Waiting for password\r\n");
1925	else
1926		printf("     Waiting for user name\r\n");
1927	printf("     TYPE: %s", typenames[type]);
1928	if (type == TYPE_A || type == TYPE_E)
1929		printf(", FORM: %s", formnames[form]);
1930	if (type == TYPE_L)
1931#if NBBY == 8
1932		printf(" %d", NBBY);
1933#else
1934		printf(" %d", bytesize);	/* need definition! */
1935#endif
1936	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1937	    strunames[stru], modenames[mode]);
1938	if (data != -1)
1939		printf("     Data connection open\r\n");
1940	else if (pdata != -1) {
1941		ispassive = 1;
1942		su = &pasv_addr;
1943		goto printaddr;
1944	} else if (usedefault == 0) {
1945		ispassive = 0;
1946		su = &data_dest;
1947printaddr:
1948#define UC(b) (((int) b) & 0xff)
1949		if (epsvall) {
1950			printf("     EPSV only mode (EPSV ALL)\r\n");
1951			goto epsvonly;
1952		}
1953
1954		/* PORT/PASV */
1955		if (su->su_family == AF_INET) {
1956			a = (u_char *) &su->su_sin.sin_addr;
1957			p = (u_char *) &su->su_sin.sin_port;
1958			printf("     %s (%d,%d,%d,%d,%d,%d)\r\n",
1959				ispassive ? "PASV" : "PORT",
1960				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1961				UC(p[0]), UC(p[1]));
1962		}
1963
1964		/* LPRT/LPSV */
1965	    {
1966		int alen, af, i;
1967
1968		switch (su->su_family) {
1969		case AF_INET:
1970			a = (u_char *) &su->su_sin.sin_addr;
1971			p = (u_char *) &su->su_sin.sin_port;
1972			alen = sizeof(su->su_sin.sin_addr);
1973			af = 4;
1974			break;
1975		case AF_INET6:
1976			a = (u_char *) &su->su_sin6.sin6_addr;
1977			p = (u_char *) &su->su_sin6.sin6_port;
1978			alen = sizeof(su->su_sin6.sin6_addr);
1979			af = 6;
1980			break;
1981		default:
1982			af = 0;
1983			break;
1984		}
1985		if (af) {
1986			printf("     %s (%d,%d,", ispassive ? "LPSV" : "LPRT",
1987				af, alen);
1988			for (i = 0; i < alen; i++)
1989				printf("%d,", UC(a[i]));
1990			printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
1991		}
1992	    }
1993
1994epsvonly:;
1995		/* EPRT/EPSV */
1996	    {
1997		int af;
1998
1999		switch (su->su_family) {
2000		case AF_INET:
2001			af = 1;
2002			break;
2003		case AF_INET6:
2004			af = 2;
2005			break;
2006		default:
2007			af = 0;
2008			break;
2009		}
2010		if (af) {
2011			if (!getnameinfo((struct sockaddr *)su, su->su_len,
2012					hname, sizeof(hname) - 1, NULL, 0,
2013					NI_NUMERICHOST)) {
2014				printf("     %s |%d|%s|%d|\r\n",
2015					ispassive ? "EPSV" : "EPRT",
2016					af, hname, htons(su->su_port));
2017			}
2018		}
2019	    }
2020#undef UC
2021	} else
2022		printf("     No data connection\r\n");
2023	reply(211, "End of status");
2024}
2025
2026void
2027fatal(s)
2028	char *s;
2029{
2030
2031	reply(451, "Error in server: %s\n", s);
2032	reply(221, "Closing connection due to server error.");
2033	dologout(0);
2034	/* NOTREACHED */
2035}
2036
2037void
2038#if __STDC__
2039reply(int n, const char *fmt, ...)
2040#else
2041reply(n, fmt, va_alist)
2042	int n;
2043	char *fmt;
2044        va_dcl
2045#endif
2046{
2047	va_list ap;
2048#if __STDC__
2049	va_start(ap, fmt);
2050#else
2051	va_start(ap);
2052#endif
2053	(void)printf("%d ", n);
2054	(void)vprintf(fmt, ap);
2055	(void)printf("\r\n");
2056	(void)fflush(stdout);
2057	if (debug) {
2058		syslog(LOG_DEBUG, "<--- %d ", n);
2059		vsyslog(LOG_DEBUG, fmt, ap);
2060	}
2061}
2062
2063void
2064#if __STDC__
2065lreply(int n, const char *fmt, ...)
2066#else
2067lreply(n, fmt, va_alist)
2068	int n;
2069	char *fmt;
2070        va_dcl
2071#endif
2072{
2073	va_list ap;
2074#if __STDC__
2075	va_start(ap, fmt);
2076#else
2077	va_start(ap);
2078#endif
2079	(void)printf("%d- ", n);
2080	(void)vprintf(fmt, ap);
2081	(void)printf("\r\n");
2082	(void)fflush(stdout);
2083	if (debug) {
2084		syslog(LOG_DEBUG, "<--- %d- ", n);
2085		vsyslog(LOG_DEBUG, fmt, ap);
2086	}
2087}
2088
2089static void
2090ack(s)
2091	char *s;
2092{
2093
2094	reply(250, "%s command successful.", s);
2095}
2096
2097void
2098nack(s)
2099	char *s;
2100{
2101
2102	reply(502, "%s command not implemented.", s);
2103}
2104
2105/* ARGSUSED */
2106void
2107yyerror(s)
2108	char *s;
2109{
2110	char *cp;
2111
2112	if ((cp = strchr(cbuf,'\n')))
2113		*cp = '\0';
2114	reply(500, "'%s': command not understood.", cbuf);
2115}
2116
2117void
2118delete(name)
2119	char *name;
2120{
2121	struct stat st;
2122
2123	LOGCMD("delete", name);
2124	if (stat(name, &st) < 0) {
2125		perror_reply(550, name);
2126		return;
2127	}
2128	if ((st.st_mode&S_IFMT) == S_IFDIR) {
2129		if (rmdir(name) < 0) {
2130			perror_reply(550, name);
2131			return;
2132		}
2133		goto done;
2134	}
2135	if (unlink(name) < 0) {
2136		perror_reply(550, name);
2137		return;
2138	}
2139done:
2140	ack("DELE");
2141}
2142
2143void
2144cwd(path)
2145	char *path;
2146{
2147
2148	if (chdir(path) < 0)
2149		perror_reply(550, path);
2150	else
2151		ack("CWD");
2152}
2153
2154void
2155makedir(name)
2156	char *name;
2157{
2158
2159	LOGCMD("mkdir", name);
2160	if (mkdir(name, 0777) < 0)
2161		perror_reply(550, name);
2162	else
2163		reply(257, "MKD command successful.");
2164}
2165
2166void
2167removedir(name)
2168	char *name;
2169{
2170
2171	LOGCMD("rmdir", name);
2172	if (rmdir(name) < 0)
2173		perror_reply(550, name);
2174	else
2175		ack("RMD");
2176}
2177
2178void
2179pwd()
2180{
2181	char path[MAXPATHLEN + 1];
2182
2183	if (getwd(path) == (char *)NULL)
2184		reply(550, "%s.", path);
2185	else
2186		reply(257, "\"%s\" is current directory.", path);
2187}
2188
2189char *
2190renamefrom(name)
2191	char *name;
2192{
2193	struct stat st;
2194
2195	if (stat(name, &st) < 0) {
2196		perror_reply(550, name);
2197		return ((char *)0);
2198	}
2199	reply(350, "File exists, ready for destination name");
2200	return (name);
2201}
2202
2203void
2204renamecmd(from, to)
2205	char *from, *to;
2206{
2207	struct stat st;
2208
2209	LOGCMD2("rename", from, to);
2210
2211	if (guest && (stat(to, &st) == 0)) {
2212		reply(550, "%s: permission denied", to);
2213		return;
2214	}
2215
2216	if (rename(from, to) < 0)
2217		perror_reply(550, "rename");
2218	else
2219		ack("RNTO");
2220}
2221
2222static void
2223dolog(who)
2224	struct sockaddr *who;
2225{
2226	int error;
2227
2228	realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len);
2229
2230#ifdef SETPROCTITLE
2231#ifdef VIRTUAL_HOSTING
2232	if (thishost != firsthost)
2233		snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
2234			 remotehost, hostname);
2235	else
2236#endif
2237		snprintf(proctitle, sizeof(proctitle), "%s: connected",
2238			 remotehost);
2239	setproctitle("%s", proctitle);
2240#endif /* SETPROCTITLE */
2241
2242	if (logging) {
2243#ifdef VIRTUAL_HOSTING
2244		if (thishost != firsthost)
2245			syslog(LOG_INFO, "connection from %s (to %s)",
2246			       remotehost, hostname);
2247		else
2248#endif
2249		{
2250			char	who_name[MAXHOSTNAMELEN];
2251
2252			error = getnameinfo(who, who->sa_len,
2253					    who_name, sizeof(who_name) - 1,
2254					    NULL, 0,
2255					    NI_NUMERICHOST|NI_WITHSCOPEID);
2256			syslog(LOG_INFO, "connection from %s (%s)", remotehost,
2257			       error == 0 ? who_name : "");
2258		}
2259	}
2260}
2261
2262/*
2263 * Record logout in wtmp file
2264 * and exit with supplied status.
2265 */
2266void
2267dologout(status)
2268	int status;
2269{
2270	/*
2271	 * Prevent reception of SIGURG from resulting in a resumption
2272	 * back to the main program loop.
2273	 */
2274	transflag = 0;
2275
2276	if (logged_in) {
2277		(void) seteuid((uid_t)0);
2278		ftpd_logwtmp(ttyline, "", "");
2279	}
2280	/* beware of flushing buffers after a SIGPIPE */
2281	_exit(status);
2282}
2283
2284static void
2285myoob(signo)
2286	int signo;
2287{
2288	char *cp;
2289
2290	/* only process if transfer occurring */
2291	if (!transflag)
2292		return;
2293	cp = tmpline;
2294	if (getline(cp, 7, stdin) == NULL) {
2295		reply(221, "You could at least say goodbye.");
2296		dologout(0);
2297	}
2298	upper(cp);
2299	if (strcmp(cp, "ABOR\r\n") == 0) {
2300		tmpline[0] = '\0';
2301		reply(426, "Transfer aborted. Data connection closed.");
2302		reply(226, "Abort successful");
2303		longjmp(urgcatch, 1);
2304	}
2305	if (strcmp(cp, "STAT\r\n") == 0) {
2306		tmpline[0] = '\0';
2307		if (file_size != (off_t) -1)
2308			reply(213, "Status: %qd of %qd bytes transferred",
2309			    byte_count, file_size);
2310		else
2311			reply(213, "Status: %qd bytes transferred", byte_count);
2312	}
2313}
2314
2315/*
2316 * Note: a response of 425 is not mentioned as a possible response to
2317 *	the PASV command in RFC959. However, it has been blessed as
2318 *	a legitimate response by Jon Postel in a telephone conversation
2319 *	with Rick Adams on 25 Jan 89.
2320 */
2321void
2322passive()
2323{
2324	int len;
2325	char *p, *a;
2326
2327	if (pdata >= 0)		/* close old port if one set */
2328		close(pdata);
2329
2330	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2331	if (pdata < 0) {
2332		perror_reply(425, "Can't open passive connection");
2333		return;
2334	}
2335
2336	(void) seteuid((uid_t)0);
2337
2338#ifdef IP_PORTRANGE
2339	if (ctrl_addr.su_family == AF_INET) {
2340	    int on = restricted_data_ports ? IP_PORTRANGE_HIGH
2341					   : IP_PORTRANGE_DEFAULT;
2342
2343	    if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2344			    (char *)&on, sizeof(on)) < 0)
2345		    goto pasv_error;
2346	}
2347#endif
2348#ifdef IPV6_PORTRANGE
2349	if (ctrl_addr.su_family == AF_INET6) {
2350	    int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
2351					   : IPV6_PORTRANGE_DEFAULT;
2352
2353	    if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2354			    (char *)&on, sizeof(on)) < 0)
2355		    goto pasv_error;
2356	}
2357#endif
2358
2359	pasv_addr = ctrl_addr;
2360	pasv_addr.su_port = 0;
2361	if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0)
2362		goto pasv_error;
2363
2364	(void) seteuid((uid_t)pw->pw_uid);
2365
2366	len = sizeof(pasv_addr);
2367	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2368		goto pasv_error;
2369	if (listen(pdata, 1) < 0)
2370		goto pasv_error;
2371	if (pasv_addr.su_family == AF_INET)
2372		a = (char *) &pasv_addr.su_sin.sin_addr;
2373	else if (pasv_addr.su_family == AF_INET6 &&
2374		 IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr))
2375		a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
2376	else
2377		goto pasv_error;
2378
2379	p = (char *) &pasv_addr.su_port;
2380
2381#define UC(b) (((int) b) & 0xff)
2382
2383	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2384		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2385	return;
2386
2387pasv_error:
2388	(void) seteuid((uid_t)pw->pw_uid);
2389	(void) close(pdata);
2390	pdata = -1;
2391	perror_reply(425, "Can't open passive connection");
2392	return;
2393}
2394
2395/*
2396 * Long Passive defined in RFC 1639.
2397 *     228 Entering Long Passive Mode
2398 *         (af, hal, h1, h2, h3,..., pal, p1, p2...)
2399 */
2400
2401void
2402long_passive(cmd, pf)
2403	char *cmd;
2404	int pf;
2405{
2406	int len;
2407	char *p, *a;
2408
2409	if (pdata >= 0)		/* close old port if one set */
2410		close(pdata);
2411
2412	if (pf != PF_UNSPEC) {
2413		if (ctrl_addr.su_family != pf) {
2414			switch (ctrl_addr.su_family) {
2415			case AF_INET:
2416				pf = 1;
2417				break;
2418			case AF_INET6:
2419				pf = 2;
2420				break;
2421			default:
2422				pf = 0;
2423				break;
2424			}
2425			/*
2426			 * XXX
2427			 * only EPRT/EPSV ready clients will understand this
2428			 */
2429			if (strcmp(cmd, "EPSV") == 0 && pf) {
2430				reply(522, "Network protocol mismatch, "
2431					"use (%d)", pf);
2432			} else
2433				reply(501, "Network protocol mismatch"); /*XXX*/
2434
2435			return;
2436		}
2437	}
2438
2439	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2440	if (pdata < 0) {
2441		perror_reply(425, "Can't open passive connection");
2442		return;
2443	}
2444
2445	(void) seteuid((uid_t)0);
2446
2447	pasv_addr = ctrl_addr;
2448	pasv_addr.su_port = 0;
2449	len = pasv_addr.su_len;
2450
2451#ifdef IP_PORTRANGE
2452	if (ctrl_addr.su_family == AF_INET) {
2453	    int on = restricted_data_ports ? IP_PORTRANGE_HIGH
2454					   : IP_PORTRANGE_DEFAULT;
2455
2456	    if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2457			    (char *)&on, sizeof(on)) < 0)
2458		    goto pasv_error;
2459	}
2460#endif
2461#ifdef IPV6_PORTRANGE
2462	if (ctrl_addr.su_family == AF_INET6) {
2463	    int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH
2464					   : IPV6_PORTRANGE_DEFAULT;
2465
2466	    if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2467			    (char *)&on, sizeof(on)) < 0)
2468		    goto pasv_error;
2469	}
2470#endif
2471
2472	if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0)
2473		goto pasv_error;
2474
2475	(void) seteuid((uid_t)pw->pw_uid);
2476
2477	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2478		goto pasv_error;
2479	if (listen(pdata, 1) < 0)
2480		goto pasv_error;
2481
2482#define UC(b) (((int) b) & 0xff)
2483
2484	if (strcmp(cmd, "LPSV") == 0) {
2485		p = (char *)&pasv_addr.su_port;
2486		switch (pasv_addr.su_family) {
2487		case AF_INET:
2488			a = (char *) &pasv_addr.su_sin.sin_addr;
2489		v4_reply:
2490			reply(228,
2491"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2492			      4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2493			      2, UC(p[0]), UC(p[1]));
2494			return;
2495		case AF_INET6:
2496			if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) {
2497				a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12];
2498				goto v4_reply;
2499			}
2500			a = (char *) &pasv_addr.su_sin6.sin6_addr;
2501			reply(228,
2502"Entering Long Passive Mode "
2503"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2504			      6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2505			      UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
2506			      UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
2507			      UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
2508			      2, UC(p[0]), UC(p[1]));
2509			return;
2510		}
2511	} else if (strcmp(cmd, "EPSV") == 0) {
2512		switch (pasv_addr.su_family) {
2513		case AF_INET:
2514		case AF_INET6:
2515			reply(229, "Entering Extended Passive Mode (|||%d|)",
2516				ntohs(pasv_addr.su_port));
2517			return;
2518		}
2519	} else {
2520		/* more proper error code? */
2521	}
2522
2523pasv_error:
2524	(void) seteuid((uid_t)pw->pw_uid);
2525	(void) close(pdata);
2526	pdata = -1;
2527	perror_reply(425, "Can't open passive connection");
2528	return;
2529}
2530
2531/*
2532 * Generate unique name for file with basename "local".
2533 * The file named "local" is already known to exist.
2534 * Generates failure reply on error.
2535 */
2536static char *
2537gunique(local)
2538	char *local;
2539{
2540	static char new[MAXPATHLEN];
2541	struct stat st;
2542	int count;
2543	char *cp;
2544
2545	cp = strrchr(local, '/');
2546	if (cp)
2547		*cp = '\0';
2548	if (stat(cp ? local : ".", &st) < 0) {
2549		perror_reply(553, cp ? local : ".");
2550		return ((char *) 0);
2551	}
2552	if (cp)
2553		*cp = '/';
2554	/* -4 is for the .nn<null> we put on the end below */
2555	(void) snprintf(new, sizeof(new) - 4, "%s", local);
2556	cp = new + strlen(new);
2557	*cp++ = '.';
2558	for (count = 1; count < 100; count++) {
2559		(void)sprintf(cp, "%d", count);
2560		if (stat(new, &st) < 0)
2561			return (new);
2562	}
2563	reply(452, "Unique file name cannot be created.");
2564	return (NULL);
2565}
2566
2567/*
2568 * Format and send reply containing system error number.
2569 */
2570void
2571perror_reply(code, string)
2572	int code;
2573	char *string;
2574{
2575
2576	reply(code, "%s: %s.", string, strerror(errno));
2577}
2578
2579static char *onefile[] = {
2580	"",
2581	0
2582};
2583
2584void
2585send_file_list(whichf)
2586	char *whichf;
2587{
2588	struct stat st;
2589	DIR *dirp = NULL;
2590	struct dirent *dir;
2591	FILE *dout = NULL;
2592	char **dirlist, *dirname;
2593	int simple = 0;
2594	int freeglob = 0;
2595	glob_t gl;
2596
2597	if (strpbrk(whichf, "~{[*?") != NULL) {
2598		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2599
2600		memset(&gl, 0, sizeof(gl));
2601		freeglob = 1;
2602		if (glob(whichf, flags, 0, &gl)) {
2603			reply(550, "not found");
2604			goto out;
2605		} else if (gl.gl_pathc == 0) {
2606			errno = ENOENT;
2607			perror_reply(550, whichf);
2608			goto out;
2609		}
2610		dirlist = gl.gl_pathv;
2611	} else {
2612		onefile[0] = whichf;
2613		dirlist = onefile;
2614		simple = 1;
2615	}
2616
2617	if (setjmp(urgcatch)) {
2618		transflag = 0;
2619		goto out;
2620	}
2621	while ((dirname = *dirlist++)) {
2622		if (stat(dirname, &st) < 0) {
2623			/*
2624			 * If user typed "ls -l", etc, and the client
2625			 * used NLST, do what the user meant.
2626			 */
2627			if (dirname[0] == '-' && *dirlist == NULL &&
2628			    transflag == 0) {
2629				retrieve(_PATH_LS " %s", dirname);
2630				goto out;
2631			}
2632			perror_reply(550, whichf);
2633			if (dout != NULL) {
2634				(void) fclose(dout);
2635				transflag = 0;
2636				data = -1;
2637				pdata = -1;
2638			}
2639			goto out;
2640		}
2641
2642		if (S_ISREG(st.st_mode)) {
2643			if (dout == NULL) {
2644				dout = dataconn("file list", (off_t)-1, "w");
2645				if (dout == NULL)
2646					goto out;
2647				transflag++;
2648			}
2649			fprintf(dout, "%s%s\n", dirname,
2650				type == TYPE_A ? "\r" : "");
2651			byte_count += strlen(dirname) + 1;
2652			continue;
2653		} else if (!S_ISDIR(st.st_mode))
2654			continue;
2655
2656		if ((dirp = opendir(dirname)) == NULL)
2657			continue;
2658
2659		while ((dir = readdir(dirp)) != NULL) {
2660			char nbuf[MAXPATHLEN];
2661
2662			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2663				continue;
2664			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2665			    dir->d_namlen == 2)
2666				continue;
2667
2668			snprintf(nbuf, sizeof(nbuf),
2669				"%s/%s", dirname, dir->d_name);
2670
2671			/*
2672			 * We have to do a stat to insure it's
2673			 * not a directory or special file.
2674			 */
2675			if (simple || (stat(nbuf, &st) == 0 &&
2676			    S_ISREG(st.st_mode))) {
2677				if (dout == NULL) {
2678					dout = dataconn("file list", (off_t)-1,
2679						"w");
2680					if (dout == NULL)
2681						goto out;
2682					transflag++;
2683				}
2684				if (nbuf[0] == '.' && nbuf[1] == '/')
2685					fprintf(dout, "%s%s\n", &nbuf[2],
2686						type == TYPE_A ? "\r" : "");
2687				else
2688					fprintf(dout, "%s%s\n", nbuf,
2689						type == TYPE_A ? "\r" : "");
2690				byte_count += strlen(nbuf) + 1;
2691			}
2692		}
2693		(void) closedir(dirp);
2694	}
2695
2696	if (dout == NULL)
2697		reply(550, "No files found.");
2698	else if (ferror(dout) != 0)
2699		perror_reply(550, "Data connection");
2700	else
2701		reply(226, "Transfer complete.");
2702
2703	transflag = 0;
2704	if (dout != NULL)
2705		(void) fclose(dout);
2706	data = -1;
2707	pdata = -1;
2708out:
2709	if (freeglob) {
2710		freeglob = 0;
2711		globfree(&gl);
2712	}
2713}
2714
2715void
2716reapchild(signo)
2717	int signo;
2718{
2719	while (wait3(NULL, WNOHANG, NULL) > 0);
2720}
2721
2722#ifdef OLD_SETPROCTITLE
2723/*
2724 * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
2725 * Warning, since this is usually started from inetd.conf, it often doesn't
2726 * have much of an environment or arglist to overwrite.
2727 */
2728void
2729#if __STDC__
2730setproctitle(const char *fmt, ...)
2731#else
2732setproctitle(fmt, va_alist)
2733	char *fmt;
2734        va_dcl
2735#endif
2736{
2737	int i;
2738	va_list ap;
2739	char *p, *bp, ch;
2740	char buf[LINE_MAX];
2741
2742#if __STDC__
2743	va_start(ap, fmt);
2744#else
2745	va_start(ap);
2746#endif
2747	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
2748
2749	/* make ps print our process name */
2750	p = Argv[0];
2751	*p++ = '-';
2752
2753	i = strlen(buf);
2754	if (i > LastArgv - p - 2) {
2755		i = LastArgv - p - 2;
2756		buf[i] = '\0';
2757	}
2758	bp = buf;
2759	while (ch = *bp++)
2760		if (ch != '\n' && ch != '\r')
2761			*p++ = ch;
2762	while (p < LastArgv)
2763		*p++ = ' ';
2764}
2765#endif /* OLD_SETPROCTITLE */
2766
2767static void
2768logxfer(name, size, start)
2769	char *name;
2770	long size;
2771	long start;
2772{
2773	char buf[1024];
2774	char path[MAXPATHLEN + 1];
2775	time_t now;
2776
2777	if (statfd >= 0 && getwd(path) != NULL) {
2778		time(&now);
2779		snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n",
2780			ctime(&now)+4, ident, remotehost,
2781			path, name, size, now - start + (now == start));
2782		write(statfd, buf, strlen(buf));
2783	}
2784}
2785