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