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