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