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