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