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