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