xref: /netbsd-src/libexec/ftpd/ftpd.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: ftpd.c,v 1.182 2007/07/23 10:41:05 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Luke Mewburn.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  */
67 
68 /*
69  * Copyright (C) 1997 and 1998 WIDE Project.
70  * All rights reserved.
71  *
72  * Redistribution and use in source and binary forms, with or without
73  * modification, are permitted provided that the following conditions
74  * are met:
75  * 1. Redistributions of source code must retain the above copyright
76  *    notice, this list of conditions and the following disclaimer.
77  * 2. Redistributions in binary form must reproduce the above copyright
78  *    notice, this list of conditions and the following disclaimer in the
79  *    documentation and/or other materials provided with the distribution.
80  * 3. Neither the name of the project nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  */
96 
97 #include <sys/cdefs.h>
98 #ifndef lint
99 __COPYRIGHT(
100 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
101 	The Regents of the University of California.  All rights reserved.\n");
102 #endif /* not lint */
103 
104 #ifndef lint
105 #if 0
106 static char sccsid[] = "@(#)ftpd.c	8.5 (Berkeley) 4/28/95";
107 #else
108 __RCSID("$NetBSD: ftpd.c,v 1.182 2007/07/23 10:41:05 lukem Exp $");
109 #endif
110 #endif /* not lint */
111 
112 /*
113  * FTP server.
114  */
115 #include <sys/param.h>
116 #include <sys/stat.h>
117 #include <sys/ioctl.h>
118 #include <sys/socket.h>
119 #include <sys/wait.h>
120 #include <sys/mman.h>
121 #include <sys/resource.h>
122 
123 #include <netinet/in.h>
124 #include <netinet/in_systm.h>
125 #include <netinet/ip.h>
126 
127 #define	FTP_NAMES
128 #include <arpa/ftp.h>
129 #include <arpa/inet.h>
130 #include <arpa/telnet.h>
131 
132 #include <ctype.h>
133 #include <dirent.h>
134 #include <err.h>
135 #include <errno.h>
136 #include <fcntl.h>
137 #include <fnmatch.h>
138 #include <glob.h>
139 #include <grp.h>
140 #include <limits.h>
141 #include <netdb.h>
142 #include <pwd.h>
143 #include <poll.h>
144 #include <signal.h>
145 #include <stdarg.h>
146 #include <stdio.h>
147 #include <stdlib.h>
148 #include <string.h>
149 #include <syslog.h>
150 #include <time.h>
151 #include <tzfile.h>
152 #include <unistd.h>
153 #include <util.h>
154 #ifdef SUPPORT_UTMP
155 #include <utmp.h>
156 #endif
157 #ifdef SUPPORT_UTMPX
158 #include <utmpx.h>
159 #endif
160 #ifdef SKEY
161 #include <skey.h>
162 #endif
163 #ifdef KERBEROS5
164 #include <com_err.h>
165 #include <krb5/krb5.h>
166 #endif
167 
168 #ifdef	LOGIN_CAP
169 #include <login_cap.h>
170 #endif
171 
172 #ifdef USE_PAM
173 #include <security/pam_appl.h>
174 #endif
175 
176 #define	GLOBAL
177 #include "extern.h"
178 #include "pathnames.h"
179 #include "version.h"
180 
181 static sig_atomic_t	transflag;
182 static sig_atomic_t	urgflag;
183 
184 int	data;
185 int	Dflag;
186 int	sflag;
187 int	stru;			/* avoid C keyword */
188 int	mode;
189 int	dataport;		/* use specific data port */
190 int	dopidfile;		/* maintain pid file */
191 int	doutmp;			/* update utmp file */
192 int	dowtmp;			/* update wtmp file */
193 int	doxferlog;		/* syslog/write wu-ftpd style xferlog entries */
194 int	xferlogfd;		/* fd to write wu-ftpd xferlog entries to */
195 int	getnameopts;		/* flags for use with getname() */
196 int	dropprivs;		/* if privileges should or have been dropped */
197 int	mapped;			/* IPv4 connection on AF_INET6 socket */
198 off_t	file_size;
199 off_t	byte_count;
200 static char ttyline[20];
201 
202 #ifdef USE_PAM
203 static int	auth_pam(struct passwd **, const char *);
204 pam_handle_t	*pamh = NULL;
205 #endif
206 
207 #ifdef SUPPORT_UTMP
208 static struct utmp utmp;	/* for utmp */
209 #endif
210 #ifdef SUPPORT_UTMPX
211 static struct utmpx utmpx;	/* for utmpx */
212 #endif
213 
214 static const char *anondir = NULL;
215 static const char *confdir = _DEFAULT_CONFDIR;
216 
217 static char	*curname;		/* current USER name */
218 static size_t	curname_len;		/* length of curname (include NUL) */
219 
220 #if defined(KERBEROS) || defined(KERBEROS5)
221 int	has_ccache = 0;
222 int	notickets = 1;
223 char	*krbtkfile_env = NULL;
224 char	*tty = ttyline;
225 int	login_krb5_forwardable_tgt = 0;
226 #endif
227 
228 int epsvall = 0;
229 
230 /*
231  * Timeout intervals for retrying connections
232  * to hosts that don't accept PORT cmds.  This
233  * is a kludge, but given the problems with TCP...
234  */
235 #define	SWAITMAX	90	/* wait at most 90 seconds */
236 #define	SWAITINT	5	/* interval between retries */
237 
238 int	swaitmax = SWAITMAX;
239 int	swaitint = SWAITINT;
240 
241 enum send_status {
242 	SS_SUCCESS,
243 	SS_ABORTED,			/* transfer aborted */
244 	SS_NO_TRANSFER,			/* no transfer made yet */
245 	SS_FILE_ERROR,			/* file read error */
246 	SS_DATA_ERROR			/* data send error */
247 };
248 
249 static int	 bind_pasv_addr(void);
250 static int	 checkuser(const char *, const char *, int, int, char **);
251 static int	 checkaccess(const char *);
252 static int	 checkpassword(const struct passwd *, const char *);
253 static void	 end_login(void);
254 static FILE	*getdatasock(const char *);
255 static char	*gunique(const char *);
256 static void	 login_utmp(const char *, const char *, const char *,
257 		     struct sockinet *);
258 static void	 logremotehost(struct sockinet *);
259 static void	 lostconn(int);
260 static void	 toolong(int);
261 static void	 sigquit(int);
262 static void	 sigurg(int);
263 static int	 handleoobcmd(void);
264 static int	 receive_data(FILE *, FILE *);
265 static int	 send_data(FILE *, FILE *, const struct stat *, int);
266 static struct passwd *sgetpwnam(const char *);
267 static int	 write_data(int, char *, size_t, off_t *, struct timeval *,
268 		     int);
269 static enum send_status
270 		 send_data_with_read(int, int, const struct stat *, int);
271 static enum send_status
272 		 send_data_with_mmap(int, int, const struct stat *, int);
273 static void	 logrusage(const struct rusage *, const struct rusage *);
274 static void	 logout_utmp(void);
275 
276 int	main(int, char *[]);
277 
278 #if defined(KERBEROS)
279 int	klogin(struct passwd *, char *, char *, char *);
280 void	kdestroy(void);
281 #endif
282 #if defined(KERBEROS5)
283 int	k5login(struct passwd *, char *, char *, char *);
284 void	k5destroy(void);
285 #endif
286 
287 int
288 main(int argc, char *argv[])
289 {
290 	int		ch, on = 1, tos, keepalive;
291 	socklen_t	addrlen;
292 #ifdef KERBEROS5
293 	krb5_error_code	kerror;
294 #endif
295 	char		*p;
296 	const char	*xferlogname = NULL;
297 	long		l;
298 	struct sigaction sa;
299 	sa_family_t	af = AF_UNSPEC;
300 
301 	connections = 1;
302 	ftpd_debug = 0;
303 	logging = 0;
304 	pdata = -1;
305 	Dflag = 0;
306 	sflag = 0;
307 	dataport = 0;
308 	dopidfile = 1;		/* default: DO use a pid file to count users */
309 	doutmp = 0;		/* default: Do NOT log to utmp */
310 	dowtmp = 1;		/* default: DO log to wtmp */
311 	doxferlog = 0;		/* default: Do NOT syslog xferlog */
312 	xferlogfd = -1;		/* default: Do NOT write xferlog file */
313 	getnameopts = 0;	/* default: xlate addrs to name */
314 	dropprivs = 0;
315 	mapped = 0;
316 	usedefault = 1;
317 	emailaddr = NULL;
318 	hostname[0] = '\0';
319 	homedir[0] = '\0';
320 	gidcount = 0;
321 	is_oob = 0;
322 	version = FTPD_VERSION;
323 
324 	/*
325 	 * LOG_NDELAY sets up the logging connection immediately,
326 	 * necessary for anonymous ftp's that chroot and can't do it later.
327 	 */
328 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
329 
330 	while ((ch = getopt(argc, argv,
331 	    "46a:c:C:Dde:h:HlL:nP:qQrst:T:uUvV:wWX")) != -1) {
332 		switch (ch) {
333 		case '4':
334 			af = AF_INET;
335 			break;
336 
337 		case '6':
338 			af = AF_INET6;
339 			break;
340 
341 		case 'a':
342 			anondir = optarg;
343 			break;
344 
345 		case 'c':
346 			confdir = optarg;
347 			break;
348 
349 		case 'C':
350 			pw = sgetpwnam(optarg);
351 			exit(checkaccess(optarg) ? 0 : 1);
352 			/* NOTREACHED */
353 
354 		case 'D':
355 			Dflag = 1;
356 			break;
357 
358 		case 'd':
359 		case 'v':		/* deprecated */
360 			ftpd_debug = 1;
361 			break;
362 
363 		case 'e':
364 			emailaddr = optarg;
365 			break;
366 
367 		case 'h':
368 			strlcpy(hostname, optarg, sizeof(hostname));
369 			break;
370 
371 		case 'H':
372 			if (gethostname(hostname, sizeof(hostname)) == -1)
373 				hostname[0] = '\0';
374 			hostname[sizeof(hostname) - 1] = '\0';
375 			break;
376 
377 		case 'l':
378 			logging++;	/* > 1 == extra logging */
379 			break;
380 
381 		case 'L':
382 			xferlogname = optarg;
383 			break;
384 
385 		case 'n':
386 			getnameopts = NI_NUMERICHOST;
387 			break;
388 
389 		case 'P':
390 			errno = 0;
391 			p = NULL;
392 			l = strtol(optarg, &p, 10);
393 			if (errno || *optarg == '\0' || *p != '\0' ||
394 			    l < IPPORT_RESERVED ||
395 			    l > IPPORT_ANONMAX) {
396 				syslog(LOG_WARNING, "Invalid dataport %s",
397 				    optarg);
398 				dataport = 0;
399 			}
400 			dataport = (int)l;
401 			break;
402 
403 		case 'q':
404 			dopidfile = 1;
405 			break;
406 
407 		case 'Q':
408 			dopidfile = 0;
409 			break;
410 
411 		case 'r':
412 			dropprivs = 1;
413 			break;
414 
415 		case 's':
416 			sflag = 1;
417 			break;
418 
419 		case 't':
420 		case 'T':
421 			syslog(LOG_WARNING,
422 			    "-%c has been deprecated in favour of ftpd.conf",
423 			    ch);
424 			break;
425 
426 		case 'u':
427 			doutmp = 1;
428 			break;
429 
430 		case 'U':
431 			doutmp = 0;
432 			break;
433 
434 		case 'V':
435 			if (EMPTYSTR(optarg) || strcmp(optarg, "-") == 0)
436 				version = NULL;
437 			else
438 				version = ftpd_strdup(optarg);
439 			break;
440 
441 		case 'w':
442 			dowtmp = 1;
443 			break;
444 
445 		case 'W':
446 			dowtmp = 0;
447 			break;
448 
449 		case 'X':
450 			doxferlog |= 1;
451 			break;
452 
453 		default:
454 			if (optopt == 'a' || optopt == 'C')
455 				exit(1);
456 			syslog(LOG_WARNING, "unknown flag -%c ignored", optopt);
457 			break;
458 		}
459 	}
460 	if (EMPTYSTR(confdir))
461 		confdir = _DEFAULT_CONFDIR;
462 
463 	if (dowtmp) {
464 #ifdef SUPPORT_UTMPX
465 		ftpd_initwtmpx();
466 #endif
467 #ifdef SUPPORT_UTMP
468 		ftpd_initwtmp();
469 #endif
470 	}
471 	errno = 0;
472 	l = sysconf(_SC_LOGIN_NAME_MAX);
473 	if (l == -1 && errno != 0) {
474 		syslog(LOG_ERR, "sysconf _SC_LOGIN_NAME_MAX: %m");
475 		exit(1);
476 	} else if (l <= 0) {
477 		syslog(LOG_WARNING, "using conservative LOGIN_NAME_MAX value");
478 		curname_len = _POSIX_LOGIN_NAME_MAX;
479 	} else
480 		curname_len = (size_t)l;
481 	curname = malloc(curname_len);
482 	if (curname == NULL) {
483 		syslog(LOG_ERR, "malloc: %m");
484 		exit(1);
485 	}
486 	curname[0] = '\0';
487 
488 	if (Dflag) {
489 		int error, fd, i, n, *socks;
490 		struct pollfd *fds;
491 		struct addrinfo hints, *res, *res0;
492 
493 		if (daemon(1, 0) == -1) {
494 			syslog(LOG_ERR, "failed to daemonize: %m");
495 			exit(1);
496 		}
497 		(void)memset(&sa, 0, sizeof(sa));
498 		sa.sa_handler = SIG_IGN;
499 		sa.sa_flags = SA_NOCLDWAIT;
500 		sigemptyset(&sa.sa_mask);
501 		(void)sigaction(SIGCHLD, &sa, NULL);
502 
503 		(void)memset(&hints, 0, sizeof(hints));
504 		hints.ai_flags = AI_PASSIVE;
505 		hints.ai_family = af;
506 		hints.ai_socktype = SOCK_STREAM;
507 		error = getaddrinfo(NULL, "ftp", &hints, &res0);
508 		if (error) {
509 			syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
510 			exit(1);
511 		}
512 
513 		for (n = 0, res = res0; res != NULL; res = res->ai_next)
514 			n++;
515 		if (n == 0) {
516 			syslog(LOG_ERR, "no addresses available");
517 			exit(1);
518 		}
519 		socks = malloc(n * sizeof(int));
520 		fds = malloc(n * sizeof(struct pollfd));
521 		if (socks == NULL || fds == NULL) {
522 			syslog(LOG_ERR, "malloc: %m");
523 			exit(1);
524 		}
525 
526 		for (n = 0, res = res0; res != NULL; res = res->ai_next) {
527 			socks[n] = socket(res->ai_family, res->ai_socktype,
528 			    res->ai_protocol);
529 			if (socks[n] == -1)
530 				continue;
531 			(void)setsockopt(socks[n], SOL_SOCKET, SO_REUSEADDR,
532 			    &on, sizeof(on));
533 			if (bind(socks[n], res->ai_addr, res->ai_addrlen)
534 			    == -1) {
535 				(void)close(socks[n]);
536 				continue;
537 			}
538 			if (listen(socks[n], 12) == -1) {
539 				(void)close(socks[n]);
540 				continue;
541 			}
542 
543 			fds[n].fd = socks[n];
544 			fds[n].events = POLLIN;
545 			n++;
546 		}
547 		if (n == 0) {
548 			syslog(LOG_ERR, "%m");
549 			exit(1);
550 		}
551 		freeaddrinfo(res0);
552 
553 		if (pidfile(NULL) == -1)
554 			syslog(LOG_ERR, "failed to write a pid file: %m");
555 
556 		for (;;) {
557 			if (poll(fds, n, INFTIM) == -1) {
558 				if (errno == EINTR)
559 					continue;
560 				syslog(LOG_ERR, "poll: %m");
561 				exit(1);
562 			}
563 			for (i = 0; i < n; i++) {
564 				if (fds[i].revents & POLLIN) {
565 					fd = accept(fds[i].fd, NULL, NULL);
566 					if (fd == -1) {
567 						syslog(LOG_ERR, "accept: %m");
568 						continue;
569 					}
570 					switch (fork()) {
571 					case -1:
572 						syslog(LOG_ERR, "fork: %m");
573 						break;
574 					case 0:
575 						goto child;
576 						/* NOTREACHED */
577 					}
578 					(void)close(fd);
579 				}
580 			}
581 		}
582  child:
583 		(void)dup2(fd, STDIN_FILENO);
584 		(void)dup2(fd, STDOUT_FILENO);
585 		(void)dup2(fd, STDERR_FILENO);
586 		for (i = 0; i < n; i++)
587 			(void)close(socks[i]);
588 	}
589 
590 	memset((char *)&his_addr, 0, sizeof(his_addr));
591 	addrlen = sizeof(his_addr.si_su);
592 	if (getpeername(0, (struct sockaddr *)&his_addr.si_su, &addrlen) < 0) {
593 		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
594 		exit(1);
595 	}
596 	his_addr.su_len = addrlen;
597 	memset((char *)&ctrl_addr, 0, sizeof(ctrl_addr));
598 	addrlen = sizeof(ctrl_addr.si_su);
599 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
600 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
601 		exit(1);
602 	}
603 	ctrl_addr.su_len = addrlen;
604 #ifdef INET6
605 	if (his_addr.su_family == AF_INET6
606 	 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_6addr)) {
607 #if 1
608 		/*
609 		 * IPv4 control connection arrived to AF_INET6 socket.
610 		 * I hate to do this, but this is the easiest solution.
611 		 *
612 		 * The assumption is untrue on SIIT environment.
613 		 */
614 		struct sockinet tmp_addr;
615 		const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
616 
617 		tmp_addr = his_addr;
618 		memset(&his_addr, 0, sizeof(his_addr));
619 		his_addr.su_family = AF_INET;
620 		his_addr.su_len = sizeof(his_addr.si_su.su_sin);
621 		memcpy(&his_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
622 		    sizeof(his_addr.su_addr));
623 		his_addr.su_port = tmp_addr.su_port;
624 
625 		tmp_addr = ctrl_addr;
626 		memset(&ctrl_addr, 0, sizeof(ctrl_addr));
627 		ctrl_addr.su_family = AF_INET;
628 		ctrl_addr.su_len = sizeof(ctrl_addr.si_su.su_sin);
629 		memcpy(&ctrl_addr.su_addr, &tmp_addr.su_6addr.s6_addr[off],
630 		    sizeof(ctrl_addr.su_addr));
631 		ctrl_addr.su_port = tmp_addr.su_port;
632 #else
633 		while (fgets(line, sizeof(line), fd) != NULL) {
634 			if ((cp = strchr(line, '\n')) != NULL)
635 				*cp = '\0';
636 			reply(-530, "%s", line);
637 		}
638 		(void) fflush(stdout);
639 		(void) fclose(fd);
640 		reply(530,
641 		    "Connection from IPv4 mapped address is not supported.");
642 		exit(0);
643 #endif
644 
645 		mapped = 1;
646 	} else
647 #endif /* INET6 */
648 		mapped = 0;
649 #ifdef IP_TOS
650 	if (!mapped && his_addr.su_family == AF_INET) {
651 		tos = IPTOS_LOWDELAY;
652 		if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
653 			       sizeof(int)) < 0)
654 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
655 	}
656 #endif
657 	/* if the hostname hasn't been given, attempt to determine it */
658 	if (hostname[0] == '\0') {
659 		if (getnameinfo((struct sockaddr *)&ctrl_addr.si_su,
660 		    ctrl_addr.su_len, hostname, sizeof(hostname), NULL, 0,
661 			getnameopts) != 0)
662 			(void)gethostname(hostname, sizeof(hostname));
663 		hostname[sizeof(hostname) - 1] = '\0';
664 	}
665 
666 	/* set this here so klogin can use it... */
667 	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
668 
669 	(void) freopen(_PATH_DEVNULL, "w", stderr);
670 
671 	memset(&sa, 0, sizeof(sa));
672 	sa.sa_handler = SIG_DFL;
673 	sa.sa_flags = SA_RESTART;
674 	sigemptyset(&sa.sa_mask);
675 	(void) sigaction(SIGCHLD, &sa, NULL);
676 
677 	sa.sa_handler = sigquit;
678 	sa.sa_flags = SA_RESTART;
679 	sigfillset(&sa.sa_mask);	/* block all sigs in these handlers */
680 	(void) sigaction(SIGHUP, &sa, NULL);
681 	(void) sigaction(SIGINT, &sa, NULL);
682 	(void) sigaction(SIGQUIT, &sa, NULL);
683 	(void) sigaction(SIGTERM, &sa, NULL);
684 	sa.sa_handler = lostconn;
685 	(void) sigaction(SIGPIPE, &sa, NULL);
686 	sa.sa_handler = toolong;
687 	(void) sigaction(SIGALRM, &sa, NULL);
688 	sa.sa_handler = sigurg;
689 	(void) sigaction(SIGURG, &sa, NULL);
690 
691 	/* Try to handle urgent data inline */
692 #ifdef SO_OOBINLINE
693 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
694 		syslog(LOG_WARNING, "setsockopt: %m");
695 #endif
696 	/* Set keepalives on the socket to detect dropped connections.  */
697 #ifdef SO_KEEPALIVE
698 	keepalive = 1;
699 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
700 	    sizeof(int)) < 0)
701 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
702 #endif
703 
704 #ifdef	F_SETOWN
705 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
706 		syslog(LOG_WARNING, "fcntl F_SETOWN: %m");
707 #endif
708 	logremotehost(&his_addr);
709 	/*
710 	 * Set up default state
711 	 */
712 	data = -1;
713 	type = TYPE_A;
714 	form = FORM_N;
715 	stru = STRU_F;
716 	mode = MODE_S;
717 	tmpline[0] = '\0';
718 	hasyyerrored = 0;
719 
720 #ifdef KERBEROS5
721 	kerror = krb5_init_context(&kcontext);
722 	if (kerror) {
723 		syslog(LOG_ERR, "%s when initializing Kerberos context",
724 		    error_message(kerror));
725 		exit(0);
726 	}
727 #endif /* KERBEROS5 */
728 
729 	init_curclass();
730 	curclass.timeout = 300;		/* 5 minutes, as per login(1) */
731 	curclass.type = CLASS_REAL;
732 
733 	/* If logins are disabled, print out the message. */
734 	if (display_file(_PATH_NOLOGIN, 530)) {
735 		reply(530, "System not available.");
736 		exit(0);
737 	}
738 	(void)display_file(conffilename(_NAME_FTPWELCOME), 220);
739 		/* reply(220,) must follow */
740 	if (EMPTYSTR(version))
741 		reply(220, "%s FTP server ready.", hostname);
742 	else
743 		reply(220, "%s FTP server (%s) ready.", hostname, version);
744 
745 	if (xferlogname != NULL) {
746 		xferlogfd = open(xferlogname, O_WRONLY | O_APPEND | O_CREAT,
747 		    0660);
748 		if (xferlogfd == -1)
749 			syslog(LOG_WARNING, "open xferlog `%s': %m",
750 			    xferlogname);
751 		else
752 			doxferlog |= 2;
753 	}
754 
755 	ftp_loop();
756 	/* NOTREACHED */
757 }
758 
759 static void
760 lostconn(int signo __unused)
761 {
762 
763 	if (ftpd_debug)
764 		syslog(LOG_DEBUG, "lost connection");
765 	dologout(1);
766 }
767 
768 static void
769 toolong(int signo __unused)
770 {
771 
772 		/* XXXSIGRACE */
773 	reply(421,
774 	    "Timeout (" LLF " seconds): closing control connection.",
775 	    (LLT)curclass.timeout);
776 	if (logging)
777 		syslog(LOG_INFO, "User %s timed out after " LLF " seconds",
778 		    (pw ? pw->pw_name : "unknown"), (LLT)curclass.timeout);
779 	dologout(1);
780 }
781 
782 static void
783 sigquit(int signo)
784 {
785 
786 	if (ftpd_debug)
787 		syslog(LOG_DEBUG, "got signal %d", signo);
788 	dologout(1);
789 }
790 
791 static void
792 sigurg(int signo __unused)
793 {
794 
795 	urgflag = 1;
796 }
797 
798 
799 /*
800  * Save the result of a getpwnam.  Used for USER command, since
801  * the data returned must not be clobbered by any other command
802  * (e.g., globbing).
803  */
804 static struct passwd *
805 sgetpwnam(const char *name)
806 {
807 	static struct passwd save;
808 	struct passwd *p;
809 
810 	if ((p = getpwnam(name)) == NULL)
811 		return (p);
812 	if (save.pw_name) {
813 		free((char *)save.pw_name);
814 		memset(save.pw_passwd, 0, strlen(save.pw_passwd));
815 		free((char *)save.pw_passwd);
816 		free((char *)save.pw_gecos);
817 		free((char *)save.pw_dir);
818 		free((char *)save.pw_shell);
819 	}
820 	save = *p;
821 	save.pw_name = ftpd_strdup(p->pw_name);
822 	save.pw_passwd = ftpd_strdup(p->pw_passwd);
823 	save.pw_gecos = ftpd_strdup(p->pw_gecos);
824 	save.pw_dir = ftpd_strdup(p->pw_dir);
825 	save.pw_shell = ftpd_strdup(p->pw_shell);
826 	return (&save);
827 }
828 
829 static int	login_attempts;	/* number of failed login attempts */
830 static int	askpasswd;	/* had USER command, ask for PASSwd */
831 static int	permitted;	/* USER permitted */
832 
833 /*
834  * USER command.
835  * Sets global passwd pointer pw if named account exists and is acceptable;
836  * sets askpasswd if a PASS command is expected.  If logged in previously,
837  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
838  * _NAME_FTPUSERS, and ftp account exists, set guest and pw, then just return.
839  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
840  * requesting login privileges.  Disallow anyone who does not have a standard
841  * shell as returned by getusershell().  Disallow anyone mentioned in the file
842  * _NAME_FTPUSERS to allow people such as root and uucp to be avoided.
843  */
844 void
845 user(const char *name)
846 {
847 	char	*class;
848 #ifdef	LOGIN_CAP
849 	login_cap_t *lc = NULL;
850 #endif
851 
852 	class = NULL;
853 	if (logged_in) {
854 		switch (curclass.type) {
855 		case CLASS_GUEST:
856 			reply(530, "Can't change user from guest login.");
857 			return;
858 		case CLASS_CHROOT:
859 			reply(530, "Can't change user from chroot user.");
860 			return;
861 		case CLASS_REAL:
862 			if (dropprivs) {
863 				reply(530, "Can't change user.");
864 				return;
865 			}
866 			end_login();
867 			break;
868 		default:
869 			abort();
870 		}
871 	}
872 
873 #if defined(KERBEROS)
874 	kdestroy();
875 #endif
876 #if defined(KERBEROS5)
877 	k5destroy();
878 #endif
879 
880 	curclass.type = CLASS_REAL;
881 	askpasswd = 0;
882 	permitted = 0;
883 
884 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
885 			/* need `pw' setup for checkaccess() and checkuser () */
886 		if ((pw = sgetpwnam("ftp")) == NULL)
887 			reply(530, "User %s unknown.", name);
888 		else if (! checkaccess("ftp") || ! checkaccess("anonymous"))
889 			reply(530, "User %s access denied.", name);
890 		else {
891 			curclass.type = CLASS_GUEST;
892 			askpasswd = 1;
893 			reply(331,
894 			    "Guest login ok, type your name as password.");
895 		}
896 		if (!askpasswd) {
897 			if (logging)
898 				syslog(LOG_NOTICE,
899 				    "ANONYMOUS FTP LOGIN REFUSED FROM %s",
900 				    remotehost);
901 			end_login();
902 			goto cleanup_user;
903 		}
904 		name = "ftp";
905 	} else
906 		pw = sgetpwnam(name);
907 
908 	strlcpy(curname, name, curname_len);
909 
910 			/* check user in /etc/ftpusers, and setup class */
911 	permitted = checkuser(_NAME_FTPUSERS, curname, 1, 0, &class);
912 
913 			/* check user in /etc/ftpchroot */
914 #ifdef	LOGIN_CAP
915 	lc = login_getpwclass(pw);
916 #endif
917 	if (checkuser(_NAME_FTPCHROOT, curname, 0, 0, NULL)
918 #ifdef	LOGIN_CAP	/* Allow login.conf configuration as well */
919 	    || login_getcapbool(lc, "ftp-chroot", 0)
920 #endif
921 	) {
922 		if (curclass.type == CLASS_GUEST) {
923 			syslog(LOG_NOTICE,
924 	    "Can't change guest user to chroot class; remove entry in %s",
925 			    _NAME_FTPCHROOT);
926 			exit(1);
927 		}
928 		curclass.type = CLASS_CHROOT;
929 	}
930 			/* determine default class */
931 	if (class == NULL) {
932 		switch (curclass.type) {
933 		case CLASS_GUEST:
934 			class = ftpd_strdup("guest");
935 			break;
936 		case CLASS_CHROOT:
937 			class = ftpd_strdup("chroot");
938 			break;
939 		case CLASS_REAL:
940 			class = ftpd_strdup("real");
941 			break;
942 		default:
943 			syslog(LOG_ERR, "unknown curclass.type %d; aborting",
944 			    curclass.type);
945 			abort();
946 		}
947 	}
948 			/* parse ftpd.conf, setting up various parameters */
949 	parse_conf(class);
950 			/* if not guest user, check for valid shell */
951 	if (pw == NULL)
952 		permitted = 0;
953 	else {
954 		const char	*cp, *shell;
955 
956 		if ((shell = pw->pw_shell) == NULL || *shell == 0)
957 			shell = _PATH_BSHELL;
958 		while ((cp = getusershell()) != NULL)
959 			if (strcmp(cp, shell) == 0)
960 				break;
961 		endusershell();
962 		if (cp == NULL && curclass.type != CLASS_GUEST)
963 			permitted = 0;
964 	}
965 
966 			/* deny quickly (after USER not PASS) if requested */
967 	if (CURCLASS_FLAGS_ISSET(denyquick) && !permitted) {
968 		reply(530, "User %s may not use FTP.", curname);
969 		if (logging)
970 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
971 			    remotehost, curname);
972 		end_login();
973 		goto cleanup_user;
974 	}
975 
976 			/* if haven't asked yet (i.e, not anon), ask now */
977 	if (!askpasswd) {
978 		askpasswd = 1;
979 #ifdef SKEY
980 		if (skey_haskey(curname) == 0) {
981 			const char *myskey;
982 
983 			myskey = skey_keyinfo(curname);
984 			reply(331, "Password [ %s ] required for %s.",
985 			    myskey ? myskey : "error getting challenge",
986 			    curname);
987 		} else
988 #endif
989 			reply(331, "Password required for %s.", curname);
990 	}
991 
992  cleanup_user:
993 #ifdef LOGIN_CAP
994 	login_close(lc);
995 #endif
996 	/*
997 	 * Delay before reading passwd after first failed
998 	 * attempt to slow down passwd-guessing programs.
999 	 */
1000 	if (login_attempts)
1001 		sleep((unsigned) login_attempts);
1002 
1003 	if (class)
1004 		free(class);
1005 }
1006 
1007 /*
1008  * Determine whether something is to happen (allow access, chroot)
1009  * for a user. Each line is a shell-style glob followed by
1010  * `yes' or `no'.
1011  *
1012  * For backward compatibility, `allow' and `deny' are synonymns
1013  * for `yes' and `no', respectively.
1014  *
1015  * Each glob is matched against the username in turn, and the first
1016  * match found is used. If no match is found, the result is the
1017  * argument `def'. If a match is found but without and explicit
1018  * `yes'/`no', the result is the opposite of def.
1019  *
1020  * If the file doesn't exist at all, the result is the argument
1021  * `nofile'
1022  *
1023  * Any line starting with `#' is considered a comment and ignored.
1024  *
1025  * Returns 0 if the user is denied, or 1 if they are allowed.
1026  *
1027  * NOTE: needs struct passwd *pw setup before use.
1028  */
1029 static int
1030 checkuser(const char *fname, const char *name, int def, int nofile,
1031 	    char **retclass)
1032 {
1033 	FILE	*fd;
1034 	int	 retval;
1035 	char	*word, *perm, *class, *buf, *p;
1036 	size_t	 len, line;
1037 
1038 	retval = def;
1039 	if (retclass != NULL)
1040 		*retclass = NULL;
1041 	if ((fd = fopen(conffilename(fname), "r")) == NULL)
1042 		return nofile;
1043 
1044 	line = 0;
1045 	for (;
1046 	    (buf = fparseln(fd, &len, &line, NULL, FPARSELN_UNESCCOMM |
1047 			    FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
1048 	    free(buf), buf = NULL) {
1049 		word = perm = class = NULL;
1050 		p = buf;
1051 		if (len < 1)
1052 			continue;
1053 		if (p[len - 1] == '\n')
1054 			p[--len] = '\0';
1055 		if (EMPTYSTR(p))
1056 			continue;
1057 
1058 		NEXTWORD(p, word);
1059 		NEXTWORD(p, perm);
1060 		NEXTWORD(p, class);
1061 		if (EMPTYSTR(word))
1062 			continue;
1063 		if (!EMPTYSTR(class)) {
1064 			if (strcasecmp(class, "all") == 0 ||
1065 			    strcasecmp(class, "none") == 0) {
1066 				syslog(LOG_WARNING,
1067 		"%s line %d: illegal user-defined class `%s' - skipping entry",
1068 					    fname, (int)line, class);
1069 				continue;
1070 			}
1071 		}
1072 
1073 					/* have a host specifier */
1074 		if ((p = strchr(word, '@')) != NULL) {
1075 			unsigned long	net, mask, addr;
1076 			int		bits;
1077 
1078 			*p++ = '\0';
1079 					/* check against network or CIDR */
1080 			if (isdigit((unsigned char)*p) &&
1081 			    (bits = inet_net_pton(AF_INET, p,
1082 			    &net, sizeof(net))) != -1) {
1083 				net = ntohl(net);
1084 				mask = 0xffffffffU << (32 - bits);
1085 				addr = ntohl(his_addr.su_addr.s_addr);
1086 				if ((addr & mask) != net)
1087 					continue;
1088 
1089 					/* check against hostname glob */
1090 			} else if (fnmatch(p, remotehost, FNM_CASEFOLD) != 0)
1091 				continue;
1092 		}
1093 
1094 					/* have a group specifier */
1095 		if ((p = strchr(word, ':')) != NULL) {
1096 			gid_t	*groups, *ng;
1097 			int	 gsize, i, found;
1098 
1099 			if (pw == NULL)
1100 				continue;	/* no match for unknown user */
1101 			*p++ = '\0';
1102 			groups = NULL;
1103 			gsize = 16;
1104 			do {
1105 				ng = realloc(groups, gsize * sizeof(gid_t));
1106 				if (ng == NULL)
1107 					fatal(
1108 					    "Local resource failure: realloc");
1109 				groups = ng;
1110 			} while (getgrouplist(pw->pw_name, pw->pw_gid,
1111 						groups, &gsize) == -1);
1112 			found = 0;
1113 			for (i = 0; i < gsize; i++) {
1114 				struct group *g;
1115 
1116 				if ((g = getgrgid(groups[i])) == NULL)
1117 					continue;
1118 				if (fnmatch(p, g->gr_name, 0) == 0) {
1119 					found = 1;
1120 					break;
1121 				}
1122 			}
1123 			free(groups);
1124 			if (!found)
1125 				continue;
1126 		}
1127 
1128 					/* check against username glob */
1129 		if (fnmatch(word, name, 0) != 0)
1130 			continue;
1131 
1132 		if (perm != NULL &&
1133 		    ((strcasecmp(perm, "allow") == 0) ||
1134 		     (strcasecmp(perm, "yes") == 0)))
1135 			retval = 1;
1136 		else if (perm != NULL &&
1137 		    ((strcasecmp(perm, "deny") == 0) ||
1138 		     (strcasecmp(perm, "no") == 0)))
1139 			retval = 0;
1140 		else
1141 			retval = !def;
1142 		if (!EMPTYSTR(class) && retclass != NULL)
1143 			*retclass = ftpd_strdup(class);
1144 		free(buf);
1145 		break;
1146 	}
1147 	(void) fclose(fd);
1148 	return (retval);
1149 }
1150 
1151 /*
1152  * Check if user is allowed by /etc/ftpusers
1153  * returns 1 for yes, 0 for no
1154  *
1155  * NOTE: needs struct passwd *pw setup (for checkuser())
1156  */
1157 static int
1158 checkaccess(const char *name)
1159 {
1160 
1161 	return (checkuser(_NAME_FTPUSERS, name, 1, 0, NULL));
1162 }
1163 
1164 static void
1165 login_utmp(const char *line, const char *name, const char *host,
1166     struct sockinet *haddr)
1167 {
1168 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
1169 	struct timeval tv;
1170 	(void)gettimeofday(&tv, NULL);
1171 #endif
1172 #ifdef SUPPORT_UTMPX
1173 	if (doutmp) {
1174 		(void)memset(&utmpx, 0, sizeof(utmpx));
1175 		utmpx.ut_tv = tv;
1176 		utmpx.ut_pid = getpid();
1177 		utmpx.ut_id[0] = 'f';
1178 		utmpx.ut_id[1] = 't';
1179 		utmpx.ut_id[2] = 'p';
1180 		utmpx.ut_id[3] = '*';
1181 		utmpx.ut_type = USER_PROCESS;
1182 		(void)strncpy(utmpx.ut_name, name, sizeof(utmpx.ut_name));
1183 		(void)strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
1184 		(void)strncpy(utmpx.ut_host, host, sizeof(utmpx.ut_host));
1185 		(void)memcpy(&utmpx.ut_ss, &haddr->si_su, haddr->su_len);
1186 		ftpd_loginx(&utmpx);
1187 	}
1188 	if (dowtmp)
1189 		ftpd_logwtmpx(line, name, host, haddr, 0, USER_PROCESS);
1190 #endif
1191 #ifdef SUPPORT_UTMP
1192 	if (doutmp) {
1193 		(void)memset(&utmp, 0, sizeof(utmp));
1194 		(void)time(&utmp.ut_time);
1195 		(void)strncpy(utmp.ut_name, name, sizeof(utmp.ut_name));
1196 		(void)strncpy(utmp.ut_line, line, sizeof(utmp.ut_line));
1197 		(void)strncpy(utmp.ut_host, host, sizeof(utmp.ut_host));
1198 		ftpd_login(&utmp);
1199 	}
1200 	if (dowtmp)
1201 		ftpd_logwtmp(line, name, host);
1202 #endif
1203 }
1204 
1205 static void
1206 logout_utmp(void)
1207 {
1208 #ifdef SUPPORT_UTMPX
1209 	int okwtmpx = dowtmp;
1210 #endif
1211 #ifdef SUPPORT_UTMP
1212 	int okwtmp = dowtmp;
1213 #endif
1214 	if (logged_in) {
1215 #ifdef SUPPORT_UTMPX
1216 		if (doutmp)
1217 			okwtmpx &= ftpd_logoutx(ttyline, 0, DEAD_PROCESS);
1218 		if (okwtmpx)
1219 			ftpd_logwtmpx(ttyline, "", "", NULL, 0, DEAD_PROCESS);
1220 #endif
1221 #ifdef SUPPORT_UTMP
1222 		if (doutmp)
1223 			okwtmp &= ftpd_logout(ttyline);
1224 		if (okwtmp)
1225 			ftpd_logwtmp(ttyline, "", "");
1226 #endif
1227 	}
1228 }
1229 
1230 /*
1231  * Terminate login as previous user (if any), resetting state;
1232  * used when USER command is given or login fails.
1233  */
1234 static void
1235 end_login(void)
1236 {
1237 #ifdef USE_PAM
1238 	int e;
1239 #endif
1240 	logout_utmp();
1241 	show_chdir_messages(-1);		/* flush chdir cache */
1242 	if (pw != NULL && pw->pw_passwd != NULL)
1243 		memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
1244 	pw = NULL;
1245 	logged_in = 0;
1246 	askpasswd = 0;
1247 	permitted = 0;
1248 	quietmessages = 0;
1249 	gidcount = 0;
1250 	curclass.type = CLASS_REAL;
1251 	(void) seteuid((uid_t)0);
1252 #ifdef	LOGIN_CAP
1253 	setusercontext(NULL, getpwuid(0), 0,
1254 		       LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1255 #endif
1256 #ifdef USE_PAM
1257 	if (pamh) {
1258 		if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS)
1259 			syslog(LOG_ERR, "pam_setcred: %s",
1260 			    pam_strerror(pamh, e));
1261 		if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS)
1262 			syslog(LOG_ERR, "pam_close_session: %s",
1263 			    pam_strerror(pamh, e));
1264 		if ((e = pam_end(pamh, e)) != PAM_SUCCESS)
1265 			syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
1266 		pamh = NULL;
1267 	}
1268 #endif
1269 }
1270 
1271 void
1272 pass(const char *passwd)
1273 {
1274 	int		 rval;
1275 	char		 root[MAXPATHLEN];
1276 #ifdef	LOGIN_CAP
1277 	login_cap_t *lc = NULL;
1278 #endif
1279 #ifdef USE_PAM
1280 	int e;
1281 #endif
1282 	if (logged_in || askpasswd == 0) {
1283 		reply(503, "Login with USER first.");
1284 		return;
1285 	}
1286 	askpasswd = 0;
1287 	if (curclass.type != CLASS_GUEST) {
1288 			/* "ftp" is the only account allowed with no password */
1289 		if (pw == NULL) {
1290 			rval = 1;	/* failure below */
1291 			goto skip;
1292 		}
1293 #ifdef USE_PAM
1294 		rval = auth_pam(&pw, passwd);
1295 #ifdef notdef
1296 		/* If PAM fails, we proceed with other authentications */
1297 		if (rval >= 0) {
1298 			goto skip;
1299 		}
1300 #else
1301 		/* If PAM fails, that's it */
1302 		goto skip;
1303 #endif
1304 #endif
1305 #if defined(KERBEROS)
1306 		if (klogin(pw, "", hostname, (char *)passwd) == 0) {
1307 			rval = 0;
1308 			goto skip;
1309 		}
1310 #endif
1311 #if defined(KERBEROS5)
1312 		if (k5login(pw, "", hostname, (char *)passwd) == 0) {
1313 			rval = 0;
1314 			goto skip;
1315 		}
1316 #endif
1317 #ifdef SKEY
1318 		if (skey_haskey(pw->pw_name) == 0) {
1319 			char *p;
1320 			int r;
1321 
1322 			p = ftpd_strdup(passwd);
1323 			r = skey_passcheck(pw->pw_name, p);
1324 			free(p);
1325 			if (r != -1) {
1326 				rval = 0;
1327 				goto skip;
1328 			}
1329 		}
1330 #endif
1331 		if (!sflag)
1332 			rval = checkpassword(pw, passwd);
1333 		else
1334 			rval = 1;
1335 
1336  skip:
1337 
1338 			/*
1339 			 * If rval > 0, the user failed the authentication check
1340 			 * above.  If rval == 0, either Kerberos or local
1341 			 * authentication succeeded.
1342 			 */
1343 		if (rval) {
1344 			reply(530, "%s", rval == 2 ? "Password expired." :
1345 			    "Login incorrect.");
1346 			if (logging) {
1347 				syslog(LOG_NOTICE,
1348 				    "FTP LOGIN FAILED FROM %s", remotehost);
1349 				syslog(LOG_AUTHPRIV | LOG_NOTICE,
1350 				    "FTP LOGIN FAILED FROM %s, %s",
1351 				    remotehost, curname);
1352 			}
1353 			pw = NULL;
1354 			if (login_attempts++ >= 5) {
1355 				syslog(LOG_NOTICE,
1356 				    "repeated login failures from %s",
1357 				    remotehost);
1358 				exit(0);
1359 			}
1360 			return;
1361 		}
1362 	}
1363 
1364 			/* password ok; check if anything else prevents login */
1365 	if (! permitted) {
1366 		reply(530, "User %s may not use FTP.", pw->pw_name);
1367 		if (logging)
1368 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
1369 			    remotehost, pw->pw_name);
1370 		goto bad;
1371 	}
1372 
1373 	login_attempts = 0;		/* this time successful */
1374 	if (setegid((gid_t)pw->pw_gid) < 0) {
1375 		reply(550, "Can't set gid.");
1376 		goto bad;
1377 	}
1378 #ifdef	LOGIN_CAP
1379 	if ((lc = login_getpwclass(pw)) != NULL) {
1380 #ifdef notyet
1381 		char	remote_ip[NI_MAXHOST];
1382 
1383 		if (getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1384 			remote_ip, sizeof(remote_ip) - 1, NULL, 0,
1385 			NI_NUMERICHOST))
1386 				*remote_ip = 0;
1387 		remote_ip[sizeof(remote_ip) - 1] = 0;
1388 		if (!auth_hostok(lc, remotehost, remote_ip)) {
1389 			syslog(LOG_INFO|LOG_AUTH,
1390 			    "FTP LOGIN FAILED (HOST) as %s: permission denied.",
1391 			    pw->pw_name);
1392 			reply(530, "Permission denied.");
1393 			pw = NULL;
1394 			return;
1395 		}
1396 		if (!auth_timeok(lc, time(NULL))) {
1397 			reply(530, "Login not available right now.");
1398 			pw = NULL;
1399 			return;
1400 		}
1401 #endif
1402 	}
1403 	setsid();
1404 	setusercontext(lc, pw, 0,
1405 		LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY|
1406 		LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1407 #else
1408 	(void) initgroups(pw->pw_name, pw->pw_gid);
1409 			/* cache groups for cmds.c::matchgroup() */
1410 #endif
1411 #ifdef USE_PAM
1412 	if (pamh) {
1413 		if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
1414 			syslog(LOG_ERR, "pam_open_session: %s",
1415 			    pam_strerror(pamh, e));
1416 		} else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
1417 		    != PAM_SUCCESS) {
1418 			syslog(LOG_ERR, "pam_setcred: %s",
1419 			    pam_strerror(pamh, e));
1420 		}
1421 	}
1422 #endif
1423 	gidcount = getgroups(0, NULL);
1424 	if (gidlist)
1425 		free(gidlist);
1426 	gidlist = malloc(gidcount * sizeof *gidlist);
1427 	gidcount = getgroups(gidcount, gidlist);
1428 
1429 	/* open utmp/wtmp before chroot */
1430 	login_utmp(ttyline, pw->pw_name, remotehost, &his_addr);
1431 
1432 	logged_in = 1;
1433 
1434 	connections = 1;
1435 	if (dopidfile)
1436 		count_users();
1437 	if (curclass.limit != -1 && connections > curclass.limit) {
1438 		if (! EMPTYSTR(curclass.limitfile))
1439 			(void)display_file(conffilename(curclass.limitfile),
1440 			    530);
1441 		reply(530,
1442 		    "User %s access denied, connection limit of " LLF
1443 		    " reached.",
1444 		    pw->pw_name, (LLT)curclass.limit);
1445 		syslog(LOG_NOTICE,
1446 		    "Maximum connection limit of " LLF
1447 		    " for class %s reached, login refused for %s",
1448 		    (LLT)curclass.limit, curclass.classname, pw->pw_name);
1449 		goto bad;
1450 	}
1451 
1452 	homedir[0] = '/';
1453 	switch (curclass.type) {
1454 	case CLASS_GUEST:
1455 			/*
1456 			 * We MUST do a chdir() after the chroot. Otherwise
1457 			 * the old current directory will be accessible as "."
1458 			 * outside the new root!
1459 			 */
1460 		format_path(root,
1461 		    curclass.chroot ? curclass.chroot :
1462 		    anondir ? anondir :
1463 		    pw->pw_dir);
1464 		format_path(homedir,
1465 		    curclass.homedir ? curclass.homedir :
1466 		    "/");
1467 		if (EMPTYSTR(homedir))
1468 			homedir[0] = '/';
1469 		if (EMPTYSTR(root) || chroot(root) < 0) {
1470 			syslog(LOG_NOTICE,
1471 			    "GUEST user %s: can't chroot to %s: %m",
1472 			    pw->pw_name, root);
1473 			goto bad_guest;
1474 		}
1475 		if (chdir(homedir) < 0) {
1476 			syslog(LOG_NOTICE,
1477 			    "GUEST user %s: can't chdir to %s: %m",
1478 			    pw->pw_name, homedir);
1479  bad_guest:
1480 			reply(550, "Can't set guest privileges.");
1481 			goto bad;
1482 		}
1483 		break;
1484 	case CLASS_CHROOT:
1485 		format_path(root,
1486 		    curclass.chroot ? curclass.chroot :
1487 		    pw->pw_dir);
1488 		format_path(homedir,
1489 		    curclass.homedir ? curclass.homedir :
1490 		    "/");
1491 		if (EMPTYSTR(homedir))
1492 			homedir[0] = '/';
1493 		if (EMPTYSTR(root) || chroot(root) < 0) {
1494 			syslog(LOG_NOTICE,
1495 			    "CHROOT user %s: can't chroot to %s: %m",
1496 			    pw->pw_name, root);
1497 			goto bad_chroot;
1498 		}
1499 		if (chdir(homedir) < 0) {
1500 			syslog(LOG_NOTICE,
1501 			    "CHROOT user %s: can't chdir to %s: %m",
1502 			    pw->pw_name, homedir);
1503  bad_chroot:
1504 			reply(550, "Can't change root.");
1505 			goto bad;
1506 		}
1507 		break;
1508 	case CLASS_REAL:
1509 			/* only chroot REAL if explicitly requested */
1510 		if (! EMPTYSTR(curclass.chroot)) {
1511 			format_path(root, curclass.chroot);
1512 			if (EMPTYSTR(root) || chroot(root) < 0) {
1513 				syslog(LOG_NOTICE,
1514 				    "REAL user %s: can't chroot to %s: %m",
1515 				    pw->pw_name, root);
1516 				goto bad_chroot;
1517 			}
1518 		}
1519 		format_path(homedir,
1520 		    curclass.homedir ? curclass.homedir :
1521 		    pw->pw_dir);
1522 		if (EMPTYSTR(homedir) || chdir(homedir) < 0) {
1523 			if (chdir("/") < 0) {
1524 				syslog(LOG_NOTICE,
1525 				    "REAL user %s: can't chdir to %s: %m",
1526 				    pw->pw_name,
1527 				    !EMPTYSTR(homedir) ?  homedir : "/");
1528 				reply(530,
1529 				    "User %s: can't change directory to %s.",
1530 				    pw->pw_name,
1531 				    !EMPTYSTR(homedir) ? homedir : "/");
1532 				goto bad;
1533 			} else {
1534 				reply(-230,
1535 				    "No directory! Logging in with home=/");
1536 				homedir[0] = '/';
1537 			}
1538 		}
1539 		break;
1540 	}
1541 #ifndef LOGIN_CAP
1542 	setsid();
1543 	setlogin(pw->pw_name);
1544 #endif
1545 	if (dropprivs ||
1546 	    (curclass.type != CLASS_REAL &&
1547 	    ntohs(ctrl_addr.su_port) > IPPORT_RESERVED + 1)) {
1548 		dropprivs++;
1549 		if (setgid((gid_t)pw->pw_gid) < 0) {
1550 			reply(550, "Can't set gid.");
1551 			goto bad;
1552 		}
1553 		if (setuid((uid_t)pw->pw_uid) < 0) {
1554 			reply(550, "Can't set uid.");
1555 			goto bad;
1556 		}
1557 	} else {
1558 		if (seteuid((uid_t)pw->pw_uid) < 0) {
1559 			reply(550, "Can't set uid.");
1560 			goto bad;
1561 		}
1562 	}
1563 	setenv("HOME", homedir, 1);
1564 
1565 	if (curclass.type == CLASS_GUEST && passwd[0] == '-')
1566 		quietmessages = 1;
1567 
1568 			/*
1569 			 * Display a login message, if it exists.
1570 			 * N.B. reply(230,) must follow the message.
1571 			 */
1572 	if (! EMPTYSTR(curclass.motd))
1573 		(void)display_file(conffilename(curclass.motd), 230);
1574 	show_chdir_messages(230);
1575 	if (curclass.type == CLASS_GUEST) {
1576 		char *p;
1577 
1578 		reply(230, "Guest login ok, access restrictions apply.");
1579 #if defined(HAVE_SETPROCTITLE)
1580 		snprintf(proctitle, sizeof(proctitle),
1581 		    "%s: anonymous/%s", remotehost, passwd);
1582 		setproctitle("%s", proctitle);
1583 #endif /* defined(HAVE_SETPROCTITLE) */
1584 		if (logging)
1585 			syslog(LOG_INFO,
1586 			"ANONYMOUS FTP LOGIN FROM %s, %s (class: %s, type: %s)",
1587 			    remotehost, passwd,
1588 			    curclass.classname, CURCLASSTYPE);
1589 			/* store guest password reply into pw_passwd */
1590 		REASSIGN(pw->pw_passwd, ftpd_strdup(passwd));
1591 		for (p = pw->pw_passwd; *p; p++)
1592 			if (!isgraph((unsigned char)*p))
1593 				*p = '_';
1594 	} else {
1595 		reply(230, "User %s logged in.", pw->pw_name);
1596 #if defined(HAVE_SETPROCTITLE)
1597 		snprintf(proctitle, sizeof(proctitle),
1598 		    "%s: %s", remotehost, pw->pw_name);
1599 		setproctitle("%s", proctitle);
1600 #endif /* defined(HAVE_SETPROCTITLE) */
1601 		if (logging)
1602 			syslog(LOG_INFO,
1603 			    "FTP LOGIN FROM %s as %s (class: %s, type: %s)",
1604 			    remotehost, pw->pw_name,
1605 			    curclass.classname, CURCLASSTYPE);
1606 	}
1607 	(void) umask(curclass.umask);
1608 #ifdef	LOGIN_CAP
1609 	login_close(lc);
1610 #endif
1611 	return;
1612 
1613  bad:
1614 #ifdef	LOGIN_CAP
1615 	login_close(lc);
1616 #endif
1617 			/* Forget all about it... */
1618 	end_login();
1619 }
1620 
1621 void
1622 retrieve(char *argv[], const char *name)
1623 {
1624 	FILE *fin, *dout;
1625 	struct stat st;
1626 	int (*closefunc)(FILE *) = NULL;
1627 	int dolog, sendrv, closerv, stderrfd, isconversion, isdata, isls;
1628 	struct timeval start, finish, td, *tdp;
1629 	struct rusage rusage_before, rusage_after;
1630 	const char *dispname;
1631 	char *error;
1632 
1633 	sendrv = closerv = stderrfd = -1;
1634 	isconversion = isdata = isls = dolog = 0;
1635 	tdp = NULL;
1636 	dispname = name;
1637 	fin = dout = NULL;
1638 	error = NULL;
1639 	if (argv == NULL) {		/* if not running a command ... */
1640 		dolog = 1;
1641 		isdata = 1;
1642 		fin = fopen(name, "r");
1643 		closefunc = fclose;
1644 		if (fin == NULL)	/* doesn't exist?; try a conversion */
1645 			argv = do_conversion(name);
1646 		if (argv != NULL) {
1647 			isconversion++;
1648 			syslog(LOG_DEBUG, "get command: '%s' on '%s'",
1649 			    argv[0], name);
1650 		}
1651 	}
1652 	if (argv != NULL) {
1653 		char temp[MAXPATHLEN];
1654 
1655 		if (strcmp(argv[0], INTERNAL_LS) == 0) {
1656 			isls = 1;
1657 			stderrfd = -1;
1658 		} else {
1659 			(void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
1660 			stderrfd = mkstemp(temp);
1661 			if (stderrfd != -1)
1662 				(void)unlink(temp);
1663 		}
1664 		dispname = argv[0];
1665 		fin = ftpd_popen(argv, "r", stderrfd);
1666 		closefunc = ftpd_pclose;
1667 		st.st_size = -1;
1668 		st.st_blksize = BUFSIZ;
1669 	}
1670 	if (fin == NULL) {
1671 		if (errno != 0) {
1672 			perror_reply(550, dispname);
1673 			if (dolog)
1674 				logxfer("get", -1, name, NULL, NULL,
1675 				    strerror(errno));
1676 		}
1677 		goto cleanupretrieve;
1678 	}
1679 	byte_count = -1;
1680 	if (argv == NULL
1681 	    && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1682 		error = "Not a plain file";
1683 		reply(550, "%s: %s.", dispname, error);
1684 		goto done;
1685 	}
1686 	if (restart_point) {
1687 		if (type == TYPE_A) {
1688 			off_t i;
1689 			int c;
1690 
1691 			for (i = 0; i < restart_point; i++) {
1692 				if ((c=getc(fin)) == EOF) {
1693 					error = strerror(errno);
1694 					perror_reply(550, dispname);
1695 					goto done;
1696 				}
1697 				if (c == '\n')
1698 					i++;
1699 			}
1700 		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1701 			error = strerror(errno);
1702 			perror_reply(550, dispname);
1703 			goto done;
1704 		}
1705 	}
1706 	dout = dataconn(dispname, st.st_size, "w");
1707 	if (dout == NULL)
1708 		goto done;
1709 
1710 	(void)getrusage(RUSAGE_SELF, &rusage_before);
1711 	(void)gettimeofday(&start, NULL);
1712 	sendrv = send_data(fin, dout, &st, isdata);
1713 	(void)gettimeofday(&finish, NULL);
1714 	(void)getrusage(RUSAGE_SELF, &rusage_after);
1715 	closedataconn(dout);		/* close now to affect timing stats */
1716 	timersub(&finish, &start, &td);
1717 	tdp = &td;
1718  done:
1719 	if (dolog) {
1720 		logxfer("get", byte_count, name, NULL, tdp, error);
1721 		if (tdp != NULL)
1722 			logrusage(&rusage_before, &rusage_after);
1723 	}
1724 	closerv = (*closefunc)(fin);
1725 	if (sendrv == 0) {
1726 		FILE *errf;
1727 		struct stat sb;
1728 
1729 		if (!isls && argv != NULL && closerv != 0) {
1730 			reply(-226,
1731 			    "Command returned an exit status of %d",
1732 			    closerv);
1733 			if (isconversion)
1734 				syslog(LOG_WARNING,
1735 				    "retrieve command: '%s' returned %d",
1736 				    argv[0], closerv);
1737 		}
1738 		if (!isls && argv != NULL && stderrfd != -1 &&
1739 		    (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
1740 		    ((errf = fdopen(stderrfd, "r")) != NULL)) {
1741 			char *cp, line[LINE_MAX];
1742 
1743 			reply(-226, "Command error messages:");
1744 			rewind(errf);
1745 			while (fgets(line, sizeof(line), errf) != NULL) {
1746 				if ((cp = strchr(line, '\n')) != NULL)
1747 					*cp = '\0';
1748 				reply(0, "  %s", line);
1749 			}
1750 			(void) fflush(stdout);
1751 			(void) fclose(errf);
1752 				/* a reply(226,) must follow */
1753 		}
1754 		reply(226, "Transfer complete.");
1755 	}
1756  cleanupretrieve:
1757 	if (stderrfd != -1)
1758 		(void)close(stderrfd);
1759 	if (isconversion)
1760 		free(argv);
1761 }
1762 
1763 void
1764 store(const char *name, const char *fmode, int unique)
1765 {
1766 	FILE *fout, *din;
1767 	struct stat st;
1768 	int (*closefunc)(FILE *);
1769 	struct timeval start, finish, td, *tdp;
1770 	char *desc, *error;
1771 
1772 	din = NULL;
1773 	desc = (*fmode == 'w') ? "put" : "append";
1774 	error = NULL;
1775 	if (unique && stat(name, &st) == 0 &&
1776 	    (name = gunique(name)) == NULL) {
1777 		logxfer(desc, -1, name, NULL, NULL,
1778 		    "cannot create unique file");
1779 		goto cleanupstore;
1780 	}
1781 
1782 	if (restart_point)
1783 		fmode = "r+";
1784 	fout = fopen(name, fmode);
1785 	closefunc = fclose;
1786 	tdp = NULL;
1787 	if (fout == NULL) {
1788 		perror_reply(553, name);
1789 		logxfer(desc, -1, name, NULL, NULL, strerror(errno));
1790 		goto cleanupstore;
1791 	}
1792 	byte_count = -1;
1793 	if (restart_point) {
1794 		if (type == TYPE_A) {
1795 			off_t i;
1796 			int c;
1797 
1798 			for (i = 0; i < restart_point; i++) {
1799 				if ((c=getc(fout)) == EOF) {
1800 					error = strerror(errno);
1801 					perror_reply(550, name);
1802 					goto done;
1803 				}
1804 				if (c == '\n')
1805 					i++;
1806 			}
1807 			/*
1808 			 * We must do this seek to "current" position
1809 			 * because we are changing from reading to
1810 			 * writing.
1811 			 */
1812 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1813 				error = strerror(errno);
1814 				perror_reply(550, name);
1815 				goto done;
1816 			}
1817 		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1818 			error = strerror(errno);
1819 			perror_reply(550, name);
1820 			goto done;
1821 		}
1822 	}
1823 	din = dataconn(name, (off_t)-1, "r");
1824 	if (din == NULL)
1825 		goto done;
1826 	(void)gettimeofday(&start, NULL);
1827 	if (receive_data(din, fout) == 0) {
1828 		if (unique)
1829 			reply(226, "Transfer complete (unique file name:%s).",
1830 			    name);
1831 		else
1832 			reply(226, "Transfer complete.");
1833 	}
1834 	(void)gettimeofday(&finish, NULL);
1835 	closedataconn(din);		/* close now to affect timing stats */
1836 	timersub(&finish, &start, &td);
1837 	tdp = &td;
1838  done:
1839 	logxfer(desc, byte_count, name, NULL, tdp, error);
1840 	(*closefunc)(fout);
1841  cleanupstore:
1842 	;
1843 }
1844 
1845 static FILE *
1846 getdatasock(const char *fmode)
1847 {
1848 	int		on, s, t, tries;
1849 	in_port_t	port;
1850 
1851 	on = 1;
1852 	if (data >= 0)
1853 		return (fdopen(data, fmode));
1854 	if (! dropprivs)
1855 		(void) seteuid((uid_t)0);
1856 	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1857 	if (s < 0)
1858 		goto bad;
1859 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1860 	    (char *) &on, sizeof(on)) < 0)
1861 		goto bad;
1862 	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1863 	    (char *) &on, sizeof(on)) < 0)
1864 		goto bad;
1865 			/* anchor socket to avoid multi-homing problems */
1866 	data_source = ctrl_addr;
1867 			/*
1868 			 * By default source port for PORT connctions is
1869 			 * ctrlport-1 (see RFC959 section 5.2).
1870 			 * However, if privs have been dropped and that
1871 			 * would be < IPPORT_RESERVED, use a random port
1872 			 * instead.
1873 			 */
1874 	if (dataport)
1875 		port = dataport;
1876 	else
1877 		port = ntohs(ctrl_addr.su_port) - 1;
1878 	if (dropprivs && port < IPPORT_RESERVED)
1879 		port = 0;		/* use random port */
1880 	data_source.su_port = htons(port);
1881 
1882 	for (tries = 1; ; tries++) {
1883 		if (bind(s, (struct sockaddr *)&data_source.si_su,
1884 		    data_source.su_len) >= 0)
1885 			break;
1886 		if (errno != EADDRINUSE || tries > 10)
1887 			goto bad;
1888 		sleep(tries);
1889 	}
1890 	if (! dropprivs)
1891 		(void) seteuid((uid_t)pw->pw_uid);
1892 #ifdef IP_TOS
1893 	if (!mapped && ctrl_addr.su_family == AF_INET) {
1894 		on = IPTOS_THROUGHPUT;
1895 		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1896 			       sizeof(int)) < 0)
1897 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1898 	}
1899 #endif
1900 	return (fdopen(s, fmode));
1901  bad:
1902 		/* Return the real value of errno (close may change it) */
1903 	t = errno;
1904 	if (! dropprivs)
1905 		(void) seteuid((uid_t)pw->pw_uid);
1906 	(void) close(s);
1907 	errno = t;
1908 	return (NULL);
1909 }
1910 
1911 FILE *
1912 dataconn(const char *name, off_t size, const char *fmode)
1913 {
1914 	char sizebuf[32];
1915 	FILE *file;
1916 	int retry, tos, keepalive, conerrno;
1917 
1918 	file_size = size;
1919 	byte_count = 0;
1920 	if (size != (off_t) -1)
1921 		(void)snprintf(sizebuf, sizeof(sizebuf), " (" LLF " byte%s)",
1922 		    (LLT)size, PLURAL(size));
1923 	else
1924 		sizebuf[0] = '\0';
1925 	if (pdata >= 0) {
1926 		struct sockinet from;
1927 		int s;
1928 		socklen_t fromlen = sizeof(from.su_len);
1929 
1930 		(void) alarm(curclass.timeout);
1931 		s = accept(pdata, (struct sockaddr *)&from.si_su, &fromlen);
1932 		(void) alarm(0);
1933 		if (s < 0) {
1934 			reply(425, "Can't open data connection.");
1935 			(void) close(pdata);
1936 			pdata = -1;
1937 			return (NULL);
1938 		}
1939 		(void) close(pdata);
1940 		pdata = s;
1941 		switch (from.su_family) {
1942 		case AF_INET:
1943 #ifdef IP_TOS
1944 			if (!mapped) {
1945 				tos = IPTOS_THROUGHPUT;
1946 				(void) setsockopt(s, IPPROTO_IP, IP_TOS,
1947 				    (char *)&tos, sizeof(int));
1948 			}
1949 			break;
1950 #endif
1951 		}
1952 		/* Set keepalives on the socket to detect dropped conns. */
1953 #ifdef SO_KEEPALIVE
1954 		keepalive = 1;
1955 		(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1956 		    (char *)&keepalive, sizeof(int));
1957 #endif
1958 		reply(150, "Opening %s mode data connection for '%s'%s.",
1959 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1960 		return (fdopen(pdata, fmode));
1961 	}
1962 	if (data >= 0) {
1963 		reply(125, "Using existing data connection for '%s'%s.",
1964 		    name, sizebuf);
1965 		usedefault = 1;
1966 		return (fdopen(data, fmode));
1967 	}
1968 	if (usedefault)
1969 		data_dest = his_addr;
1970 	usedefault = 1;
1971 	retry = conerrno = 0;
1972 	do {
1973 		file = getdatasock(fmode);
1974 		if (file == NULL) {
1975 			char hbuf[NI_MAXHOST];
1976 			char pbuf[NI_MAXSERV];
1977 
1978 			if (getnameinfo((struct sockaddr *)&data_source.si_su,
1979 			    data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1980 			    sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV))
1981 				strlcpy(hbuf, "?", sizeof(hbuf));
1982 			reply(425, "Can't create data socket (%s,%s): %s.",
1983 			      hbuf, pbuf, strerror(errno));
1984 			return (NULL);
1985 		}
1986 		data = fileno(file);
1987 		conerrno = 0;
1988 		if (connect(data, (struct sockaddr *)&data_dest.si_su,
1989 		    data_dest.su_len) == 0)
1990 			break;
1991 		conerrno = errno;
1992 		(void) fclose(file);
1993 		file = NULL;
1994 		data = -1;
1995 		if (conerrno == EADDRINUSE) {
1996 			sleep((unsigned) swaitint);
1997 			retry += swaitint;
1998 		} else {
1999 			break;
2000 		}
2001 	} while (retry <= swaitmax);
2002 	if (conerrno != 0) {
2003 		perror_reply(425, "Can't build data connection");
2004 		return (NULL);
2005 	}
2006 	reply(150, "Opening %s mode data connection for '%s'%s.",
2007 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
2008 	return (file);
2009 }
2010 
2011 void
2012 closedataconn(FILE *fd)
2013 {
2014 
2015 	if (fd == NULL)
2016 		return;
2017 	(void)fclose(fd);
2018 	data = -1;
2019 	if (pdata >= 0)
2020 		(void)close(pdata);
2021 	pdata = -1;
2022 }
2023 
2024 int
2025 write_data(int fd, char *buf, size_t size, off_t *bufrem,
2026     struct timeval *then, int isdata)
2027 {
2028 	struct timeval now, td;
2029 	ssize_t c;
2030 
2031 	while (size > 0) {
2032 		c = size;
2033 		if (curclass.writesize) {
2034 			if (curclass.writesize < c)
2035 				c = curclass.writesize;
2036 		}
2037 		if (curclass.rateget) {
2038 			if (*bufrem < c)
2039 				c = *bufrem;
2040 		}
2041 		(void) alarm(curclass.timeout);
2042 		c = write(fd, buf, c);
2043 		if (c <= 0)
2044 			return (1);
2045 		buf += c;
2046 		size -= c;
2047 		byte_count += c;
2048 		if (isdata) {
2049 			total_data_out += c;
2050 			total_data += c;
2051 		}
2052 		total_bytes_out += c;
2053 		total_bytes += c;
2054 		if (curclass.rateget) {
2055 			*bufrem -= c;
2056 			if (*bufrem == 0) {
2057 				(void)gettimeofday(&now, NULL);
2058 				timersub(&now, then, &td);
2059 				if (td.tv_sec == 0) {
2060 					usleep(1000000 - td.tv_usec);
2061 					(void)gettimeofday(then, NULL);
2062 				} else
2063 					*then = now;
2064 				*bufrem = curclass.rateget;
2065 			}
2066 		}
2067 	}
2068 	return (0);
2069 }
2070 
2071 static enum send_status
2072 send_data_with_read(int filefd, int netfd, const struct stat *st, int isdata)
2073 {
2074 	struct timeval then;
2075 	off_t bufrem;
2076 	size_t readsize;
2077 	char *buf;
2078 	int c, error;
2079 
2080 	if (curclass.readsize)
2081 		readsize = curclass.readsize;
2082 	else
2083 		readsize = (size_t)st->st_blksize;
2084 	if ((buf = malloc(readsize)) == NULL) {
2085 		perror_reply(451, "Local resource failure: malloc");
2086 		return (SS_NO_TRANSFER);
2087 	}
2088 
2089 	if (curclass.rateget) {
2090 		bufrem = curclass.rateget;
2091 		(void)gettimeofday(&then, NULL);
2092 	}
2093 	while (1) {
2094 		(void) alarm(curclass.timeout);
2095 		c = read(filefd, buf, readsize);
2096 		if (c == 0)
2097 			error = SS_SUCCESS;
2098 		else if (c < 0)
2099 			error = SS_FILE_ERROR;
2100 		else if (write_data(netfd, buf, c, &bufrem, &then, isdata))
2101 			error = SS_DATA_ERROR;
2102 		else if (urgflag && handleoobcmd())
2103 			error = SS_ABORTED;
2104 		else
2105 			continue;
2106 
2107 		free(buf);
2108 		return (error);
2109 	}
2110 }
2111 
2112 static enum send_status
2113 send_data_with_mmap(int filefd, int netfd, const struct stat *st, int isdata)
2114 {
2115 	struct timeval then;
2116 	off_t bufrem, filesize, off, origoff;
2117 	size_t mapsize, winsize;
2118 	int error, sendbufsize, sendlowat;
2119 	void *win;
2120 
2121 	if (curclass.sendbufsize) {
2122 		sendbufsize = curclass.sendbufsize;
2123 		if (setsockopt(netfd, SOL_SOCKET, SO_SNDBUF,
2124 		    &sendbufsize, sizeof(int)) == -1)
2125 			syslog(LOG_WARNING, "setsockopt(SO_SNDBUF, %d): %m",
2126 			    sendbufsize);
2127 	}
2128 
2129 	if (curclass.sendlowat) {
2130 		sendlowat = curclass.sendlowat;
2131 		if (setsockopt(netfd, SOL_SOCKET, SO_SNDLOWAT,
2132 		    &sendlowat, sizeof(int)) == -1)
2133 			syslog(LOG_WARNING, "setsockopt(SO_SNDLOWAT, %d): %m",
2134 			    sendlowat);
2135 	}
2136 
2137 	winsize = curclass.mmapsize;
2138 	filesize = st->st_size;
2139 	if (ftpd_debug)
2140 		syslog(LOG_INFO, "mmapsize = %ld, writesize = %ld",
2141 		    (long)winsize, (long)curclass.writesize);
2142 	if (winsize == 0)
2143 		goto try_read;
2144 
2145 	off = lseek(filefd, (off_t)0, SEEK_CUR);
2146 	if (off == -1)
2147 		goto try_read;
2148 
2149 	origoff = off;
2150 	if (curclass.rateget) {
2151 		bufrem = curclass.rateget;
2152 		(void)gettimeofday(&then, NULL);
2153 	}
2154 	while (1) {
2155 		mapsize = MIN(filesize - off, winsize);
2156 		if (mapsize == 0)
2157 			break;
2158 		win = mmap(NULL, mapsize, PROT_READ,
2159 		    MAP_FILE|MAP_SHARED, filefd, off);
2160 		if (win == MAP_FAILED) {
2161 			if (off == origoff)
2162 				goto try_read;
2163 			return (SS_FILE_ERROR);
2164 		}
2165 		(void) madvise(win, mapsize, MADV_SEQUENTIAL);
2166 		error = write_data(netfd, win, mapsize, &bufrem, &then,
2167 		    isdata);
2168 		(void) madvise(win, mapsize, MADV_DONTNEED);
2169 		munmap(win, mapsize);
2170 		if (urgflag && handleoobcmd())
2171 			return (SS_ABORTED);
2172 		if (error)
2173 			return (SS_DATA_ERROR);
2174 		off += mapsize;
2175 	}
2176 	return (SS_SUCCESS);
2177 
2178  try_read:
2179 	return (send_data_with_read(filefd, netfd, st, isdata));
2180 }
2181 
2182 /*
2183  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
2184  * encapsulation of the data subject to Mode, Structure, and Type.
2185  *
2186  * NB: Form isn't handled.
2187  */
2188 static int
2189 send_data(FILE *instr, FILE *outstr, const struct stat *st, int isdata)
2190 {
2191 	int	 c, filefd, netfd, rval;
2192 
2193 	urgflag = 0;
2194 	transflag = 1;
2195 	rval = -1;
2196 
2197 	switch (type) {
2198 
2199 	case TYPE_A:
2200  /* XXXLUKEM: rate limit ascii send (get) */
2201 		(void) alarm(curclass.timeout);
2202 		while ((c = getc(instr)) != EOF) {
2203 			if (urgflag && handleoobcmd())
2204 				goto cleanup_send_data;
2205 			byte_count++;
2206 			if (c == '\n') {
2207 				if (ferror(outstr))
2208 					goto data_err;
2209 				(void) putc('\r', outstr);
2210 				if (isdata) {
2211 					total_data_out++;
2212 					total_data++;
2213 				}
2214 				total_bytes_out++;
2215 				total_bytes++;
2216 			}
2217 			(void) putc(c, outstr);
2218 			if (isdata) {
2219 				total_data_out++;
2220 				total_data++;
2221 			}
2222 			total_bytes_out++;
2223 			total_bytes++;
2224 			if ((byte_count % 4096) == 0)
2225 				(void) alarm(curclass.timeout);
2226 		}
2227 		(void) alarm(0);
2228 		fflush(outstr);
2229 		if (ferror(instr))
2230 			goto file_err;
2231 		if (ferror(outstr))
2232 			goto data_err;
2233 		rval = 0;
2234 		goto cleanup_send_data;
2235 
2236 	case TYPE_I:
2237 	case TYPE_L:
2238 		filefd = fileno(instr);
2239 		netfd = fileno(outstr);
2240 		switch (send_data_with_mmap(filefd, netfd, st, isdata)) {
2241 
2242 		case SS_SUCCESS:
2243 			break;
2244 
2245 		case SS_ABORTED:
2246 		case SS_NO_TRANSFER:
2247 			goto cleanup_send_data;
2248 
2249 		case SS_FILE_ERROR:
2250 			goto file_err;
2251 
2252 		case SS_DATA_ERROR:
2253 			goto data_err;
2254 		}
2255 		rval = 0;
2256 		goto cleanup_send_data;
2257 
2258 	default:
2259 		reply(550, "Unimplemented TYPE %d in send_data", type);
2260 		goto cleanup_send_data;
2261 	}
2262 
2263  data_err:
2264 	(void) alarm(0);
2265 	perror_reply(426, "Data connection");
2266 	goto cleanup_send_data;
2267 
2268  file_err:
2269 	(void) alarm(0);
2270 	perror_reply(551, "Error on input file");
2271 	goto cleanup_send_data;
2272 
2273  cleanup_send_data:
2274 	(void) alarm(0);
2275 	transflag = 0;
2276 	urgflag = 0;
2277 	if (isdata) {
2278 		total_files_out++;
2279 		total_files++;
2280 	}
2281 	total_xfers_out++;
2282 	total_xfers++;
2283 	return (rval);
2284 }
2285 
2286 /*
2287  * Transfer data from peer to "outstr" using the appropriate encapulation of
2288  * the data subject to Mode, Structure, and Type.
2289  *
2290  * N.B.: Form isn't handled.
2291  */
2292 static int
2293 receive_data(FILE *instr, FILE *outstr)
2294 {
2295 	int	c, netfd, filefd, rval;
2296 	int	volatile bare_lfs;
2297 	off_t	byteswritten;
2298 	char	*buf;
2299 	size_t	readsize;
2300 	struct sigaction sa, sa_saved;
2301 	struct stat st;
2302 
2303 	memset(&sa, 0, sizeof(sa));
2304 	sigfillset(&sa.sa_mask);
2305 	sa.sa_flags = SA_RESTART;
2306 	sa.sa_handler = lostconn;
2307 	(void) sigaction(SIGALRM, &sa, &sa_saved);
2308 
2309 	bare_lfs = 0;
2310 	urgflag = 0;
2311 	transflag = 1;
2312 	rval = -1;
2313 	byteswritten = 0;
2314 	buf = NULL;
2315 
2316 #define FILESIZECHECK(x) \
2317 			do { \
2318 				if (curclass.maxfilesize != -1 && \
2319 				    (x) > curclass.maxfilesize) { \
2320 					errno = EFBIG; \
2321 					goto file_err; \
2322 				} \
2323 			} while (0)
2324 
2325 	switch (type) {
2326 
2327 	case TYPE_I:
2328 	case TYPE_L:
2329 		netfd = fileno(instr);
2330 		filefd = fileno(outstr);
2331 		(void) alarm(curclass.timeout);
2332 		if (curclass.readsize)
2333 			readsize = curclass.readsize;
2334 		else if (fstat(filefd, &st))
2335 			readsize = (size_t)st.st_blksize;
2336 		else
2337 			readsize = BUFSIZ;
2338 		if ((buf = malloc(readsize)) == NULL) {
2339 			perror_reply(451, "Local resource failure: malloc");
2340 			goto cleanup_recv_data;
2341 		}
2342 		if (curclass.rateput) {
2343 			while (1) {
2344 				int d;
2345 				struct timeval then, now, td;
2346 				off_t bufrem;
2347 
2348 				(void)gettimeofday(&then, NULL);
2349 				errno = c = d = 0;
2350 				for (bufrem = curclass.rateput; bufrem > 0; ) {
2351 					if ((c = read(netfd, buf,
2352 					    MIN(readsize, bufrem))) <= 0)
2353 						goto recvdone;
2354 					if (urgflag && handleoobcmd())
2355 						goto cleanup_recv_data;
2356 					FILESIZECHECK(byte_count + c);
2357 					if ((d = write(filefd, buf, c)) != c)
2358 						goto file_err;
2359 					(void) alarm(curclass.timeout);
2360 					bufrem -= c;
2361 					byte_count += c;
2362 					total_data_in += c;
2363 					total_data += c;
2364 					total_bytes_in += c;
2365 					total_bytes += c;
2366 				}
2367 				(void)gettimeofday(&now, NULL);
2368 				timersub(&now, &then, &td);
2369 				if (td.tv_sec == 0)
2370 					usleep(1000000 - td.tv_usec);
2371 			}
2372 		} else {
2373 			while ((c = read(netfd, buf, readsize)) > 0) {
2374 				if (urgflag && handleoobcmd())
2375 					goto cleanup_recv_data;
2376 				FILESIZECHECK(byte_count + c);
2377 				if (write(filefd, buf, c) != c)
2378 					goto file_err;
2379 				(void) alarm(curclass.timeout);
2380 				byte_count += c;
2381 				total_data_in += c;
2382 				total_data += c;
2383 				total_bytes_in += c;
2384 				total_bytes += c;
2385 			}
2386 		}
2387  recvdone:
2388 		if (c < 0)
2389 			goto data_err;
2390 		rval = 0;
2391 		goto cleanup_recv_data;
2392 
2393 	case TYPE_E:
2394 		reply(553, "TYPE E not implemented.");
2395 		goto cleanup_recv_data;
2396 
2397 	case TYPE_A:
2398 		(void) alarm(curclass.timeout);
2399  /* XXXLUKEM: rate limit ascii receive (put) */
2400 		while ((c = getc(instr)) != EOF) {
2401 			if (urgflag && handleoobcmd())
2402 				goto cleanup_recv_data;
2403 			byte_count++;
2404 			total_data_in++;
2405 			total_data++;
2406 			total_bytes_in++;
2407 			total_bytes++;
2408 			if ((byte_count % 4096) == 0)
2409 				(void) alarm(curclass.timeout);
2410 			if (c == '\n')
2411 				bare_lfs++;
2412 			while (c == '\r') {
2413 				if (ferror(outstr))
2414 					goto data_err;
2415 				if ((c = getc(instr)) != '\n') {
2416 					byte_count++;
2417 					total_data_in++;
2418 					total_data++;
2419 					total_bytes_in++;
2420 					total_bytes++;
2421 					if ((byte_count % 4096) == 0)
2422 						(void) alarm(curclass.timeout);
2423 					byteswritten++;
2424 					FILESIZECHECK(byteswritten);
2425 					(void) putc ('\r', outstr);
2426 					if (c == '\0' || c == EOF)
2427 						goto contin2;
2428 				}
2429 			}
2430 			byteswritten++;
2431 			FILESIZECHECK(byteswritten);
2432 			(void) putc(c, outstr);
2433  contin2:	;
2434 		}
2435 		(void) alarm(0);
2436 		fflush(outstr);
2437 		if (ferror(instr))
2438 			goto data_err;
2439 		if (ferror(outstr))
2440 			goto file_err;
2441 		if (bare_lfs) {
2442 			reply(-226,
2443 			    "WARNING! %d bare linefeeds received in ASCII mode",
2444 			    bare_lfs);
2445 			reply(0, "File may not have transferred correctly.");
2446 		}
2447 		rval = 0;
2448 		goto cleanup_recv_data;
2449 
2450 	default:
2451 		reply(550, "Unimplemented TYPE %d in receive_data", type);
2452 		goto cleanup_recv_data;
2453 	}
2454 #undef FILESIZECHECK
2455 
2456  data_err:
2457 	(void) alarm(0);
2458 	perror_reply(426, "Data Connection");
2459 	goto cleanup_recv_data;
2460 
2461  file_err:
2462 	(void) alarm(0);
2463 	perror_reply(452, "Error writing file");
2464 	goto cleanup_recv_data;
2465 
2466  cleanup_recv_data:
2467 	(void) alarm(0);
2468 	(void) sigaction(SIGALRM, &sa_saved, NULL);
2469 	if (buf)
2470 		free(buf);
2471 	transflag = 0;
2472 	urgflag = 0;
2473 	total_files_in++;
2474 	total_files++;
2475 	total_xfers_in++;
2476 	total_xfers++;
2477 	return (rval);
2478 }
2479 
2480 void
2481 statcmd(void)
2482 {
2483 	struct sockinet *su = NULL;
2484 	static char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
2485 	u_char *a, *p;
2486 	int ispassive, af;
2487 	off_t otbi, otbo, otb;
2488 
2489 	a = p = (u_char *)NULL;
2490 
2491 	reply(-211, "%s FTP server status:", hostname);
2492 	reply(0, "Version: %s", EMPTYSTR(version) ? "<suppressed>" : version);
2493 	hbuf[0] = '\0';
2494 	if (!getnameinfo((struct sockaddr *)&his_addr.si_su, his_addr.su_len,
2495 			hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)
2496 	    && strcmp(remotehost, hbuf) != 0)
2497 		reply(0, "Connected to %s (%s)", remotehost, hbuf);
2498 	else
2499 		reply(0, "Connected to %s", remotehost);
2500 
2501 	if (logged_in) {
2502 		if (curclass.type == CLASS_GUEST)
2503 			reply(0, "Logged in anonymously");
2504 		else
2505 			reply(0, "Logged in as %s%s", pw->pw_name,
2506 			    curclass.type == CLASS_CHROOT ? " (chroot)" : "");
2507 	} else if (askpasswd)
2508 		reply(0, "Waiting for password");
2509 	else
2510 		reply(0, "Waiting for user name");
2511 	cprintf(stdout, "    TYPE: %s", typenames[type]);
2512 	if (type == TYPE_A || type == TYPE_E)
2513 		cprintf(stdout, ", FORM: %s", formnames[form]);
2514 	if (type == TYPE_L) {
2515 #if NBBY == 8
2516 		cprintf(stdout, " %d", NBBY);
2517 #else
2518 			/* XXX: `bytesize' needs to be defined in this case */
2519 		cprintf(stdout, " %d", bytesize);
2520 #endif
2521 	}
2522 	cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n",
2523 	    strunames[stru], modenames[mode]);
2524 	ispassive = 0;
2525 	if (data != -1) {
2526 		reply(0, "Data connection open");
2527 		su = NULL;
2528 	} else if (pdata != -1) {
2529 		reply(0, "in Passive mode");
2530 		if (curclass.advertise.su_len != 0)
2531 			su = &curclass.advertise;
2532 		else
2533 			su = &pasv_addr;
2534 		ispassive = 1;
2535 		goto printaddr;
2536 	} else if (usedefault == 0) {
2537 		su = (struct sockinet *)&data_dest;
2538 
2539 		if (epsvall) {
2540 			reply(0, "EPSV only mode (EPSV ALL)");
2541 			goto epsvonly;
2542 		}
2543  printaddr:
2544 							/* PASV/PORT */
2545 		if (su->su_family == AF_INET) {
2546 			a = (u_char *) &su->su_addr;
2547 			p = (u_char *) &su->su_port;
2548 #define UC(b) (((int) b) & 0xff)
2549 			reply(0, "%s (%d,%d,%d,%d,%d,%d)",
2550 				ispassive ? "PASV" : "PORT" ,
2551 				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2552 				UC(p[0]), UC(p[1]));
2553 		}
2554 
2555 							/* LPSV/LPRT */
2556 	    {
2557 		int alen, i;
2558 
2559 		alen = 0;
2560 		switch (su->su_family) {
2561 		case AF_INET:
2562 			a = (u_char *) &su->su_addr;
2563 			p = (u_char *) &su->su_port;
2564 			alen = sizeof(su->su_addr);
2565 			af = 4;
2566 			break;
2567 #ifdef INET6
2568 		case AF_INET6:
2569 			a = (u_char *) &su->su_6addr;
2570 			p = (u_char *) &su->su_port;
2571 			alen = sizeof(su->su_6addr);
2572 			af = 6;
2573 			break;
2574 #endif
2575 		default:
2576 			af = 0;
2577 			break;
2578 		}
2579 		if (af) {
2580 			cprintf(stdout, "    %s (%d,%d",
2581 			    ispassive ? "LPSV" : "LPRT", af, alen);
2582 			for (i = 0; i < alen; i++)
2583 				cprintf(stdout, ",%d", UC(a[i]));
2584 			cprintf(stdout, ",%d,%d,%d)\r\n",
2585 			    2, UC(p[0]), UC(p[1]));
2586 #undef UC
2587 		}
2588 	    }
2589 
2590 		/* EPRT/EPSV */
2591  epsvonly:
2592 		af = af2epsvproto(su->su_family);
2593 		hbuf[0] = '\0';
2594 		if (af > 0) {
2595 			struct sockinet tmp;
2596 
2597 			tmp = *su;
2598 #ifdef INET6
2599 			if (tmp.su_family == AF_INET6)
2600 				tmp.su_scope_id = 0;
2601 #endif
2602 			if (getnameinfo((struct sockaddr *)&tmp.si_su,
2603 			    tmp.su_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
2604 			    NI_NUMERICHOST | NI_NUMERICSERV) == 0)
2605 				reply(0, "%s (|%d|%s|%s|)",
2606 				    ispassive ? "EPSV" : "EPRT",
2607 				    af, hbuf, sbuf);
2608 		}
2609 	} else
2610 		reply(0, "No data connection");
2611 
2612 	if (logged_in) {
2613 		reply(0,
2614 		    "Data sent:        " LLF " byte%s in " LLF " file%s",
2615 		    (LLT)total_data_out, PLURAL(total_data_out),
2616 		    (LLT)total_files_out, PLURAL(total_files_out));
2617 		reply(0,
2618 		    "Data received:    " LLF " byte%s in " LLF " file%s",
2619 		    (LLT)total_data_in, PLURAL(total_data_in),
2620 		    (LLT)total_files_in, PLURAL(total_files_in));
2621 		reply(0,
2622 		    "Total data:       " LLF " byte%s in " LLF " file%s",
2623 		    (LLT)total_data, PLURAL(total_data),
2624 		    (LLT)total_files, PLURAL(total_files));
2625 	}
2626 	otbi = total_bytes_in;
2627 	otbo = total_bytes_out;
2628 	otb = total_bytes;
2629 	reply(0, "Traffic sent:     " LLF " byte%s in " LLF " transfer%s",
2630 	    (LLT)otbo, PLURAL(otbo),
2631 	    (LLT)total_xfers_out, PLURAL(total_xfers_out));
2632 	reply(0, "Traffic received: " LLF " byte%s in " LLF " transfer%s",
2633 	    (LLT)otbi, PLURAL(otbi),
2634 	    (LLT)total_xfers_in, PLURAL(total_xfers_in));
2635 	reply(0, "Total traffic:    " LLF " byte%s in " LLF " transfer%s",
2636 	    (LLT)otb, PLURAL(otb),
2637 	    (LLT)total_xfers, PLURAL(total_xfers));
2638 
2639 	if (logged_in && !CURCLASS_FLAGS_ISSET(private)) {
2640 		struct ftpconv *cp;
2641 
2642 		reply(0, "%s", "");
2643 		reply(0, "Class: %s, type: %s",
2644 		    curclass.classname, CURCLASSTYPE);
2645 		reply(0, "Check PORT/LPRT commands: %sabled",
2646 		    CURCLASS_FLAGS_ISSET(checkportcmd) ? "en" : "dis");
2647 		if (! EMPTYSTR(curclass.display))
2648 			reply(0, "Display file: %s", curclass.display);
2649 		if (! EMPTYSTR(curclass.notify))
2650 			reply(0, "Notify fileglob: %s", curclass.notify);
2651 		reply(0, "Idle timeout: " LLF ", maximum timeout: " LLF,
2652 		    (LLT)curclass.timeout, (LLT)curclass.maxtimeout);
2653 		reply(0, "Current connections: %d", connections);
2654 		if (curclass.limit == -1)
2655 			reply(0, "Maximum connections: unlimited");
2656 		else
2657 			reply(0, "Maximum connections: " LLF,
2658 			    (LLT)curclass.limit);
2659 		if (curclass.limitfile)
2660 			reply(0, "Connection limit exceeded message file: %s",
2661 			    conffilename(curclass.limitfile));
2662 		if (! EMPTYSTR(curclass.chroot))
2663 			reply(0, "Chroot format: %s", curclass.chroot);
2664 		reply(0, "Deny bad ftpusers(5) quickly: %sabled",
2665 		    CURCLASS_FLAGS_ISSET(denyquick) ? "en" : "dis");
2666 		if (! EMPTYSTR(curclass.homedir))
2667 			reply(0, "Homedir format: %s", curclass.homedir);
2668 		if (curclass.maxfilesize == -1)
2669 			reply(0, "Maximum file size: unlimited");
2670 		else
2671 			reply(0, "Maximum file size: " LLF,
2672 			    (LLT)curclass.maxfilesize);
2673 		if (! EMPTYSTR(curclass.motd))
2674 			reply(0, "MotD file: %s", conffilename(curclass.motd));
2675 		reply(0,
2676 	    "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
2677 		    CURCLASS_FLAGS_ISSET(modify) ? "en" : "dis");
2678 		reply(0, "Upload commands (APPE, STOR, STOU): %sabled",
2679 		    CURCLASS_FLAGS_ISSET(upload) ? "en" : "dis");
2680 		reply(0, "Sanitize file names: %sabled",
2681 		    CURCLASS_FLAGS_ISSET(sanenames) ? "en" : "dis");
2682 		reply(0, "PASV/LPSV/EPSV connections: %sabled",
2683 		    CURCLASS_FLAGS_ISSET(passive) ? "en" : "dis");
2684 		if (curclass.advertise.su_len != 0) {
2685 			char buf[50];	/* big enough for IPv6 address */
2686 			const char *bp;
2687 
2688 			bp = inet_ntop(curclass.advertise.su_family,
2689 			    (void *)&curclass.advertise.su_addr,
2690 			    buf, sizeof(buf));
2691 			if (bp != NULL)
2692 				reply(0, "PASV advertise address: %s", bp);
2693 		}
2694 		if (curclass.portmin && curclass.portmax)
2695 			reply(0, "PASV port range: " LLF " - " LLF,
2696 			    (LLT)curclass.portmin, (LLT)curclass.portmax);
2697 		if (curclass.rateget)
2698 			reply(0, "Rate get limit: " LLF " bytes/sec",
2699 			    (LLT)curclass.rateget);
2700 		else
2701 			reply(0, "Rate get limit: disabled");
2702 		if (curclass.rateput)
2703 			reply(0, "Rate put limit: " LLF " bytes/sec",
2704 			    (LLT)curclass.rateput);
2705 		else
2706 			reply(0, "Rate put limit: disabled");
2707 		if (curclass.mmapsize)
2708 			reply(0, "Mmap size: " LLF, (LLT)curclass.mmapsize);
2709 		else
2710 			reply(0, "Mmap size: disabled");
2711 		if (curclass.readsize)
2712 			reply(0, "Read size: " LLF, (LLT)curclass.readsize);
2713 		else
2714 			reply(0, "Read size: default");
2715 		if (curclass.writesize)
2716 			reply(0, "Write size: " LLF, (LLT)curclass.writesize);
2717 		else
2718 			reply(0, "Write size: default");
2719 		if (curclass.recvbufsize)
2720 			reply(0, "Receive buffer size: " LLF,
2721 			    (LLT)curclass.recvbufsize);
2722 		else
2723 			reply(0, "Receive buffer size: default");
2724 		if (curclass.sendbufsize)
2725 			reply(0, "Send buffer size: " LLF,
2726 			    (LLT)curclass.sendbufsize);
2727 		else
2728 			reply(0, "Send buffer size: default");
2729 		if (curclass.sendlowat)
2730 			reply(0, "Send low water mark: " LLF,
2731 			    (LLT)curclass.sendlowat);
2732 		else
2733 			reply(0, "Send low water mark: default");
2734 		reply(0, "Umask: %.04o", curclass.umask);
2735 		for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
2736 			if (cp->suffix == NULL || cp->types == NULL ||
2737 			    cp->command == NULL)
2738 				continue;
2739 			reply(0, "Conversion: %s [%s] disable: %s, command: %s",
2740 			    cp->suffix, cp->types, cp->disable, cp->command);
2741 		}
2742 	}
2743 
2744 	reply(211, "End of status");
2745 }
2746 
2747 void
2748 fatal(const char *s)
2749 {
2750 
2751 	reply(451, "Error in server: %s\n", s);
2752 	reply(221, "Closing connection due to server error.");
2753 	dologout(0);
2754 	/* NOTREACHED */
2755 }
2756 
2757 /*
2758  * reply() --
2759  *	depending on the value of n, display fmt with a trailing CRLF and
2760  *	prefix of:
2761  *	n < -1		prefix the message with abs(n) + "-"	(initial line)
2762  *	n == 0		prefix the message with 4 spaces	(middle lines)
2763  *	n >  0		prefix the message with n + " "		(final line)
2764  */
2765 void
2766 reply(int n, const char *fmt, ...)
2767 {
2768 	char	msg[MAXPATHLEN * 2 + 100];
2769 	size_t	b;
2770 	va_list	ap;
2771 
2772 	b = 0;
2773 	if (n == 0)
2774 		b = snprintf(msg, sizeof(msg), "    ");
2775 	else if (n < 0)
2776 		b = snprintf(msg, sizeof(msg), "%d-", -n);
2777 	else
2778 		b = snprintf(msg, sizeof(msg), "%d ", n);
2779 	va_start(ap, fmt);
2780 	vsnprintf(msg + b, sizeof(msg) - b, fmt, ap);
2781 	va_end(ap);
2782 	cprintf(stdout, "%s\r\n", msg);
2783 	(void)fflush(stdout);
2784 	if (ftpd_debug)
2785 		syslog(LOG_DEBUG, "<--- %s", msg);
2786 }
2787 
2788 static void
2789 logremotehost(struct sockinet *who)
2790 {
2791 
2792 	if (getnameinfo((struct sockaddr *)&who->si_su,
2793 	    who->su_len, remotehost, sizeof(remotehost), NULL, 0,
2794 	    getnameopts))
2795 		strlcpy(remotehost, "?", sizeof(remotehost));
2796 
2797 #if defined(HAVE_SETPROCTITLE)
2798 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2799 	setproctitle("%s", proctitle);
2800 #endif /* defined(HAVE_SETPROCTITLE) */
2801 	if (logging)
2802 		syslog(LOG_INFO, "connection from %s to %s",
2803 		    remotehost, hostname);
2804 }
2805 
2806 /*
2807  * Record logout in wtmp file and exit with supplied status.
2808  * NOTE: because this is called from signal handlers it cannot
2809  *       use stdio (or call other functions that use stdio).
2810  */
2811 void
2812 dologout(int status)
2813 {
2814 	/*
2815 	* Prevent reception of SIGURG from resulting in a resumption
2816 	* back to the main program loop.
2817 	*/
2818 	transflag = 0;
2819 	logout_utmp();
2820 	if (logged_in) {
2821 #ifdef KERBEROS
2822 		if (!notickets && krbtkfile_env)
2823 			unlink(krbtkfile_env);
2824 #endif
2825 	}
2826 	/* beware of flushing buffers after a SIGPIPE */
2827 	if (xferlogfd != -1)
2828 		close(xferlogfd);
2829 	_exit(status);
2830 }
2831 
2832 void
2833 abor(void)
2834 {
2835 
2836 	if (!transflag)
2837 		return;
2838 	tmpline[0] = '\0';
2839 	is_oob = 0;
2840 	reply(426, "Transfer aborted. Data connection closed.");
2841 	reply(226, "Abort successful");
2842 	transflag = 0;		/* flag that the transfer has aborted */
2843 }
2844 
2845 void
2846 statxfer(void)
2847 {
2848 
2849 	if (!transflag)
2850 		return;
2851 	tmpline[0] = '\0';
2852 	is_oob = 0;
2853 	if (file_size != (off_t) -1)
2854 		reply(213,
2855 		    "Status: " LLF " of " LLF " byte%s transferred",
2856 		    (LLT)byte_count, (LLT)file_size,
2857 		    PLURAL(byte_count));
2858 	else
2859 		reply(213, "Status: " LLF " byte%s transferred",
2860 		    (LLT)byte_count, PLURAL(byte_count));
2861 }
2862 
2863 /*
2864  * Call when urgflag != 0 to handle Out Of Band commands.
2865  * Returns non zero if the OOB command aborted the transfer
2866  * by setting transflag to 0. (c.f., "ABOR").
2867  */
2868 static int
2869 handleoobcmd()
2870 {
2871 	char *cp;
2872 
2873 	if (!urgflag)
2874 		return (0);
2875 	urgflag = 0;
2876 	/* only process if transfer occurring */
2877 	if (!transflag)
2878 		return (0);
2879 	cp = tmpline;
2880 	if (getline(cp, sizeof(tmpline), stdin) == NULL) {
2881 		reply(221, "You could at least say goodbye.");
2882 		dologout(0);
2883 	}
2884 		/*
2885 		 * Manually parse OOB commands, because we can't
2886 		 * recursively call the yacc parser...
2887 		 */
2888 	if (strcasecmp(cp, "ABOR\r\n") == 0) {
2889 		abor();
2890 	} else if (strcasecmp(cp, "STAT\r\n") == 0) {
2891 		statxfer();
2892 	} else {
2893 		/* XXX: error with "500 unknown command" ? */
2894 	}
2895 	return (transflag == 0);
2896 }
2897 
2898 static int
2899 bind_pasv_addr(void)
2900 {
2901 	static int passiveport;
2902 	int port, len;
2903 
2904 	len = pasv_addr.su_len;
2905 	if (curclass.portmin == 0 && curclass.portmax == 0) {
2906 		pasv_addr.su_port = 0;
2907 		return (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len));
2908 	}
2909 
2910 	if (passiveport == 0) {
2911 		srand(getpid());
2912 		passiveport = rand() % (curclass.portmax - curclass.portmin)
2913 		    + curclass.portmin;
2914 	}
2915 
2916 	port = passiveport;
2917 	while (1) {
2918 		port++;
2919 		if (port > curclass.portmax)
2920 			port = curclass.portmin;
2921 		else if (port == passiveport) {
2922 			errno = EAGAIN;
2923 			return (-1);
2924 		}
2925 		pasv_addr.su_port = htons(port);
2926 		if (bind(pdata, (struct sockaddr *)&pasv_addr.si_su, len) == 0)
2927 			break;
2928 		if (errno != EADDRINUSE)
2929 			return (-1);
2930 	}
2931 	passiveport = port;
2932 	return (0);
2933 }
2934 
2935 /*
2936  * Note: a response of 425 is not mentioned as a possible response to
2937  *	the PASV command in RFC959. However, it has been blessed as
2938  *	a legitimate response by Jon Postel in a telephone conversation
2939  *	with Rick Adams on 25 Jan 89.
2940  */
2941 void
2942 passive(void)
2943 {
2944 	socklen_t len, recvbufsize;
2945 	char *p, *a;
2946 
2947 	if (pdata >= 0)
2948 		close(pdata);
2949 	pdata = socket(AF_INET, SOCK_STREAM, 0);
2950 	if (pdata < 0 || !logged_in) {
2951 		perror_reply(425, "Can't open passive connection");
2952 		return;
2953 	}
2954 	pasv_addr = ctrl_addr;
2955 
2956 	if (bind_pasv_addr() < 0)
2957 		goto pasv_error;
2958 	len = pasv_addr.su_len;
2959 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
2960 		goto pasv_error;
2961 	pasv_addr.su_len = len;
2962 	if (curclass.recvbufsize) {
2963 		recvbufsize = curclass.recvbufsize;
2964 		if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, &recvbufsize,
2965 			       sizeof(int)) == -1)
2966 			syslog(LOG_WARNING, "setsockopt(SO_RCVBUF, %d): %m",
2967 			       recvbufsize);
2968 	}
2969 	if (listen(pdata, 1) < 0)
2970 		goto pasv_error;
2971 	if (curclass.advertise.su_len != 0)
2972 		a = (char *) &curclass.advertise.su_addr;
2973 	else
2974 		a = (char *) &pasv_addr.su_addr;
2975 	p = (char *) &pasv_addr.su_port;
2976 
2977 #define UC(b) (((int) b) & 0xff)
2978 
2979 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2980 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2981 	return;
2982 
2983  pasv_error:
2984 	(void) close(pdata);
2985 	pdata = -1;
2986 	perror_reply(425, "Can't open passive connection");
2987 	return;
2988 }
2989 
2990 /*
2991  * convert protocol identifier to/from AF
2992  */
2993 int
2994 lpsvproto2af(int proto)
2995 {
2996 
2997 	switch (proto) {
2998 	case 4:
2999 		return AF_INET;
3000 #ifdef INET6
3001 	case 6:
3002 		return AF_INET6;
3003 #endif
3004 	default:
3005 		return -1;
3006 	}
3007 }
3008 
3009 int
3010 af2lpsvproto(int af)
3011 {
3012 
3013 	switch (af) {
3014 	case AF_INET:
3015 		return 4;
3016 #ifdef INET6
3017 	case AF_INET6:
3018 		return 6;
3019 #endif
3020 	default:
3021 		return -1;
3022 	}
3023 }
3024 
3025 int
3026 epsvproto2af(int proto)
3027 {
3028 
3029 	switch (proto) {
3030 	case 1:
3031 		return AF_INET;
3032 #ifdef INET6
3033 	case 2:
3034 		return AF_INET6;
3035 #endif
3036 	default:
3037 		return -1;
3038 	}
3039 }
3040 
3041 int
3042 af2epsvproto(int af)
3043 {
3044 
3045 	switch (af) {
3046 	case AF_INET:
3047 		return 1;
3048 #ifdef INET6
3049 	case AF_INET6:
3050 		return 2;
3051 #endif
3052 	default:
3053 		return -1;
3054 	}
3055 }
3056 
3057 /*
3058  * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
3059  * 229 Entering Extended Passive Mode (|||port|)
3060  */
3061 void
3062 long_passive(char *cmd, int pf)
3063 {
3064 	socklen_t len;
3065 	char *p, *a;
3066 
3067 	if (!logged_in) {
3068 		syslog(LOG_NOTICE, "long passive but not logged in");
3069 		reply(503, "Login with USER first.");
3070 		return;
3071 	}
3072 
3073 	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
3074 		/*
3075 		 * XXX: only EPRT/EPSV ready clients will understand this
3076 		 */
3077 		if (strcmp(cmd, "EPSV") != 0)
3078 			reply(501, "Network protocol mismatch"); /*XXX*/
3079 		else
3080 			epsv_protounsupp("Network protocol mismatch");
3081 
3082 		return;
3083 	}
3084 
3085 	if (pdata >= 0)
3086 		close(pdata);
3087 	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
3088 	if (pdata < 0) {
3089 		perror_reply(425, "Can't open passive connection");
3090 		return;
3091 	}
3092 	pasv_addr = ctrl_addr;
3093 	if (bind_pasv_addr() < 0)
3094 		goto pasv_error;
3095 	len = pasv_addr.su_len;
3096 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr.si_su, &len) < 0)
3097 		goto pasv_error;
3098 	pasv_addr.su_len = len;
3099 	if (listen(pdata, 1) < 0)
3100 		goto pasv_error;
3101 	p = (char *) &pasv_addr.su_port;
3102 
3103 #define UC(b) (((int) b) & 0xff)
3104 
3105 	if (strcmp(cmd, "LPSV") == 0) {
3106 		struct sockinet *advert;
3107 
3108 		if (curclass.advertise.su_len != 0)
3109 			advert = &curclass.advertise;
3110 		else
3111 			advert = &pasv_addr;
3112 		switch (advert->su_family) {
3113 		case AF_INET:
3114 			a = (char *) &advert->su_addr;
3115 			reply(228,
3116     "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
3117 				4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3118 				2, UC(p[0]), UC(p[1]));
3119 			return;
3120 #ifdef INET6
3121 		case AF_INET6:
3122 			a = (char *) &advert->su_6addr;
3123 			reply(228,
3124     "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
3125 				6, 16,
3126 				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
3127 				UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
3128 				UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
3129 				UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
3130 				2, UC(p[0]), UC(p[1]));
3131 			return;
3132 #endif
3133 		}
3134 #undef UC
3135 	} else if (strcmp(cmd, "EPSV") == 0) {
3136 		switch (pasv_addr.su_family) {
3137 		case AF_INET:
3138 #ifdef INET6
3139 		case AF_INET6:
3140 #endif
3141 			reply(229, "Entering Extended Passive Mode (|||%d|)",
3142 			    ntohs(pasv_addr.su_port));
3143 			return;
3144 		}
3145 	} else {
3146 		/* more proper error code? */
3147 	}
3148 
3149  pasv_error:
3150 	(void) close(pdata);
3151 	pdata = -1;
3152 	perror_reply(425, "Can't open passive connection");
3153 	return;
3154 }
3155 
3156 int
3157 extended_port(const char *arg)
3158 {
3159 	char *tmp = NULL;
3160 	char *result[3];
3161 	char *p, *q;
3162 	char delim;
3163 	struct addrinfo hints;
3164 	struct addrinfo *res = NULL;
3165 	int i;
3166 	unsigned long proto;
3167 
3168 	tmp = ftpd_strdup(arg);
3169 	p = tmp;
3170 	delim = p[0];
3171 	p++;
3172 	memset(result, 0, sizeof(result));
3173 	for (i = 0; i < 3; i++) {
3174 		q = strchr(p, delim);
3175 		if (!q || *q != delim)
3176 			goto parsefail;
3177 		*q++ = '\0';
3178 		result[i] = p;
3179 		p = q;
3180 	}
3181 
3182 			/* some more sanity checks */
3183 	errno = 0;
3184 	p = NULL;
3185 	(void)strtoul(result[2], &p, 10);
3186 	if (errno || !*result[2] || *p)
3187 		goto parsefail;
3188 	errno = 0;
3189 	p = NULL;
3190 	proto = strtoul(result[0], &p, 10);
3191 	if (errno || !*result[0] || *p)
3192 		goto protounsupp;
3193 
3194 	memset(&hints, 0, sizeof(hints));
3195 	hints.ai_family = epsvproto2af((int)proto);
3196 	if (hints.ai_family < 0)
3197 		goto protounsupp;
3198 	hints.ai_socktype = SOCK_STREAM;
3199 	hints.ai_flags = AI_NUMERICHOST;
3200 	if (getaddrinfo(result[1], result[2], &hints, &res))
3201 		goto parsefail;
3202 	if (res->ai_next)
3203 		goto parsefail;
3204 	if (sizeof(data_dest) < res->ai_addrlen)
3205 		goto parsefail;
3206 	memcpy(&data_dest.si_su, res->ai_addr, res->ai_addrlen);
3207 	data_dest.su_len = res->ai_addrlen;
3208 #ifdef INET6
3209 	if (his_addr.su_family == AF_INET6 &&
3210 	    data_dest.su_family == AF_INET6) {
3211 			/* XXX: more sanity checks! */
3212 		data_dest.su_scope_id = his_addr.su_scope_id;
3213 	}
3214 #endif
3215 
3216 	if (tmp != NULL)
3217 		free(tmp);
3218 	if (res)
3219 		freeaddrinfo(res);
3220 	return 0;
3221 
3222  parsefail:
3223 	reply(500, "Invalid argument, rejected.");
3224 	usedefault = 1;
3225 	if (tmp != NULL)
3226 		free(tmp);
3227 	if (res)
3228 		freeaddrinfo(res);
3229 	return -1;
3230 
3231  protounsupp:
3232 	epsv_protounsupp("Protocol not supported");
3233 	usedefault = 1;
3234 	if (tmp != NULL)
3235 		free(tmp);
3236 	return -1;
3237 }
3238 
3239 /*
3240  * 522 Protocol not supported (proto,...)
3241  * as we assume address family for control and data connections are the same,
3242  * we do not return the list of address families we support - instead, we
3243  * return the address family of the control connection.
3244  */
3245 void
3246 epsv_protounsupp(const char *message)
3247 {
3248 	int proto;
3249 
3250 	proto = af2epsvproto(ctrl_addr.su_family);
3251 	if (proto < 0)
3252 		reply(501, "%s", message);	/* XXX */
3253 	else
3254 		reply(522, "%s, use (%d)", message, proto);
3255 }
3256 
3257 /*
3258  * Generate unique name for file with basename "local".
3259  * The file named "local" is already known to exist.
3260  * Generates failure reply on error.
3261  *
3262  * XXX:	this function should under go changes similar to
3263  *	the mktemp(3)/mkstemp(3) changes.
3264  */
3265 static char *
3266 gunique(const char *local)
3267 {
3268 	static char new[MAXPATHLEN];
3269 	struct stat st;
3270 	char *cp;
3271 	int count;
3272 
3273 	cp = strrchr(local, '/');
3274 	if (cp)
3275 		*cp = '\0';
3276 	if (stat(cp ? local : ".", &st) < 0) {
3277 		perror_reply(553, cp ? local : ".");
3278 		return (NULL);
3279 	}
3280 	if (cp)
3281 		*cp = '/';
3282 	for (count = 1; count < 100; count++) {
3283 		(void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
3284 		if (stat(new, &st) < 0)
3285 			return (new);
3286 	}
3287 	reply(452, "Unique file name cannot be created.");
3288 	return (NULL);
3289 }
3290 
3291 /*
3292  * Format and send reply containing system error number.
3293  */
3294 void
3295 perror_reply(int code, const char *string)
3296 {
3297 	int save_errno;
3298 
3299 	save_errno = errno;
3300 	reply(code, "%s: %s.", string, strerror(errno));
3301 	errno = save_errno;
3302 }
3303 
3304 static char *onefile[] = {
3305 	"",
3306 	0
3307 };
3308 
3309 void
3310 send_file_list(const char *whichf)
3311 {
3312 	struct stat st;
3313 	DIR *dirp;
3314 	struct dirent *dir;
3315 	FILE *volatile dout;
3316 	char **volatile dirlist;
3317 	char *dirname, *p;
3318 	char *notglob;
3319 	int volatile simple;
3320 	int volatile freeglob;
3321 	glob_t gl;
3322 
3323 	dirp = NULL;
3324 	dout = NULL;
3325 	notglob = NULL;
3326 	simple = 0;
3327 	freeglob = 0;
3328 	urgflag = 0;
3329 
3330 	p = NULL;
3331 	if (strpbrk(whichf, "~{[*?") != NULL) {
3332 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE|GLOB_LIMIT;
3333 
3334 		memset(&gl, 0, sizeof(gl));
3335 		freeglob = 1;
3336 		if (glob(whichf, flags, 0, &gl)) {
3337 			reply(450, "Not found");
3338 			goto cleanup_send_file_list;
3339 		} else if (gl.gl_pathc == 0) {
3340 			errno = ENOENT;
3341 			perror_reply(450, whichf);
3342 			goto cleanup_send_file_list;
3343 		}
3344 		dirlist = gl.gl_pathv;
3345 	} else {
3346 		notglob = ftpd_strdup(whichf);
3347 		onefile[0] = notglob;
3348 		dirlist = onefile;
3349 		simple = 1;
3350 	}
3351 					/* XXX: } for vi sm */
3352 
3353 	while ((dirname = *dirlist++) != NULL) {
3354 		int trailingslash = 0;
3355 
3356 		if (stat(dirname, &st) < 0) {
3357 			/*
3358 			 * If user typed "ls -l", etc, and the client
3359 			 * used NLST, do what the user meant.
3360 			 */
3361 			/* XXX: nuke this support? */
3362 			if (dirname[0] == '-' && *dirlist == NULL &&
3363 			    transflag == 0) {
3364 				char *argv[] = { INTERNAL_LS, "", NULL };
3365 
3366 				argv[1] = dirname;
3367 				retrieve(argv, dirname);
3368 				goto cleanup_send_file_list;
3369 			}
3370 			perror_reply(450, whichf);
3371 			goto cleanup_send_file_list;
3372 		}
3373 
3374 		if (S_ISREG(st.st_mode)) {
3375 			/*
3376 			 * XXXRFC:
3377 			 *	should we follow RFC959 and not work
3378 			 *	for non directories?
3379 			 */
3380 			if (dout == NULL) {
3381 				dout = dataconn("file list", (off_t)-1, "w");
3382 				if (dout == NULL)
3383 					goto cleanup_send_file_list;
3384 				transflag = 1;
3385 			}
3386 			cprintf(dout, "%s%s\n", dirname,
3387 			    type == TYPE_A ? "\r" : "");
3388 			continue;
3389 		} else if (!S_ISDIR(st.st_mode))
3390 			continue;
3391 
3392 		if (dirname[strlen(dirname) - 1] == '/')
3393 			trailingslash++;
3394 
3395 		if ((dirp = opendir(dirname)) == NULL)
3396 			continue;
3397 
3398 		while ((dir = readdir(dirp)) != NULL) {
3399 			char nbuf[MAXPATHLEN];
3400 
3401 			if (urgflag && handleoobcmd())
3402 				goto cleanup_send_file_list;
3403 
3404 			if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name))
3405 				continue;
3406 
3407 			(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
3408 			    trailingslash ? "" : "/", dir->d_name);
3409 
3410 			/*
3411 			 * We have to do a stat to ensure it's
3412 			 * not a directory or special file.
3413 			 */
3414 			/*
3415 			 * XXXRFC:
3416 			 *	should we follow RFC959 and filter out
3417 			 *	non files ?   lukem - NO!, or not until
3418 			 *	our ftp client uses MLS{T,D} for completion.
3419 			 */
3420 			if (simple || (stat(nbuf, &st) == 0 &&
3421 			    S_ISREG(st.st_mode))) {
3422 				if (dout == NULL) {
3423 					dout = dataconn("file list", (off_t)-1,
3424 						"w");
3425 					if (dout == NULL)
3426 						goto cleanup_send_file_list;
3427 					transflag = 1;
3428 				}
3429 				p = nbuf;
3430 				if (nbuf[0] == '.' && nbuf[1] == '/')
3431 					p = &nbuf[2];
3432 				cprintf(dout, "%s%s\n", p,
3433 				    type == TYPE_A ? "\r" : "");
3434 			}
3435 		}
3436 		(void) closedir(dirp);
3437 	}
3438 
3439 	if (dout == NULL)
3440 		reply(450, "No files found.");
3441 	else if (ferror(dout) != 0)
3442 		perror_reply(451, "Data connection");
3443 	else
3444 		reply(226, "Transfer complete.");
3445 
3446  cleanup_send_file_list:
3447 	closedataconn(dout);
3448 	transflag = 0;
3449 	urgflag = 0;
3450 	total_xfers++;
3451 	total_xfers_out++;
3452 	if (notglob)
3453 		free(notglob);
3454 	if (freeglob)
3455 		globfree(&gl);
3456 }
3457 
3458 char *
3459 conffilename(const char *s)
3460 {
3461 	static char filename[MAXPATHLEN];
3462 
3463 	if (*s == '/')
3464 		strlcpy(filename, s, sizeof(filename));
3465 	else
3466 		(void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
3467 	return (filename);
3468 }
3469 
3470 /*
3471  * logxfer --
3472  *	if logging > 1, then based on the arguments, syslog a message:
3473  *	 if bytes != -1		"<command> <file1> = <bytes> bytes"
3474  *	 else if file2 != NULL	"<command> <file1> <file2>"
3475  *	 else			"<command> <file1>"
3476  *	if elapsed != NULL, append "in xxx.yyy seconds"
3477  *	if error != NULL, append ": " + error
3478  *
3479  *	if doxferlog != 0, bytes != -1, and command is "get", "put",
3480  *	or "append", syslog and/or write a wu-ftpd style xferlog entry
3481  */
3482 void
3483 logxfer(const char *command, off_t bytes, const char *file1, const char *file2,
3484     const struct timeval *elapsed, const char *error)
3485 {
3486 	char		 buf[MAXPATHLEN * 2 + 100];
3487 	char		 realfile1[MAXPATHLEN], realfile2[MAXPATHLEN];
3488 	const char	*r1, *r2;
3489 	char		 direction;
3490 	size_t		 len;
3491 	time_t		 now;
3492 
3493 	if (logging <=1 && !doxferlog)
3494 		return;
3495 
3496 	r1 = r2 = NULL;
3497 	if ((r1 = realpath(file1, realfile1)) == NULL)
3498 		r1 = file1;
3499 	if (file2 != NULL)
3500 		if ((r2 = realpath(file2, realfile2)) == NULL)
3501 			r2 = file2;
3502 
3503 		/*
3504 		 * syslog command
3505 		 */
3506 	if (logging > 1) {
3507 		len = snprintf(buf, sizeof(buf), "%s %s", command, r1);
3508 		if (bytes != (off_t)-1)
3509 			len += snprintf(buf + len, sizeof(buf) - len,
3510 			    " = " LLF " byte%s", (LLT) bytes, PLURAL(bytes));
3511 		else if (r2 != NULL)
3512 			len += snprintf(buf + len, sizeof(buf) - len,
3513 			    " %s", r2);
3514 		if (elapsed != NULL)
3515 			len += snprintf(buf + len, sizeof(buf) - len,
3516 			    " in %ld.%.03d seconds", elapsed->tv_sec,
3517 			    (int)(elapsed->tv_usec / 1000));
3518 		if (error != NULL)
3519 			len += snprintf(buf + len, sizeof(buf) - len,
3520 			    ": %s", error);
3521 		syslog(LOG_INFO, "%s", buf);
3522 	}
3523 
3524 		/*
3525 		 * syslog wu-ftpd style log entry, prefixed with "xferlog: "
3526 		 */
3527 	if (!doxferlog || bytes == -1)
3528 		return;
3529 
3530 	if (strcmp(command, "get") == 0)
3531 		direction = 'o';
3532 	else if (strcmp(command, "put") == 0 || strcmp(command, "append") == 0)
3533 		direction = 'i';
3534 	else
3535 		return;
3536 
3537 	time(&now);
3538 	len = snprintf(buf, sizeof(buf),
3539 	    "%.24s %ld %s " LLF " %s %c %s %c %c %s FTP 0 * %c\n",
3540 
3541 /*
3542  * XXX: wu-ftpd puts ' (send)' or ' (recv)' in the syslog message, and removes
3543  *	the full date.  This may be problematic for accurate log parsing,
3544  *	given that syslog messages don't contain the full date.
3545  */
3546 	    ctime(&now),
3547 	    elapsed == NULL ? 0 : elapsed->tv_sec + (elapsed->tv_usec > 0),
3548 	    remotehost,
3549 	    (LLT) bytes,
3550 	    r1,
3551 	    type == TYPE_A ? 'a' : 'b',
3552 	    "_",		/* XXX: take conversions into account? */
3553 	    direction,
3554 
3555 	    curclass.type == CLASS_GUEST ?  'a' :
3556 	    curclass.type == CLASS_CHROOT ? 'g' :
3557 	    curclass.type == CLASS_REAL ?   'r' : '?',
3558 
3559 	    curclass.type == CLASS_GUEST ? pw->pw_passwd : pw->pw_name,
3560 	    error != NULL ? 'i' : 'c'
3561 	    );
3562 
3563 	if ((doxferlog & 2) && xferlogfd != -1)
3564 		write(xferlogfd, buf, len);
3565 	if ((doxferlog & 1)) {
3566 		buf[len-1] = '\n';	/* strip \n from syslog message */
3567 		syslog(LOG_INFO, "xferlog: %s", buf);
3568 	}
3569 }
3570 
3571 /*
3572  * Log the resource usage.
3573  *
3574  * XXX: more resource usage to logging?
3575  */
3576 void
3577 logrusage(const struct rusage *rusage_before,
3578     const struct rusage *rusage_after)
3579 {
3580 	struct timeval usrtime, systime;
3581 
3582 	if (logging <= 1)
3583 		return;
3584 
3585 	timersub(&rusage_after->ru_utime, &rusage_before->ru_utime, &usrtime);
3586 	timersub(&rusage_after->ru_stime, &rusage_before->ru_stime, &systime);
3587 	syslog(LOG_INFO, "%ld.%.03du %ld.%.03ds %ld+%ldio %ldpf+%ldw",
3588 	    usrtime.tv_sec, (int)(usrtime.tv_usec / 1000),
3589 	    systime.tv_sec, (int)(systime.tv_usec / 1000),
3590 	    rusage_after->ru_inblock - rusage_before->ru_inblock,
3591 	    rusage_after->ru_oublock - rusage_before->ru_oublock,
3592 	    rusage_after->ru_majflt - rusage_before->ru_majflt,
3593 	    rusage_after->ru_nswap - rusage_before->ru_nswap);
3594 }
3595 
3596 /*
3597  * Determine if `password' is valid for user given in `pw'.
3598  * Returns 2 if password expired, 1 if otherwise failed, 0 if ok
3599  */
3600 int
3601 checkpassword(const struct passwd *pwent, const char *password)
3602 {
3603 	char	*orig, *new;
3604 	time_t	 change, expire, now;
3605 
3606 	change = expire = 0;
3607 	if (pwent == NULL)
3608 		return 1;
3609 
3610 	time(&now);
3611 	orig = pwent->pw_passwd;	/* save existing password */
3612 	expire = pwent->pw_expire;
3613 	change = (pwent->pw_change == _PASSWORD_CHGNOW)? now : pwent->pw_change;
3614 
3615 	if (orig[0] == '\0')		/* don't allow empty passwords */
3616 		return 1;
3617 
3618 	new = crypt(password, orig);	/* encrypt given password */
3619 	if (strcmp(new, orig) != 0)	/* compare */
3620 		return 1;
3621 
3622 	if ((expire && now >= expire) || (change && now >= change))
3623 		return 2;		/* check if expired */
3624 
3625 	return 0;			/* OK! */
3626 }
3627 
3628 char *
3629 ftpd_strdup(const char *s)
3630 {
3631 	char *new = strdup(s);
3632 
3633 	if (new == NULL)
3634 		fatal("Local resource failure: malloc");
3635 		/* NOTREACHED */
3636 	return (new);
3637 }
3638 
3639 /*
3640  * As per fprintf(), but increment total_bytes and total_bytes_out,
3641  * by the appropriate amount.
3642  */
3643 void
3644 cprintf(FILE *fd, const char *fmt, ...)
3645 {
3646 	off_t b;
3647 	va_list ap;
3648 
3649 	va_start(ap, fmt);
3650 	b = vfprintf(fd, fmt, ap);
3651 	va_end(ap);
3652 	total_bytes += b;
3653 	total_bytes_out += b;
3654 }
3655 
3656 #ifdef USE_PAM
3657 /*
3658  * the following code is stolen from imap-uw PAM authentication module and
3659  * login.c
3660  */
3661 #define COPY_STRING(s) (s ? strdup(s) : NULL)
3662 
3663 typedef struct {
3664 	const char *uname;		/* user name */
3665 	const char *pass;		/* password */
3666 } ftpd_cred_t;
3667 
3668 static int
3669 auth_conv(int num_msg, const struct pam_message **msg,
3670     struct pam_response **resp, void *appdata)
3671 {
3672 	int i;
3673 	ftpd_cred_t *cred = (ftpd_cred_t *) appdata;
3674 	struct pam_response *myreply;
3675 
3676 	myreply = calloc(num_msg, sizeof *myreply);
3677 	if (myreply == NULL)
3678 		return PAM_BUF_ERR;
3679 
3680 	for (i = 0; i < num_msg; i++) {
3681 		switch (msg[i]->msg_style) {
3682 		case PAM_PROMPT_ECHO_ON:	/* assume want user name */
3683 			myreply[i].resp_retcode = PAM_SUCCESS;
3684 			myreply[i].resp = COPY_STRING(cred->uname);
3685 			/* PAM frees resp. */
3686 			break;
3687 		case PAM_PROMPT_ECHO_OFF:	/* assume want password */
3688 			myreply[i].resp_retcode = PAM_SUCCESS;
3689 			myreply[i].resp = COPY_STRING(cred->pass);
3690 			/* PAM frees resp. */
3691 			break;
3692 		case PAM_TEXT_INFO:
3693 		case PAM_ERROR_MSG:
3694 			myreply[i].resp_retcode = PAM_SUCCESS;
3695 			myreply[i].resp = NULL;
3696 			break;
3697 		default:			/* unknown message style */
3698 			free(myreply);
3699 			return PAM_CONV_ERR;
3700 		}
3701 	}
3702 
3703 	*resp = myreply;
3704 	return PAM_SUCCESS;
3705 }
3706 
3707 /*
3708  * Attempt to authenticate the user using PAM.  Returns 0 if the user is
3709  * authenticated, or 1 if not authenticated.  If some sort of PAM system
3710  * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
3711  * function returns -1.  This can be used as an indication that we should
3712  * fall back to a different authentication mechanism.
3713  */
3714 static int
3715 auth_pam(struct passwd **ppw, const char *pwstr)
3716 {
3717 	const char *tmpl_user;
3718 	const void *item;
3719 	int rval;
3720 	int e;
3721 	ftpd_cred_t auth_cred = { (*ppw)->pw_name, pwstr };
3722 	struct pam_conv conv = { &auth_conv, &auth_cred };
3723 
3724 	e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh);
3725 	if (e != PAM_SUCCESS) {
3726 		/*
3727 		 * In OpenPAM, it's OK to pass NULL to pam_strerror()
3728 		 * if context creation has failed in the first place.
3729 		 */
3730 		syslog(LOG_ERR, "pam_start: %s", pam_strerror(NULL, e));
3731 		return -1;
3732 	}
3733 
3734 	e = pam_set_item(pamh, PAM_RHOST, remotehost);
3735 	if (e != PAM_SUCCESS) {
3736 		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
3737 			pam_strerror(pamh, e));
3738 		if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3739 			syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3740 		}
3741 		pamh = NULL;
3742 		return -1;
3743 	}
3744 
3745 	e = pam_set_item(pamh, PAM_SOCKADDR, &his_addr);
3746 	if (e != PAM_SUCCESS) {
3747 		syslog(LOG_ERR, "pam_set_item(PAM_SOCKADDR): %s",
3748 			pam_strerror(pamh, e));
3749 		if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3750 			syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3751 		}
3752 		pamh = NULL;
3753 		return -1;
3754 	}
3755 
3756 	e = pam_authenticate(pamh, 0);
3757 	switch (e) {
3758 	case PAM_SUCCESS:
3759 		/*
3760 		 * With PAM we support the concept of a "template"
3761 		 * user.  The user enters a login name which is
3762 		 * authenticated by PAM, usually via a remote service
3763 		 * such as RADIUS or TACACS+.  If authentication
3764 		 * succeeds, a different but related "template" name
3765 		 * is used for setting the credentials, shell, and
3766 		 * home directory.  The name the user enters need only
3767 		 * exist on the remote authentication server, but the
3768 		 * template name must be present in the local password
3769 		 * database.
3770 		 *
3771 		 * This is supported by two various mechanisms in the
3772 		 * individual modules.  However, from the application's
3773 		 * point of view, the template user is always passed
3774 		 * back as a changed value of the PAM_USER item.
3775 		 */
3776 		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
3777 		    PAM_SUCCESS) {
3778 			tmpl_user = (const char *) item;
3779 			if (strcmp((*ppw)->pw_name, tmpl_user) != 0)
3780 				*ppw = sgetpwnam(tmpl_user);
3781 		} else
3782 			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
3783 			    pam_strerror(pamh, e));
3784 		rval = 0;
3785 		break;
3786 
3787 	case PAM_AUTH_ERR:
3788 	case PAM_USER_UNKNOWN:
3789 	case PAM_MAXTRIES:
3790 		rval = 1;
3791 		break;
3792 
3793 	default:
3794 		syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
3795 		rval = -1;
3796 		break;
3797 	}
3798 
3799 	if (rval == 0) {
3800 		e = pam_acct_mgmt(pamh, 0);
3801 		if (e != PAM_SUCCESS) {
3802 			syslog(LOG_ERR, "pam_acct_mgmt: %s",
3803 						pam_strerror(pamh, e));
3804 			rval = 1;
3805 		}
3806 	}
3807 
3808 	if (rval != 0) {
3809 		if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
3810 			syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
3811 		}
3812 		pamh = NULL;
3813 	}
3814 	return rval;
3815 }
3816 
3817 #endif /* USE_PAM */
3818