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