Home | History | Annotate | Line # | Download | only in ftpd
ftpd.c revision 1.70
      1 /*	$NetBSD: ftpd.c,v 1.70 1999/09/30 18:12:34 tron Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1997 and 1998 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * 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. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed by the University of
     47  *	California, Berkeley and its contributors.
     48  * 4. Neither the name of the University nor the names of its contributors
     49  *    may be used to endorse or promote products derived from this software
     50  *    without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  * SUCH DAMAGE.
     63  */
     64 
     65 /*
     66  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
     67  * All rights reserved.
     68  *
     69  * This code is derived from software contributed to The NetBSD Foundation
     70  * by Luke Mewburn.
     71  *
     72  * Redistribution and use in source and binary forms, with or without
     73  * modification, are permitted provided that the following conditions
     74  * are met:
     75  * 1. Redistributions of source code must retain the above copyright
     76  *    notice, this list of conditions and the following disclaimer.
     77  * 2. Redistributions in binary form must reproduce the above copyright
     78  *    notice, this list of conditions and the following disclaimer in the
     79  *    documentation and/or other materials provided with the distribution.
     80  * 3. All advertising materials mentioning features or use of this software
     81  *    must display the following acknowledgement:
     82  *        This product includes software developed by the NetBSD
     83  *        Foundation, Inc. and its contributors.
     84  * 4. Neither the name of The NetBSD Foundation nor the names of its
     85  *    contributors may be used to endorse or promote products derived
     86  *    from this software without specific prior written permission.
     87  *
     88  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     89  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     90  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     91  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     92  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     93  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     94  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     95  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     96  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     97  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     98  * POSSIBILITY OF SUCH DAMAGE.
     99  */
    100 
    101 #include <sys/cdefs.h>
    102 #ifndef lint
    103 __COPYRIGHT(
    104 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
    105 	The Regents of the University of California.  All rights reserved.\n");
    106 #endif /* not lint */
    107 
    108 #ifndef lint
    109 #if 0
    110 static char sccsid[] = "@(#)ftpd.c	8.5 (Berkeley) 4/28/95";
    111 #else
    112 __RCSID("$NetBSD: ftpd.c,v 1.70 1999/09/30 18:12:34 tron Exp $");
    113 #endif
    114 #endif /* not lint */
    115 
    116 /*
    117  * FTP server.
    118  */
    119 #include <sys/param.h>
    120 #include <sys/stat.h>
    121 #include <sys/ioctl.h>
    122 #include <sys/socket.h>
    123 #include <sys/wait.h>
    124 
    125 #include <netinet/in.h>
    126 #include <netinet/in_systm.h>
    127 #include <netinet/ip.h>
    128 
    129 #define	FTP_NAMES
    130 #include <arpa/ftp.h>
    131 #include <arpa/inet.h>
    132 #include <arpa/telnet.h>
    133 
    134 #include <ctype.h>
    135 #include <dirent.h>
    136 #include <err.h>
    137 #include <errno.h>
    138 #include <fcntl.h>
    139 #include <fnmatch.h>
    140 #include <glob.h>
    141 #include <limits.h>
    142 #include <netdb.h>
    143 #include <pwd.h>
    144 #include <setjmp.h>
    145 #include <signal.h>
    146 #include <stdio.h>
    147 #include <stdlib.h>
    148 #include <string.h>
    149 #include <syslog.h>
    150 #include <time.h>
    151 #include <unistd.h>
    152 #ifdef SKEY
    153 #include <skey.h>
    154 #endif
    155 #ifdef KERBEROS5
    156 #include <kerberosIV/com_err.h>
    157 #include <krb5/krb5.h>
    158 #endif
    159 
    160 #include "extern.h"
    161 #include "pathnames.h"
    162 
    163 #if __STDC__
    164 #include <stdarg.h>
    165 #else
    166 #include <varargs.h>
    167 #endif
    168 
    169 #ifndef TRUE
    170 #define TRUE	1
    171 #define FALSE	0
    172 #endif
    173 
    174 const char version[] = "Version: 7.2.0";
    175 
    176 union sockunion  ctrl_addr;
    177 union sockunion  data_source;
    178 union sockunion  data_dest;
    179 union sockunion  his_addr;
    180 union sockunion  pasv_addr;
    181 
    182 int	data;
    183 jmp_buf	errcatch, urgcatch;
    184 int	logged_in;
    185 struct	passwd *pw;
    186 int	debug;
    187 int	sflag;
    188 int	logging;
    189 int	guest;
    190 int	dochroot;
    191 int	type;
    192 int	form;
    193 int	stru;			/* avoid C keyword */
    194 int	mode;
    195 int	usedefault = 1;		/* for data transfers */
    196 int	pdata = -1;		/* for passive mode */
    197 int	family = AF_INET;
    198 sig_atomic_t transflag;
    199 off_t	file_size;
    200 off_t	byte_count;
    201 char	tmpline[7];
    202 char	hostname[MAXHOSTNAMELEN+1];
    203 char	remotehost[MAXHOSTNAMELEN+1];
    204 static char ttyline[20];
    205 char	*tty = ttyline;		/* for klogin */
    206 
    207 off_t	total_data_in;		/* total file data bytes received */
    208 off_t	total_data_out;		/* total file data bytes sent data */
    209 off_t	total_data;		/* total file data bytes transferred data */
    210 off_t	total_files_in;		/* total number of data files received */
    211 off_t	total_files_out;	/* total number of data files sent */
    212 off_t	total_files;		/* total number of data files transferred */
    213 off_t	total_bytes_in;		/* total bytes received */
    214 off_t	total_bytes_out;	/* total bytes sent */
    215 off_t	total_bytes;		/* total bytes transferred */
    216 off_t	total_xfers_in;		/* total number of xfers incoming */
    217 off_t	total_xfers_out;	/* total number of xfers outgoing */
    218 off_t	total_xfers;		/* total number of xfers */
    219 
    220 static char *anondir = NULL;
    221 static char confdir[MAXPATHLEN];
    222 
    223 #if defined(KERBEROS) || defined(KERBEROS5)
    224 int	notickets = 1;
    225 char	*krbtkfile_env = NULL;
    226 #endif
    227 
    228 int epsvall = 0;
    229 
    230 /*
    231  * Timeout intervals for retrying connections
    232  * to hosts that don't accept PORT cmds.  This
    233  * is a kludge, but given the problems with TCP...
    234  */
    235 #define	SWAITMAX	90	/* wait at most 90 seconds */
    236 #define	SWAITINT	5	/* interval between retries */
    237 
    238 int	swaitmax = SWAITMAX;
    239 int	swaitint = SWAITINT;
    240 
    241 #ifdef HASSETPROCTITLE
    242 char	proctitle[BUFSIZ];	/* initial part of title */
    243 #endif /* HASSETPROCTITLE */
    244 
    245 static void	 ack __P((const char *));
    246 static void	 myoob __P((int));
    247 static int	 checkuser __P((const char *, const char *, int, int));
    248 static int	 checkaccess __P((const char *));
    249 static FILE	*dataconn __P((const char *, off_t, const char *));
    250 static void	 dolog __P((struct sockaddr *));
    251 static void	 end_login __P((void));
    252 static FILE	*getdatasock __P((const char *));
    253 static char	*gunique __P((const char *));
    254 static void	 lostconn __P((int));
    255 static int	 receive_data __P((FILE *, FILE *));
    256 static void	 replydirname __P((const char *, const char *));
    257 static int	 send_data __P((FILE *, FILE *, off_t, int));
    258 static struct passwd *
    259 		 sgetpwnam __P((const char *));
    260 
    261 int	main __P((int, char *[]));
    262 
    263 #if defined(KERBEROS) || defined(KERBEROS5)
    264 int	klogin __P((struct passwd *, char *, char *, char *));
    265 void	kdestroy __P((void));
    266 #endif
    267 
    268 int
    269 main(argc, argv)
    270 	int argc;
    271 	char *argv[];
    272 {
    273 	int addrlen, ch, on = 1, tos, keepalive;
    274 	char *cp, line[LINE_MAX];
    275 	FILE *fd;
    276 #ifdef KERBEROS5
    277 	krb5_error_code kerror;
    278 #endif
    279 
    280 	debug = 0;
    281 	logging = 0;
    282 	sflag = 0;
    283 	(void)strcpy(confdir, _DEFAULT_CONFDIR);
    284 
    285 	while ((ch = getopt(argc, argv, "a:c:C:dlst:T:u:v46")) != -1) {
    286 		switch (ch) {
    287 		case 'a':
    288 			anondir = optarg;
    289 			break;
    290 
    291 		case 'c':
    292 			(void)strncpy(confdir, optarg, sizeof(confdir));
    293 			confdir[sizeof(confdir)-1] = '\0';
    294 			break;
    295 
    296 		case 'C':
    297 			exit(checkaccess(optarg));
    298 			/* NOTREACHED */
    299 
    300 		case 'd':
    301 		case 'v':		/* deprecated */
    302 			debug = 1;
    303 			break;
    304 
    305 		case 'l':
    306 			logging++;	/* > 1 == extra logging */
    307 			break;
    308 
    309 		case 's':
    310 			sflag = 1;
    311 			break;
    312 
    313 		case 't':
    314 		case 'T':
    315 		case 'u':
    316 			warnx("-%c has been deprecated in favour of ftpd.conf",
    317 			    ch);
    318 			break;
    319 
    320 		case '4':
    321 			family = AF_INET;
    322 			break;
    323 
    324 		case '6':
    325 			family = AF_INET6;
    326 			break;
    327 
    328 		default:
    329 			if (optopt == 'a' || optopt == 'C')
    330 				exit(1);
    331 			warnx("unknown flag -%c ignored", optopt);
    332 			break;
    333 		}
    334 	}
    335 
    336 	/*
    337 	 * LOG_NDELAY sets up the logging connection immediately,
    338 	 * necessary for anonymous ftp's that chroot and can't do it later.
    339 	 */
    340 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
    341 	addrlen = sizeof(his_addr); /* xxx */
    342 	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
    343 		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
    344 		exit(1);
    345 	}
    346 	addrlen = sizeof(ctrl_addr);
    347 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
    348 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
    349 		exit(1);
    350 	}
    351 	if (his_addr.su_family == AF_INET6
    352 	 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
    353 #if 1
    354 		/*
    355 		 * IPv4 control connection arrived to AF_INET6 socket.
    356 		 * I hate to do this, but this is the easiest solution.
    357 		 */
    358 		union sockunion tmp_addr;
    359 
    360 		tmp_addr = his_addr;
    361 		memset(&his_addr, 0, sizeof(his_addr));
    362 		his_addr.su_sin.sin_family = AF_INET;
    363 		his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
    364 		memcpy(&his_addr.su_sin.sin_addr,
    365 			&tmp_addr.su_sin6.sin6_addr.s6_addr32[3],
    366 			sizeof(his_addr.su_sin.sin_addr));
    367 		his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
    368 
    369 		tmp_addr = ctrl_addr;
    370 		memset(&ctrl_addr, 0, sizeof(ctrl_addr));
    371 		ctrl_addr.su_sin.sin_family = AF_INET;
    372 		ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
    373 		memcpy(&ctrl_addr.su_sin.sin_addr,
    374 			&tmp_addr.su_sin6.sin6_addr.s6_addr32[3],
    375 			sizeof(ctrl_addr.su_sin.sin_addr));
    376 		ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
    377 #else
    378 		while (fgets(line, sizeof(line), fd) != NULL) {
    379 			if ((cp = strchr(line, '\n')) != NULL)
    380 				*cp = '\0';
    381 			lreply(530, "%s", line);
    382 		}
    383 		(void) fflush(stdout);
    384 		(void) fclose(fd);
    385 		reply(530,
    386 			"Connection from IPv4 mapped address is not supported.");
    387 		exit(0);
    388 #endif
    389 	}
    390 #ifdef IP_TOS
    391 	if (family == AF_INET) {
    392 		tos = IPTOS_LOWDELAY;
    393 		if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
    394 			       sizeof(int)) < 0)
    395 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
    396 	}
    397 #endif
    398 	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
    399 
    400 	/* set this here so klogin can use it... */
    401 	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
    402 
    403 	(void) freopen(_PATH_DEVNULL, "w", stderr);
    404 	(void) signal(SIGPIPE, lostconn);
    405 	(void) signal(SIGCHLD, SIG_IGN);
    406 	if ((long)signal(SIGURG, myoob) < 0)
    407 		syslog(LOG_ERR, "signal: %m");
    408 
    409 	/* Try to handle urgent data inline */
    410 #ifdef SO_OOBINLINE
    411 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
    412 		syslog(LOG_ERR, "setsockopt: %m");
    413 #endif
    414 	/* Set keepalives on the socket to detect dropped connections.  */
    415 #ifdef SO_KEEPALIVE
    416 	keepalive = 1;
    417 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
    418 	    sizeof(int)) < 0)
    419 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
    420 #endif
    421 
    422 #ifdef	F_SETOWN
    423 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
    424 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
    425 #endif
    426 	dolog((struct sockaddr *)&his_addr);
    427 	/*
    428 	 * Set up default state
    429 	 */
    430 	data = -1;
    431 	type = TYPE_A;
    432 	form = FORM_N;
    433 	stru = STRU_F;
    434 	mode = MODE_S;
    435 	tmpline[0] = '\0';
    436 	hasyyerrored = 0;
    437 
    438 #ifdef KERBEROS5
    439 	kerror = krb5_init_context(&kcontext);
    440 	if (kerror) {
    441 		syslog(LOG_NOTICE, "%s when initializing Kerberos context",
    442 		    error_message(kerror));
    443 		exit(0);
    444 	}
    445 #endif /* KERBEROS5 */
    446 
    447 	/* If logins are disabled, print out the message. */
    448 	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
    449 		lreply(530, "");
    450 		while (fgets(line, sizeof(line), fd) != NULL) {
    451 			if ((cp = strchr(line, '\n')) != NULL)
    452 				*cp = '\0';
    453 			lreply(0, "%s", line);
    454 		}
    455 		(void) fflush(stdout);
    456 		(void) fclose(fd);
    457 		reply(530, "System not available.");
    458 		exit(0);
    459 	}
    460 	if ((fd = fopen(conffilename(_PATH_FTPWELCOME), "r")) != NULL) {
    461 		lreply(220, "");
    462 		while (fgets(line, sizeof(line), fd) != NULL) {
    463 			if ((cp = strchr(line, '\n')) != NULL)
    464 				*cp = '\0';
    465 			lreply(0, "%s", line);
    466 		}
    467 		(void) fflush(stdout);
    468 		(void) fclose(fd);
    469 		/* reply(220,) must follow */
    470 	}
    471 	(void)gethostname(hostname, sizeof(hostname));
    472 	hostname[sizeof(hostname) - 1] = '\0';
    473 	reply(220, "%s FTP server (%s) ready.", hostname, version);
    474 	curclass.timeout = 300;		/* 5 minutes, as per login(1) */
    475 	(void) setjmp(errcatch);
    476 	for (;;)
    477 		(void) yyparse();
    478 	/* NOTREACHED */
    479 }
    480 
    481 static void
    482 lostconn(signo)
    483 	int signo;
    484 {
    485 
    486 	if (debug)
    487 		syslog(LOG_DEBUG, "lost connection");
    488 	dologout(1);
    489 }
    490 
    491 /*
    492  * Save the result of a getpwnam.  Used for USER command, since
    493  * the data returned must not be clobbered by any other command
    494  * (e.g., globbing).
    495  */
    496 static struct passwd *
    497 sgetpwnam(name)
    498 	const char *name;
    499 {
    500 	static struct passwd save;
    501 	struct passwd *p;
    502 
    503 	if ((p = getpwnam(name)) == NULL)
    504 		return (p);
    505 	if (save.pw_name) {
    506 		free((char *)save.pw_name);
    507 		free((char *)save.pw_passwd);
    508 		free((char *)save.pw_gecos);
    509 		free((char *)save.pw_dir);
    510 		free((char *)save.pw_shell);
    511 	}
    512 	save = *p;
    513 	save.pw_name = xstrdup(p->pw_name);
    514 	save.pw_passwd = xstrdup(p->pw_passwd);
    515 	save.pw_gecos = xstrdup(p->pw_gecos);
    516 	save.pw_dir = xstrdup(p->pw_dir);
    517 	save.pw_shell = xstrdup(p->pw_shell);
    518 	return (&save);
    519 }
    520 
    521 static int login_attempts;	/* number of failed login attempts */
    522 static int askpasswd;		/* had user command, ask for passwd */
    523 static char curname[10];	/* current USER name */
    524 
    525 /*
    526  * USER command.
    527  * Sets global passwd pointer pw if named account exists and is acceptable;
    528  * sets askpasswd if a PASS command is expected.  If logged in previously,
    529  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
    530  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
    531  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
    532  * requesting login privileges.  Disallow anyone who does not have a standard
    533  * shell as returned by getusershell().  Disallow anyone mentioned in the file
    534  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
    535  */
    536 void
    537 user(name)
    538 	const char *name;
    539 {
    540 	if (logged_in) {
    541 		if (guest) {
    542 			reply(530, "Can't change user from guest login.");
    543 			return;
    544 		} else if (dochroot) {
    545 			reply(530, "Can't change user from chroot user.");
    546 			return;
    547 		}
    548 		end_login();
    549 	}
    550 
    551 #if defined(KERBEROS) || defined(KERBEROS5)
    552 	kdestroy();
    553 #endif
    554 
    555 	guest = 0;
    556 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
    557 		if (checkaccess("ftp") || checkaccess("anonymous"))
    558 			reply(530, "User %s access denied.", name);
    559 		else if ((pw = sgetpwnam("ftp")) != NULL) {
    560 			guest = 1;
    561 			askpasswd = 1;
    562 			reply(331,
    563 			    "Guest login ok, type your name as password.");
    564 		} else
    565 			reply(530, "User %s unknown.", name);
    566 		if (!askpasswd && logging)
    567 			syslog(LOG_NOTICE,
    568 			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
    569 		return;
    570 	}
    571 
    572 	pw = sgetpwnam(name);
    573 	if (logging)
    574 		strncpy(curname, name, sizeof(curname)-1);
    575 
    576 #ifdef SKEY
    577 	if (skey_haskey(name) == 0) {
    578 		char *myskey;
    579 
    580 		myskey = skey_keyinfo(name);
    581 		reply(331, "Password [%s] required for %s.",
    582 		    myskey ? myskey : "error getting challenge", name);
    583 	} else
    584 #endif
    585 		reply(331, "Password required for %s.", name);
    586 
    587 	askpasswd = 1;
    588 	/*
    589 	 * Delay before reading passwd after first failed
    590 	 * attempt to slow down passwd-guessing programs.
    591 	 */
    592 	if (login_attempts)
    593 		sleep((unsigned) login_attempts);
    594 }
    595 
    596 /*
    597  * Determine whether something is to happen (allow access, chroot)
    598  * for a user. Each line is a shell-style glob followed by
    599  * `yes' or `no'.
    600  *
    601  * For backward compatability, `allow' and `deny' are synonymns
    602  * for `yes' and `no', respectively.
    603  *
    604  * Each glob is matched against the username in turn, and the first
    605  * match found is used. If no match is found, the result is the
    606  * argument `def'. If a match is found but without and explicit
    607  * `yes'/`no', the result is the opposite of def.
    608  *
    609  * If the file doesn't exist at all, the result is the argument
    610  * `nofile'
    611  *
    612  * Any line starting with `#' is considered a comment and ignored.
    613  *
    614  * Returns FALSE if the user is denied, or TRUE if they are allowed.
    615  */
    616 int
    617 checkuser(fname, name, def, nofile)
    618 	const char *fname, *name;
    619 	int def, nofile;
    620 {
    621 	FILE	*fd;
    622 	int	 retval;
    623 	char	*glob, *perm, line[BUFSIZ];
    624 
    625 	retval = def;
    626 	if ((fd = fopen(conffilename(fname), "r")) == NULL)
    627 		return nofile;
    628 
    629 	while (fgets(line, sizeof(line), fd) != NULL)  {
    630 		glob = strtok(line, " \t\n");
    631 		if (glob == NULL || glob[0] == '#')
    632 			continue;
    633 		perm = strtok(NULL, " \t\n");
    634 		if (perm == NULL)
    635 			continue;
    636 		if (fnmatch(glob, name, 0) == 0)  {
    637 			if (perm != NULL &&
    638 			    ((strcasecmp(perm, "allow") == 0) ||
    639 			    (strcasecmp(perm, "yes") == 0)))
    640 				retval = TRUE;
    641 			else if (perm != NULL &&
    642 			    ((strcasecmp(perm, "deny") == 0) ||
    643 			    (strcasecmp(perm, "no") == 0)))
    644 				retval = FALSE;
    645 			else
    646 				retval = !def;
    647 			break;
    648 		}
    649 	}
    650 	(void) fclose(fd);
    651 	return (retval);
    652 }
    653 
    654 /*
    655  * Check if user is allowed by /etc/ftpusers
    656  * returns 0 for yes, 1 for no
    657  */
    658 int
    659 checkaccess(name)
    660 	const char *name;
    661 {
    662 
    663 	return (! checkuser(_PATH_FTPUSERS, name, TRUE, FALSE));
    664 }
    665 
    666 /*
    667  * Terminate login as previous user, if any, resetting state;
    668  * used when USER command is given or login fails.
    669  */
    670 static void
    671 end_login()
    672 {
    673 
    674 	(void) seteuid((uid_t)0);
    675 	if (logged_in)
    676 		logwtmp(ttyline, "", "");
    677 	pw = NULL;
    678 	logged_in = 0;
    679 	guest = 0;
    680 	dochroot = 0;
    681 }
    682 
    683 void
    684 pass(passwd)
    685 	const char *passwd;
    686 {
    687 	int rval;
    688 	FILE *fd;
    689 	char const *cp, *shell, *home;
    690 
    691 	if (logged_in || askpasswd == 0) {
    692 		reply(503, "Login with USER first.");
    693 		return;
    694 	}
    695 	askpasswd = 0;
    696 	if (!guest) {		/* "ftp" is only account allowed no password */
    697 		if (pw == NULL) {
    698 			rval = 1;	/* failure below */
    699 			goto skip;
    700 		}
    701 #ifdef KERBEROS
    702 		if (klogin(pw, "", hostname, (char *)passwd) == 0) {
    703 			rval = 0;
    704 			goto skip;
    705 		}
    706 #endif
    707 #ifdef KERBEROS5
    708 		if (klogin(pw, "", hostname, (char *)passwd) == 0) {
    709 			rval = 0;
    710 			goto skip;
    711 		}
    712 #endif
    713 #ifdef SKEY
    714 		if (skey_haskey(pw->pw_name) == 0) {
    715 			char *p;
    716 			int r;
    717 
    718 			p = xstrdup(passwd);
    719 			r = skey_passcheck(pw->pw_name, p);
    720 			free(p);
    721 			if (r != -1) {
    722 				rval = 0;
    723 				goto skip;
    724 			}
    725 		}
    726 #endif
    727 		if (!sflag && *pw->pw_passwd != '\0' &&
    728 		    !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
    729 			rval = 0;
    730 			goto skip;
    731 		}
    732 		rval = 1;
    733 
    734 skip:
    735 		if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire)
    736 			rval = 2;
    737 		/*
    738 		 * If rval > 0, the user failed the authentication check
    739 		 * above.  If rval == 0, either Kerberos or local authentication
    740 		 * succeeded.
    741 		 */
    742 		if (rval) {
    743 			reply(530, rval == 2 ? "Password expired." :
    744 			    "Login incorrect.");
    745 			if (logging) {
    746 				syslog(LOG_NOTICE,
    747 				    "FTP LOGIN FAILED FROM %s", remotehost);
    748 				syslog(LOG_AUTHPRIV | LOG_NOTICE,
    749 				    "FTP LOGIN FAILED FROM %s, %s",
    750 				    remotehost, curname);
    751 			}
    752 			pw = NULL;
    753 			if (login_attempts++ >= 5) {
    754 				syslog(LOG_NOTICE,
    755 				    "repeated login failures from %s",
    756 				    remotehost);
    757 				exit(0);
    758 			}
    759 			return;
    760 		}
    761 	}
    762 
    763 	/* password was ok; see if anything else prevents login */
    764 	if (checkaccess(pw->pw_name))  {
    765 		reply(530, "User %s may not use FTP.", pw->pw_name);
    766 		if (logging)
    767 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
    768 			    remotehost, pw->pw_name);
    769 		pw = (struct passwd *) NULL;
    770 		return;
    771 	}
    772 	/* check for valid shell, if not guest user */
    773 	if ((shell = pw->pw_shell) == NULL || *shell == 0)
    774 		shell = _PATH_BSHELL;
    775 	while ((cp = getusershell()) != NULL)
    776 		if (strcmp(cp, shell) == 0)
    777 			break;
    778 	endusershell();
    779 	if (cp == NULL && guest == 0) {
    780 		reply(530, "User %s may not use FTP.", pw->pw_name);
    781 		if (logging)
    782 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
    783 			    remotehost, pw->pw_name);
    784 		pw = (struct passwd *) NULL;
    785 		return;
    786 	}
    787 
    788 	login_attempts = 0;		/* this time successful */
    789 	if (setegid((gid_t)pw->pw_gid) < 0) {
    790 		reply(550, "Can't set gid.");
    791 		return;
    792 	}
    793 	(void) initgroups(pw->pw_name, pw->pw_gid);
    794 
    795 	/* open wtmp before chroot */
    796 	logwtmp(ttyline, pw->pw_name, remotehost);
    797 	logged_in = 1;
    798 
    799 	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name, FALSE, FALSE);
    800 
    801 	/* parse ftpd.conf, setting up various parameters */
    802 	if (guest)
    803 		parse_conf(CLASS_GUEST);
    804 	else if (dochroot)
    805 		parse_conf(CLASS_CHROOT);
    806 	else
    807 		parse_conf(CLASS_REAL);
    808 
    809 	home = "/";
    810 	if (guest) {
    811 		/*
    812 		 * We MUST do a chdir() after the chroot. Otherwise
    813 		 * the old current directory will be accessible as "."
    814 		 * outside the new root!
    815 		 */
    816 		if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
    817 		    chdir("/") < 0) {
    818 			reply(550, "Can't set guest privileges.");
    819 			goto bad;
    820 		}
    821 	} else if (dochroot) {
    822 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
    823 			reply(550, "Can't change root.");
    824 			goto bad;
    825 		}
    826 	} else if (chdir(pw->pw_dir) < 0) {
    827 		if (chdir("/") < 0) {
    828 			reply(530, "User %s: can't change directory to %s.",
    829 			    pw->pw_name, pw->pw_dir);
    830 			goto bad;
    831 		} else
    832 			lreply(230, "No directory! Logging in with home=/");
    833 	} else
    834 		home = pw->pw_dir;
    835 	if (seteuid((uid_t)pw->pw_uid) < 0) {
    836 		reply(550, "Can't set uid.");
    837 		goto bad;
    838 	}
    839 	setenv("HOME", home, 1);
    840 
    841 
    842 	/*
    843 	 * Display a login message, if it exists.
    844 	 * N.B. reply(230,) must follow the message.
    845 	 */
    846 	if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) {
    847 		char *cp, line[LINE_MAX];
    848 
    849 		lreply(230, "");
    850 		while (fgets(line, sizeof(line), fd) != NULL) {
    851 			if ((cp = strchr(line, '\n')) != NULL)
    852 				*cp = '\0';
    853 			lreply(0, "%s", line);
    854 		}
    855 		(void) fflush(stdout);
    856 		(void) fclose(fd);
    857 	}
    858 	show_chdir_messages(230);
    859 	if (guest) {
    860 		reply(230, "Guest login ok, access restrictions apply.");
    861 #ifdef HASSETPROCTITLE
    862 		snprintf(proctitle, sizeof(proctitle),
    863 		    "%s: anonymous/%.*s", remotehost,
    864 		    (int) (sizeof(proctitle) - sizeof(remotehost) -
    865 		    sizeof(": anonymous/")), passwd);
    866 		setproctitle(proctitle);
    867 #endif /* HASSETPROCTITLE */
    868 		if (logging)
    869 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
    870 			    remotehost, passwd);
    871 	} else {
    872 		reply(230, "User %s logged in.", pw->pw_name);
    873 #ifdef HASSETPROCTITLE
    874 		snprintf(proctitle, sizeof(proctitle),
    875 		    "%s: %s", remotehost, pw->pw_name);
    876 		setproctitle(proctitle);
    877 #endif /* HASSETPROCTITLE */
    878 		if (logging)
    879 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
    880 			    remotehost, pw->pw_name);
    881 	}
    882 	(void) umask(curclass.umask);
    883 	return;
    884 bad:
    885 	/* Forget all about it... */
    886 	end_login();
    887 }
    888 
    889 void
    890 retrieve(cmd, name)
    891 	const char *cmd, *name;
    892 {
    893 	FILE *fin = NULL, *dout;
    894 	struct stat st;
    895 	int (*closefunc) __P((FILE *)) = NULL;
    896 	int log, sendrv, closerv, stderrfd, isconversion, isdata, isls;
    897 	struct timeval start, finish, td, *tdp;
    898 	char tline[BUFSIZ];
    899 	const char *dispname;
    900 
    901 	sendrv = closerv = stderrfd = -1;
    902 	isconversion = isdata = isls = log = 0;
    903 	tdp = NULL;
    904 	dispname = name;
    905 	if (cmd == NULL) {
    906 		log = 1;
    907 		isdata = 1;
    908 		fin = fopen(name, "r");
    909 		closefunc = fclose;
    910 		if (fin == NULL)
    911 			cmd = do_conversion(name);
    912 		if (cmd != NULL) {
    913 			isconversion++;
    914 			syslog(LOG_INFO, "get command: '%s'", cmd);
    915 		}
    916 	}
    917 	if (cmd != NULL) {
    918 		char temp[MAXPATHLEN + 1];
    919 
    920 		if (strncmp(cmd, INTERNAL_LS, sizeof(INTERNAL_LS) - 1) == 0 &&
    921 		    strchr(" \t\n", cmd[sizeof(INTERNAL_LS) - 1]) != NULL) {
    922 			isls = 1;
    923 			stderrfd = -1;
    924 		} else {
    925 			(void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
    926 			stderrfd = mkstemp(temp);
    927 			if (stderrfd != -1)
    928 				(void)unlink(temp);
    929 		}
    930 		(void)snprintf(tline, sizeof(tline), cmd, name);
    931 		dispname = tline;
    932 		fin = ftpd_popen(tline, "r", stderrfd);
    933 		closefunc = ftpd_pclose;
    934 		st.st_size = -1;
    935 		st.st_blksize = BUFSIZ;
    936 	}
    937 	if (fin == NULL) {
    938 		if (errno != 0) {
    939 			perror_reply(550, dispname);
    940 			if (log)
    941 				logcmd("get", -1, name, NULL, NULL,
    942 				    strerror(errno));
    943 		}
    944 		if (stderrfd != -1)
    945 			(void)close(stderrfd);
    946 		return;
    947 	}
    948 	byte_count = -1;
    949 	if (cmd == NULL
    950 	    && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
    951 		reply(550, "%s: not a plain file.", dispname);
    952 		goto done;
    953 	}
    954 	if (restart_point) {
    955 		if (type == TYPE_A) {
    956 			off_t i;
    957 			int c;
    958 
    959 			for (i = 0; i < restart_point; i++) {
    960 				if ((c=getc(fin)) == EOF) {
    961 					perror_reply(550, dispname);
    962 					goto done;
    963 				}
    964 				if (c == '\n')
    965 					i++;
    966 			}
    967 		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
    968 			perror_reply(550, dispname);
    969 			goto done;
    970 		}
    971 	}
    972 	dout = dataconn(dispname, st.st_size, "w");
    973 	if (dout == NULL)
    974 		goto done;
    975 
    976 	(void)gettimeofday(&start, NULL);
    977 	sendrv = send_data(fin, dout, st.st_blksize, isdata);
    978 	(void)gettimeofday(&finish, NULL);
    979 	(void) fclose(dout);
    980 	timersub(&finish, &start, &td);
    981 	tdp = &td;
    982 	data = -1;
    983 	pdata = -1;
    984 done:
    985 	if (log)
    986 		logcmd("get", byte_count, name, NULL, tdp, NULL);
    987 	closerv = (*closefunc)(fin);
    988 	if (sendrv == 0) {
    989 		FILE *err;
    990 		struct stat sb;
    991 
    992 		if (!isls && cmd != NULL && closerv != 0) {
    993 			lreply(226,
    994 			    "Command returned an exit status of %d",
    995 			    closerv);
    996 			if (isconversion)
    997 				syslog(LOG_INFO,
    998 				    "get command: '%s' returned %d",
    999 				    cmd, closerv);
   1000 		}
   1001 		if (!isls && cmd != NULL && stderrfd != -1 &&
   1002 		    (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
   1003 		    ((err = fdopen(stderrfd, "r")) != NULL)) {
   1004 			char *cp, line[LINE_MAX];
   1005 
   1006 			lreply(226, "Command error messages:");
   1007 			rewind(err);
   1008 			while (fgets(line, sizeof(line), err) != NULL) {
   1009 				if ((cp = strchr(line, '\n')) != NULL)
   1010 					*cp = '\0';
   1011 				lreply(0, "  %s", line);
   1012 			}
   1013 			(void) fflush(stdout);
   1014 			(void) fclose(err);
   1015 				/* a reply(226,) must follow */
   1016 		}
   1017 		reply(226, "Transfer complete.");
   1018 	}
   1019 	if (stderrfd != -1)
   1020 		(void)close(stderrfd);
   1021 }
   1022 
   1023 void
   1024 store(name, mode, unique)
   1025 	const char *name, *mode;
   1026 	int unique;
   1027 {
   1028 	FILE *fout, *din;
   1029 	struct stat st;
   1030 	int (*closefunc) __P((FILE *));
   1031 	struct timeval start, finish, td, *tdp;
   1032 	char *desc;
   1033 
   1034 	desc = (*mode == 'w') ? "put" : "append";
   1035 	if (unique && stat(name, &st) == 0 &&
   1036 	    (name = gunique(name)) == NULL) {
   1037 		logcmd(desc, -1, name, NULL, NULL, "cannot create unique file");
   1038 		return;
   1039 	}
   1040 
   1041 	if (restart_point)
   1042 		mode = "r+";
   1043 	fout = fopen(name, mode);
   1044 	closefunc = fclose;
   1045 	tdp = NULL;
   1046 	if (fout == NULL) {
   1047 		perror_reply(553, name);
   1048 		logcmd(desc, -1, name, NULL, NULL, strerror(errno));
   1049 		return;
   1050 	}
   1051 	byte_count = -1;
   1052 	if (restart_point) {
   1053 		if (type == TYPE_A) {
   1054 			off_t i;
   1055 			int c;
   1056 
   1057 			for (i = 0; i < restart_point; i++) {
   1058 				if ((c=getc(fout)) == EOF) {
   1059 					perror_reply(550, name);
   1060 					goto done;
   1061 				}
   1062 				if (c == '\n')
   1063 					i++;
   1064 			}
   1065 			/*
   1066 			 * We must do this seek to "current" position
   1067 			 * because we are changing from reading to
   1068 			 * writing.
   1069 			 */
   1070 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
   1071 				perror_reply(550, name);
   1072 				goto done;
   1073 			}
   1074 		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
   1075 			perror_reply(550, name);
   1076 			goto done;
   1077 		}
   1078 	}
   1079 	din = dataconn(name, (off_t)-1, "r");
   1080 	if (din == NULL)
   1081 		goto done;
   1082 	(void)gettimeofday(&start, NULL);
   1083 	if (receive_data(din, fout) == 0) {
   1084 		if (unique)
   1085 			reply(226, "Transfer complete (unique file name:%s).",
   1086 			    name);
   1087 		else
   1088 			reply(226, "Transfer complete.");
   1089 	}
   1090 	(void)gettimeofday(&finish, NULL);
   1091 	(void) fclose(din);
   1092 	timersub(&finish, &start, &td);
   1093 	tdp = &td;
   1094 	data = -1;
   1095 	pdata = -1;
   1096 done:
   1097 	logcmd(desc, byte_count, name, NULL, tdp, NULL);
   1098 	(*closefunc)(fout);
   1099 }
   1100 
   1101 static FILE *
   1102 getdatasock(mode)
   1103 	const char *mode;
   1104 {
   1105 	int on = 1, s, t, tries;
   1106 
   1107 	if (data >= 0)
   1108 		return (fdopen(data, mode));
   1109 	(void) seteuid((uid_t)0);
   1110 	s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
   1111 	if (s < 0)
   1112 		goto bad;
   1113 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
   1114 	    (char *) &on, sizeof(on)) < 0)
   1115 		goto bad;
   1116 	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
   1117 	    (char *) &on, sizeof(on)) < 0)
   1118 		goto bad;
   1119 	/* anchor socket to avoid multi-homing problems */
   1120 	data_source = ctrl_addr;
   1121 	data_source.su_port = htons(20); /* ftp-data port */
   1122 	for (tries = 1; ; tries++) {
   1123 		if (bind(s, (struct sockaddr *)&data_source,
   1124 		    data_source.su_len) >= 0)
   1125 			break;
   1126 		if (errno != EADDRINUSE || tries > 10)
   1127 			goto bad;
   1128 		sleep(tries);
   1129 	}
   1130 	(void) seteuid((uid_t)pw->pw_uid);
   1131 #ifdef IP_TOS
   1132 	if (ctrl_addr.su_family == AF_INET) {
   1133 		on = IPTOS_THROUGHPUT;
   1134 		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
   1135 			       sizeof(int)) < 0)
   1136 			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
   1137 	}
   1138 #endif
   1139 	return (fdopen(s, mode));
   1140 bad:
   1141 	/* Return the real value of errno (close may change it) */
   1142 	t = errno;
   1143 	(void) seteuid((uid_t)pw->pw_uid);
   1144 	(void) close(s);
   1145 	errno = t;
   1146 	return (NULL);
   1147 }
   1148 
   1149 static FILE *
   1150 dataconn(name, size, mode)
   1151 	const char *name;
   1152 	off_t size;
   1153 	const char *mode;
   1154 {
   1155 	char sizebuf[32];
   1156 	FILE *file;
   1157 	int retry = 0, tos, keepalive;
   1158 
   1159 	file_size = size;
   1160 	byte_count = 0;
   1161 	if (size != (off_t) -1)
   1162 		(void)snprintf(sizebuf, sizeof(sizebuf), " (%qd byte%s)",
   1163 		    (qdfmt_t)size, PLURAL(size));
   1164 	else
   1165 		sizebuf[0] = '\0';
   1166 	if (pdata >= 0) {
   1167 		union sockunion from;
   1168 		int s, fromlen = sizeof(from);
   1169 
   1170 		(void) alarm(curclass.timeout);
   1171 		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
   1172 		(void) alarm(0);
   1173 		if (s < 0) {
   1174 			reply(425, "Can't open data connection.");
   1175 			(void) close(pdata);
   1176 			pdata = -1;
   1177 			return (NULL);
   1178 		}
   1179 		(void) close(pdata);
   1180 		pdata = s;
   1181 		switch (from.su_family) {
   1182 		case AF_INET:
   1183 #ifdef IP_TOS
   1184 			tos = IPTOS_THROUGHPUT;
   1185 			(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
   1186 			    sizeof(int));
   1187 			break;
   1188 #endif
   1189 		}
   1190 		/* Set keepalives on the socket to detect dropped conns. */
   1191 #ifdef SO_KEEPALIVE
   1192 		keepalive = 1;
   1193 		(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
   1194 		    (char *)&keepalive, sizeof(int));
   1195 #endif
   1196 		reply(150, "Opening %s mode data connection for '%s'%s.",
   1197 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1198 		return (fdopen(pdata, mode));
   1199 	}
   1200 	if (data >= 0) {
   1201 		reply(125, "Using existing data connection for '%s'%s.",
   1202 		    name, sizebuf);
   1203 		usedefault = 1;
   1204 		return (fdopen(data, mode));
   1205 	}
   1206 	if (usedefault)
   1207 		data_dest = his_addr;
   1208 	usedefault = 1;
   1209 	file = getdatasock(mode);
   1210 	if (file == NULL) {
   1211 		char hbuf[INET6_ADDRSTRLEN];
   1212 		char pbuf[10];
   1213 		getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
   1214 			hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
   1215 			NI_NUMERICHOST | NI_NUMERICSERV);
   1216 		reply(425, "Can't create data socket (%s,%s): %s.",
   1217 		      hbuf, pbuf, strerror(errno));
   1218 		return (NULL);
   1219 	}
   1220 	data = fileno(file);
   1221 	while (connect(data, (struct sockaddr *)&data_dest,
   1222 	    data_dest.su_len) < 0) {
   1223 		if (errno == EADDRINUSE && retry < swaitmax) {
   1224 			sleep((unsigned) swaitint);
   1225 			retry += swaitint;
   1226 			continue;
   1227 		}
   1228 		perror_reply(425, "Can't build data connection");
   1229 		(void) fclose(file);
   1230 		data = -1;
   1231 		return (NULL);
   1232 	}
   1233 	reply(150, "Opening %s mode data connection for '%s'%s.",
   1234 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1235 	return (file);
   1236 }
   1237 
   1238 /*
   1239  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
   1240  * encapsulation of the data subject * to Mode, Structure, and Type.
   1241  *
   1242  * NB: Form isn't handled.
   1243  */
   1244 static int
   1245 send_data(instr, outstr, blksize, isdata)
   1246 	FILE *instr, *outstr;
   1247 	off_t blksize;
   1248 	int isdata;
   1249 {
   1250 	int	 c, cnt, filefd, netfd, rval;
   1251 	char	*buf;
   1252 
   1253 	transflag = 1;
   1254 	rval = -1;
   1255 	buf = NULL;
   1256 	if (setjmp(urgcatch))
   1257 		goto cleanup_send_data;
   1258 
   1259 	switch (type) {
   1260 
   1261 	case TYPE_A:
   1262 		(void) alarm(curclass.timeout);
   1263 		while ((c = getc(instr)) != EOF) {
   1264 			byte_count++;
   1265 			if (c == '\n') {
   1266 				if (ferror(outstr))
   1267 					goto data_err;
   1268 				(void) putc('\r', outstr);
   1269 				if (isdata) {
   1270 					total_data_out++;
   1271 					total_data++;
   1272 				}
   1273 				total_bytes_out++;
   1274 				total_bytes++;
   1275 			}
   1276 			(void) putc(c, outstr);
   1277 			if (isdata) {
   1278 				total_data_out++;
   1279 				total_data++;
   1280 			}
   1281 			total_bytes_out++;
   1282 			total_bytes++;
   1283 			if ((byte_count % 4096) == 0)
   1284 				(void) alarm(curclass.timeout);
   1285 		}
   1286 		(void) alarm(0);
   1287 		fflush(outstr);
   1288 		if (ferror(instr))
   1289 			goto file_err;
   1290 		if (ferror(outstr))
   1291 			goto data_err;
   1292 		rval = 0;
   1293 		goto cleanup_send_data;
   1294 
   1295 	case TYPE_I:
   1296 	case TYPE_L:
   1297 		if ((buf = malloc((size_t)blksize)) == NULL) {
   1298 			perror_reply(451, "Local resource failure: malloc");
   1299 			goto cleanup_send_data;
   1300 		}
   1301 		filefd = fileno(instr);
   1302 		netfd = fileno(outstr);
   1303 		(void) alarm(curclass.timeout);
   1304 		while ((cnt = read(filefd, buf, (size_t)blksize)) > 0) {
   1305 			if (write(netfd, buf, cnt) != cnt)
   1306 				goto data_err;
   1307 			(void) alarm(curclass.timeout);
   1308 			byte_count += cnt;
   1309 			if (isdata) {
   1310 				total_data_out += cnt;
   1311 				total_data += cnt;
   1312 			}
   1313 			total_bytes_out += cnt;
   1314 			total_bytes += cnt;
   1315 		}
   1316 		if (cnt < 0)
   1317 			goto file_err;
   1318 		rval = 0;
   1319 		goto cleanup_send_data;
   1320 
   1321 	default:
   1322 		reply(550, "Unimplemented TYPE %d in send_data", type);
   1323 		goto cleanup_send_data;
   1324 	}
   1325 
   1326 data_err:
   1327 	(void) alarm(0);
   1328 	perror_reply(426, "Data connection");
   1329 	goto cleanup_send_data;
   1330 
   1331 file_err:
   1332 	(void) alarm(0);
   1333 	perror_reply(551, "Error on input file");
   1334 		/* FALLTHROUGH */
   1335 
   1336 cleanup_send_data:
   1337 	(void) alarm(0);
   1338 	transflag = 0;
   1339 	if (buf)
   1340 		free(buf);
   1341 	if (isdata) {
   1342 		total_files_out++;
   1343 		total_files++;
   1344 	}
   1345 	total_xfers_out++;
   1346 	total_xfers++;
   1347 	return (rval);
   1348 }
   1349 
   1350 /*
   1351  * Transfer data from peer to "outstr" using the appropriate encapulation of
   1352  * the data subject to Mode, Structure, and Type.
   1353  *
   1354  * N.B.: Form isn't handled.
   1355  */
   1356 static int
   1357 receive_data(instr, outstr)
   1358 	FILE *instr, *outstr;
   1359 {
   1360 	int	c, cnt, bare_lfs, netfd, filefd, rval;
   1361 	char	buf[BUFSIZ];
   1362 #ifdef __GNUC__
   1363 	(void) &bare_lfs;
   1364 #endif
   1365 
   1366 	bare_lfs = 0;
   1367 	transflag = 1;
   1368 	rval = -1;
   1369 	if (setjmp(urgcatch))
   1370 		goto cleanup_recv_data;
   1371 
   1372 	switch (type) {
   1373 
   1374 	case TYPE_I:
   1375 	case TYPE_L:
   1376 		netfd = fileno(instr);
   1377 		filefd = fileno(outstr);
   1378 		(void) alarm(curclass.timeout);
   1379 		while ((cnt = read(netfd, buf, sizeof(buf))) > 0) {
   1380 			if (write(filefd, buf, cnt) != cnt)
   1381 				goto file_err;
   1382 			(void) alarm(curclass.timeout);
   1383 			byte_count += cnt;
   1384 			total_data_in += cnt;
   1385 			total_data += cnt;
   1386 			total_bytes_in += cnt;
   1387 			total_bytes += cnt;
   1388 		}
   1389 		if (cnt < 0)
   1390 			goto data_err;
   1391 		rval = 0;
   1392 		goto cleanup_recv_data;
   1393 
   1394 	case TYPE_E:
   1395 		reply(553, "TYPE E not implemented.");
   1396 		goto cleanup_recv_data;
   1397 
   1398 	case TYPE_A:
   1399 		(void) alarm(curclass.timeout);
   1400 		while ((c = getc(instr)) != EOF) {
   1401 			byte_count++;
   1402 			total_data_in++;
   1403 			total_data++;
   1404 			total_bytes_in++;
   1405 			total_bytes++;
   1406 			if ((byte_count % 4096) == 0)
   1407 				(void) alarm(curclass.timeout);
   1408 			if (c == '\n')
   1409 				bare_lfs++;
   1410 			while (c == '\r') {
   1411 				if (ferror(outstr))
   1412 					goto data_err;
   1413 				if ((c = getc(instr)) != '\n') {
   1414 					byte_count++;
   1415 					total_data_in++;
   1416 					total_data++;
   1417 					total_bytes_in++;
   1418 					total_bytes++;
   1419 					if ((byte_count % 4096) == 0)
   1420 						(void) alarm(curclass.timeout);
   1421 					(void) putc ('\r', outstr);
   1422 					if (c == '\0' || c == EOF)
   1423 						goto contin2;
   1424 				}
   1425 			}
   1426 			(void) putc(c, outstr);
   1427 	contin2:	;
   1428 		}
   1429 		(void) alarm(0);
   1430 		fflush(outstr);
   1431 		if (ferror(instr))
   1432 			goto data_err;
   1433 		if (ferror(outstr))
   1434 			goto file_err;
   1435 		if (bare_lfs) {
   1436 			lreply(226,
   1437 			    "WARNING! %d bare linefeeds received in ASCII mode",
   1438 			    bare_lfs);
   1439 			lreply(0, "File may not have transferred correctly.");
   1440 		}
   1441 		rval = 0;
   1442 		goto cleanup_recv_data;
   1443 
   1444 	default:
   1445 		reply(550, "Unimplemented TYPE %d in receive_data", type);
   1446 		goto cleanup_recv_data;
   1447 	}
   1448 
   1449 data_err:
   1450 	(void) alarm(0);
   1451 	perror_reply(426, "Data Connection");
   1452 	goto cleanup_recv_data;
   1453 
   1454 file_err:
   1455 	(void) alarm(0);
   1456 	perror_reply(452, "Error writing file");
   1457 	goto cleanup_recv_data;
   1458 
   1459 cleanup_recv_data:
   1460 	(void) alarm(0);
   1461 	transflag = 0;
   1462 	total_files_in++;
   1463 	total_files++;
   1464 	total_xfers_in++;
   1465 	total_xfers++;
   1466 	return (rval);
   1467 }
   1468 
   1469 void
   1470 statfilecmd(filename)
   1471 	const char *filename;
   1472 {
   1473 	FILE *fin;
   1474 	int c;
   1475 	char line[LINE_MAX];
   1476 
   1477 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
   1478 	fin = ftpd_popen(line, "r", STDOUT_FILENO);
   1479 	lreply(211, "status of %s:", filename);
   1480 	while ((c = getc(fin)) != EOF) {
   1481 		if (c == '\n') {
   1482 			if (ferror(stdout)){
   1483 				perror_reply(421, "control connection");
   1484 				(void) ftpd_pclose(fin);
   1485 				dologout(1);
   1486 				/* NOTREACHED */
   1487 			}
   1488 			if (ferror(fin)) {
   1489 				perror_reply(551, filename);
   1490 				(void) ftpd_pclose(fin);
   1491 				return;
   1492 			}
   1493 			(void) putc('\r', stdout);
   1494 			total_bytes++;
   1495 			total_bytes_out++;
   1496 		}
   1497 		(void) putc(c, stdout);
   1498 		total_bytes++;
   1499 		total_bytes_out++;
   1500 	}
   1501 	(void) ftpd_pclose(fin);
   1502 	reply(211, "End of Status");
   1503 }
   1504 
   1505 void
   1506 statcmd()
   1507 {
   1508 	union sockunion *su = NULL;
   1509 	static char ntop_buf[INET6_ADDRSTRLEN];
   1510   	u_char *a, *p;
   1511 	int ispassive;
   1512 	off_t b, otbi, otbo, otb;
   1513 
   1514 	a = p = (u_char *)NULL;
   1515 
   1516 	lreply(211, "%s FTP server status:", hostname);
   1517 	lreply(0, "%s", version);
   1518 	ntop_buf[0] = '\0';
   1519 	if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
   1520 			ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST)
   1521 	 && strcmp(remotehost, ntop_buf) != 0) {
   1522 		lreply(0, "Connected to %s (%s)", remotehost, ntop_buf);
   1523 	} else
   1524 		lreply(0, "Connected to %s", remotehost);
   1525 	if (logged_in) {
   1526 		if (guest)
   1527 			lreply(0, "Logged in anonymously");
   1528 		else
   1529 			lreply(0, "Logged in as %s", pw->pw_name);
   1530 	} else if (askpasswd)
   1531 		lreply(0, "Waiting for password");
   1532 	else
   1533 		lreply(0, "Waiting for user name");
   1534 	b = printf("    TYPE: %s", typenames[type]);
   1535 	total_bytes += b;
   1536 	total_bytes_out += b;
   1537 	if (type == TYPE_A || type == TYPE_E) {
   1538 		b = printf(", FORM: %s", formnames[form]);
   1539 		total_bytes += b;
   1540 		total_bytes_out += b;
   1541 	}
   1542 	if (type == TYPE_L) {
   1543 #if NBBY == 8
   1544 		b = printf(" %d", NBBY);
   1545 #else
   1546 			/* XXX: `bytesize' needs to be defined in this case */
   1547 		b = printf(" %d", bytesize);
   1548 #endif
   1549 		total_bytes += b;
   1550 		total_bytes_out += b;
   1551 	}
   1552 	b = printf("; STRUcture: %s; transfer MODE: %s\r\n",
   1553 	    strunames[stru], modenames[mode]);
   1554 	total_bytes += b;
   1555 	total_bytes_out += b;
   1556 	ispassive = 0;
   1557 	if (data != -1) {
   1558   		lreply(0, "Data connection open");
   1559 		su = NULL;
   1560 	} else if (pdata != -1) {
   1561 		b = printf("                in Passive mode");
   1562 		total_bytes += b;
   1563 		total_bytes_out += b;
   1564 		su = (union sockunion *)&pasv_addr;
   1565 		ispassive = 1;
   1566 		goto printaddr;
   1567 	} else if (usedefault == 0) {
   1568 		if (epsvall) {
   1569 			b = printf("211- EPSV only mode (EPSV ALL )\r\n");
   1570 			total_bytes += b;
   1571 			total_bytes_out += b;
   1572 			goto epsvonly;
   1573 		}
   1574 		b = printf("211- %s",
   1575 			(data_dest.su_family == AF_INET) ? "PORT" : "LPRT");
   1576 		total_bytes += b;
   1577 		total_bytes_out += b;
   1578 		su = (union sockunion *)&data_dest;
   1579 printaddr:
   1580 		/* PASV/PORT */
   1581 		if (su->su_family == AF_INET) {
   1582 			if (ispassive)
   1583 				b = printf("211- PASV ");
   1584 			else
   1585 				b = printf("211- PORT ");
   1586 			a = (u_char *) &su->su_sin.sin_addr;
   1587 			p = (u_char *) &su->su_sin.sin_port;
   1588 #define UC(b) (((int) b) & 0xff)
   1589 			b += printf("(%d,%d,%d,%d,%d,%d)\r\n",
   1590 				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
   1591 				UC(p[0]), UC(p[1]));
   1592 			total_bytes += b;
   1593 			total_bytes_out += b;
   1594 		}
   1595 
   1596 		/* LPSV/LPRT */
   1597 	    {
   1598 		int alen, af, i;
   1599 
   1600 		alen = 0;
   1601 		switch (su->su_family) {
   1602 		case AF_INET:
   1603 			a = (u_char *) &su->su_sin.sin_addr;
   1604 			p = (u_char *) &su->su_sin.sin_port;
   1605 			alen = sizeof(su->su_sin.sin_addr);
   1606 			af = 4;
   1607 			break;
   1608 		case AF_INET6:
   1609 			a = (u_char *) &su->su_sin6.sin6_addr;
   1610 			p = (u_char *) &su->su_sin6.sin6_port;
   1611 			alen = sizeof(su->su_sin6.sin6_addr);
   1612 			af = 6;
   1613 			break;
   1614 		default:
   1615 			af = 0;
   1616 			break;
   1617 		}
   1618 		if (af) {
   1619 			if (ispassive)
   1620 				b = printf("211- LPSV ");
   1621 			else
   1622 				b = printf("211- LPRT ");
   1623 			printf("(%d,%d", af, alen);
   1624 			for (i = 0; i < alen; i++)
   1625 				b += printf("%d,", UC(a[alen]));
   1626 			b += printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
   1627 			total_bytes += b;
   1628 			total_bytes_out += b;
   1629 #undef UC
   1630 		}
   1631 	    }
   1632 
   1633 		/* EPRT/EPSV */
   1634 epsvonly:;
   1635 	    {
   1636 		int af;
   1637 
   1638 		switch (su->su_family) {
   1639 		case AF_INET:
   1640 			af = 1;
   1641 			break;
   1642 		case AF_INET6:
   1643 			af = 2;
   1644 			break;
   1645 		default:
   1646 			af = 0;
   1647 			break;
   1648 		}
   1649 		if (af) {
   1650 			if (getnameinfo((struct sockaddr *)su, su->su_len,
   1651 					ntop_buf, sizeof(ntop_buf), NULL, 0,
   1652 					NI_NUMERICHOST) == 0) {
   1653 				if (ispassive)
   1654 					b = printf("211 - EPSV ");
   1655 				else
   1656 					b = printf("211 - EPRT ");
   1657 				b += printf("(|%d|%s|%d|)\r\n",
   1658 					af, ntop_buf, ntohs(su->su_port));
   1659 				total_bytes += b;
   1660 				total_bytes_out += b;
   1661 			}
   1662 		}
   1663 	    }
   1664 	} else
   1665 		lreply(0, "No data connection");
   1666 
   1667 	if (logged_in) {
   1668 		lreply(0, "Data sent:        %qd byte%s in %qd file%s",
   1669 		    (qdfmt_t)total_data_out, PLURAL(total_data_out),
   1670 		    (qdfmt_t)total_files_out, PLURAL(total_files_out));
   1671 		lreply(0, "Data received:    %qd byte%s in %qd file%s",
   1672 		    (qdfmt_t)total_data_in, PLURAL(total_data_in),
   1673 		    (qdfmt_t)total_files_in, PLURAL(total_files_in));
   1674 		lreply(0, "Total data:       %qd byte%s in %qd file%s",
   1675 		    (qdfmt_t)total_data, PLURAL(total_data),
   1676 		    (qdfmt_t)total_files, PLURAL(total_files));
   1677 	}
   1678 	otbi = total_bytes_in;
   1679 	otbo = total_bytes_out;
   1680 	otb = total_bytes;
   1681 	lreply(0, "Traffic sent:     %qd byte%s in %qd transfer%s",
   1682 	    (qdfmt_t)otbo, PLURAL(otbo),
   1683 	    (qdfmt_t)total_xfers_out, PLURAL(total_xfers_out));
   1684 	lreply(0, "Traffic received: %qd byte%s in %qd transfer%s",
   1685 	    (qdfmt_t)otbi, PLURAL(otbi),
   1686 	    (qdfmt_t)total_xfers_in, PLURAL(total_xfers_in));
   1687 	lreply(0, "Total traffic:    %qd byte%s in %qd transfer%s",
   1688 	    (qdfmt_t)otb, PLURAL(otb),
   1689 	    (qdfmt_t)total_xfers, PLURAL(total_xfers));
   1690 
   1691 	if (logged_in) {
   1692 		struct ftpconv *cp;
   1693 
   1694 		lreply(0, "");
   1695 		lreply(0, "Class: %s", curclass.classname);
   1696 		lreply(0, "Check PORT/LPRT commands: %sabled",
   1697 		    curclass.checkportcmd ? "en" : "dis");
   1698 		if (curclass.display)
   1699 			lreply(0, "Display file: %s", curclass.display);
   1700 		if (curclass.notify)
   1701 			lreply(0, "Notify fileglob: %s", curclass.notify);
   1702 		lreply(0, "Idle timeout: %d, maximum timeout: %d",
   1703 		    curclass.timeout, curclass.maxtimeout);
   1704 		lreply(0, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled",
   1705 		    curclass.modify ? "en" : "dis");
   1706 		lreply(0, "Umask: %.04o", curclass.umask);
   1707 		for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
   1708 			if (cp->suffix == NULL || cp->types == NULL ||
   1709 			    cp->command == NULL)
   1710 				continue;
   1711 			lreply(0,
   1712 			    "Conversion: %s [%s] disable: %s, command: %s",
   1713 			    cp->suffix, cp->types, cp->disable, cp->command);
   1714 		}
   1715 	}
   1716 
   1717 	reply(211, "End of status");
   1718 }
   1719 
   1720 void
   1721 fatal(s)
   1722 	const char *s;
   1723 {
   1724 
   1725 	reply(451, "Error in server: %s\n", s);
   1726 	reply(221, "Closing connection due to server error.");
   1727 	dologout(0);
   1728 	/* NOTREACHED */
   1729 }
   1730 
   1731 void
   1732 #ifdef __STDC__
   1733 reply(int n, const char *fmt, ...)
   1734 #else
   1735 reply(n, fmt, va_alist)
   1736 	int n;
   1737 	char *fmt;
   1738         va_dcl
   1739 #endif
   1740 {
   1741 	off_t b;
   1742 	va_list ap;
   1743 #ifdef __STDC__
   1744 	va_start(ap, fmt);
   1745 #else
   1746 	va_start(ap);
   1747 #endif
   1748 	b = 0;
   1749 	b += printf("%d ", n);
   1750 	b += vprintf(fmt, ap);
   1751 	b += printf("\r\n");
   1752 	total_bytes += b;
   1753 	total_bytes_out += b;
   1754 	(void)fflush(stdout);
   1755 	if (debug) {
   1756 		syslog(LOG_DEBUG, "<--- %d ", n);
   1757 		vsyslog(LOG_DEBUG, fmt, ap);
   1758 	}
   1759 }
   1760 
   1761 void
   1762 #ifdef __STDC__
   1763 lreply(int n, const char *fmt, ...)
   1764 #else
   1765 lreply(n, fmt, va_alist)
   1766 	int n;
   1767 	char *fmt;
   1768         va_dcl
   1769 #endif
   1770 {
   1771 	off_t b;
   1772 	va_list ap;
   1773 #ifdef __STDC__
   1774 	va_start(ap, fmt);
   1775 #else
   1776 	va_start(ap);
   1777 #endif
   1778 	b = 0;
   1779 	switch (n) {
   1780 		case 0:
   1781 			b += printf("    ");
   1782 		case -1:
   1783 			break;
   1784 		default:
   1785 			b += printf("%d-", n);
   1786 			break;
   1787 	}
   1788 	b += vprintf(fmt, ap);
   1789 	b += printf("\r\n");
   1790 	total_bytes += b;
   1791 	total_bytes_out += b;
   1792 	(void)fflush(stdout);
   1793 	if (debug) {
   1794 		syslog(LOG_DEBUG, "<--- %d- ", n);
   1795 		vsyslog(LOG_DEBUG, fmt, ap);
   1796 	}
   1797 }
   1798 
   1799 static void
   1800 ack(s)
   1801 	const char *s;
   1802 {
   1803 
   1804 	reply(250, "%s command successful.", s);
   1805 }
   1806 
   1807 void
   1808 delete(name)
   1809 	const char *name;
   1810 {
   1811 	char *p = NULL;
   1812 
   1813 	if (remove(name) < 0) {
   1814 		p = strerror(errno);
   1815 		perror_reply(550, name);
   1816 	} else
   1817 		ack("DELE");
   1818 	logcmd("delete", -1, name, NULL, NULL, p);
   1819 }
   1820 
   1821 void
   1822 cwd(path)
   1823 	const char *path;
   1824 {
   1825 
   1826 	if (chdir(path) < 0)
   1827 		perror_reply(550, path);
   1828 	else {
   1829 		show_chdir_messages(250);
   1830 		ack("CWD");
   1831 	}
   1832 }
   1833 
   1834 static void
   1835 replydirname(name, message)
   1836 	const char *name, *message;
   1837 {
   1838 	char npath[MAXPATHLEN + 1];
   1839 	int i;
   1840 
   1841 	for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
   1842 		npath[i] = *name;
   1843 		if (*name == '"')
   1844 			npath[++i] = '"';
   1845 	}
   1846 	npath[i] = '\0';
   1847 	reply(257, "\"%s\" %s", npath, message);
   1848 }
   1849 
   1850 void
   1851 makedir(name)
   1852 	const char *name;
   1853 {
   1854 	char *p = NULL;
   1855 
   1856 	if (mkdir(name, 0777) < 0) {
   1857 		p = strerror(errno);
   1858 		perror_reply(550, name);
   1859 	} else
   1860 		replydirname(name, "directory created.");
   1861 	logcmd("mkdir", -1, name, NULL, NULL, p);
   1862 }
   1863 
   1864 void
   1865 removedir(name)
   1866 	const char *name;
   1867 {
   1868 	char *p = NULL;
   1869 
   1870 	if (rmdir(name) < 0) {
   1871 		p = strerror(errno);
   1872 		perror_reply(550, name);
   1873 	} else
   1874 		ack("RMD");
   1875 	logcmd("rmdir", -1, name, NULL, NULL, p);
   1876 }
   1877 
   1878 void
   1879 pwd()
   1880 {
   1881 	char path[MAXPATHLEN + 1];
   1882 
   1883 	if (getcwd(path, sizeof(path) - 1) == NULL)
   1884 		reply(550, "Can't get the current directory: %s.",
   1885 		    strerror(errno));
   1886 	else
   1887 		replydirname(path, "is the current directory.");
   1888 }
   1889 
   1890 char *
   1891 renamefrom(name)
   1892 	char *name;
   1893 {
   1894 	struct stat st;
   1895 
   1896 	if (stat(name, &st) < 0) {
   1897 		perror_reply(550, name);
   1898 		return (NULL);
   1899 	}
   1900 	reply(350, "File exists, ready for destination name");
   1901 	return (name);
   1902 }
   1903 
   1904 void
   1905 renamecmd(from, to)
   1906 	const char *from, *to;
   1907 {
   1908 	char *p = NULL;
   1909 
   1910 	if (rename(from, to) < 0) {
   1911 		p = strerror(errno);
   1912 		perror_reply(550, "rename");
   1913 	} else
   1914 		ack("RNTO");
   1915 	logcmd("rename", -1, from, to, NULL, p);
   1916 }
   1917 
   1918 static void
   1919 dolog(who)
   1920 	struct sockaddr *who;
   1921 {
   1922 	int error;
   1923 	error = getnameinfo(who, who->sa_len, remotehost, sizeof(remotehost),
   1924 			    NULL, 0, 0);
   1925 #ifdef HASSETPROCTITLE
   1926 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
   1927 	setproctitle(proctitle);
   1928 #endif /* HASSETPROCTITLE */
   1929 
   1930 	if (logging)
   1931 		syslog(LOG_INFO, "connection from %s", remotehost);
   1932 }
   1933 
   1934 /*
   1935  * Record logout in wtmp file
   1936  * and exit with supplied status.
   1937  */
   1938 void
   1939 dologout(status)
   1940 	int status;
   1941 {
   1942 	/*
   1943 	* Prevent reception of SIGURG from resulting in a resumption
   1944 	* back to the main program loop.
   1945 	*/
   1946 	transflag = 0;
   1947 
   1948 	if (logged_in) {
   1949 		(void) seteuid((uid_t)0);
   1950 		logwtmp(ttyline, "", "");
   1951 #ifdef KERBEROS
   1952 		if (!notickets && krbtkfile_env)
   1953 			unlink(krbtkfile_env);
   1954 #endif
   1955 	}
   1956 	/* beware of flushing buffers after a SIGPIPE */
   1957 	_exit(status);
   1958 }
   1959 
   1960 static void
   1961 myoob(signo)
   1962 	int signo;
   1963 {
   1964 	char *cp;
   1965 
   1966 	/* only process if transfer occurring */
   1967 	if (!transflag)
   1968 		return;
   1969 	cp = tmpline;
   1970 	if (getline(cp, 7, stdin) == NULL) {
   1971 		reply(221, "You could at least say goodbye.");
   1972 		dologout(0);
   1973 	}
   1974 	if (strcasecmp(cp, "ABOR\r\n") == 0) {
   1975 		tmpline[0] = '\0';
   1976 		reply(426, "Transfer aborted. Data connection closed.");
   1977 		reply(226, "Abort successful");
   1978 		longjmp(urgcatch, 1);
   1979 	}
   1980 	if (strcasecmp(cp, "STAT\r\n") == 0) {
   1981 		if (file_size != (off_t) -1)
   1982 			reply(213, "Status: %qd of %qd byte%s transferred",
   1983 			    (qdfmt_t)byte_count, (qdfmt_t)file_size,
   1984 			    PLURAL(byte_count));
   1985 		else
   1986 			reply(213, "Status: %qd byte%s transferred",
   1987 			    (qdfmt_t)byte_count, PLURAL(byte_count));
   1988 	}
   1989 }
   1990 
   1991 /*
   1992  * Note: a response of 425 is not mentioned as a possible response to
   1993  *	the PASV command in RFC959. However, it has been blessed as
   1994  *	a legitimate response by Jon Postel in a telephone conversation
   1995  *	with Rick Adams on 25 Jan 89.
   1996  */
   1997 void
   1998 passive()
   1999 {
   2000 	int len;
   2001 	char *p, *a;
   2002 
   2003 	pdata = socket(AF_INET, SOCK_STREAM, 0);
   2004 	if (pdata < 0 || !logged_in) {
   2005 		perror_reply(425, "Can't open passive connection");
   2006 		return;
   2007 	}
   2008 	pasv_addr = ctrl_addr;
   2009 	pasv_addr.su_port = 0;
   2010 	len = pasv_addr.su_len;
   2011 	(void) seteuid((uid_t)0);
   2012 	if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0) {
   2013 		(void) seteuid((uid_t)pw->pw_uid);
   2014 		goto pasv_error;
   2015 	}
   2016 	(void) seteuid((uid_t)pw->pw_uid);
   2017 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
   2018 		goto pasv_error;
   2019 	if (listen(pdata, 1) < 0)
   2020 		goto pasv_error;
   2021 	a = (char *) &pasv_addr.su_sin.sin_addr;
   2022 	p = (char *) &pasv_addr.su_port;
   2023 
   2024 #define UC(b) (((int) b) & 0xff)
   2025 
   2026 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
   2027 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
   2028 	return;
   2029 
   2030 pasv_error:
   2031 	(void) seteuid((uid_t)pw->pw_uid);
   2032 	(void) close(pdata);
   2033 	pdata = -1;
   2034 	perror_reply(425, "Can't open passive connection");
   2035 	return;
   2036 }
   2037 
   2038 /*
   2039  * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
   2040  * 229 Entering Extended Passive Mode (|||port|)
   2041  */
   2042 void
   2043 long_passive(char *cmd, int pf)
   2044 {
   2045 	int len;
   2046 	register char *p, *a;
   2047 
   2048 	if (!logged_in) {
   2049 		syslog(LOG_NOTICE, "long passive but not logged in");
   2050 		reply(503, "Login with USER first.");
   2051 		return;
   2052 	}
   2053 
   2054 	if (pf != PF_UNSPEC) {
   2055 		if (ctrl_addr.su_family != pf) {
   2056 			switch (ctrl_addr.su_family) {
   2057 			case AF_INET:
   2058 				pf = 1;
   2059 				break;
   2060 			case AF_INET6:
   2061 				pf = 2;
   2062 				break;
   2063 			default:
   2064 				pf = 0;
   2065 				break;
   2066 			}
   2067 			/*
   2068 			 * XXX
   2069 			 * only EPRT/EPSV ready clients will understand this
   2070 			 */
   2071 			if (strcmp(cmd, "EPSV") == 0 && pf) {
   2072 				reply(522, "Network protocol mismatch, "
   2073 					    "use (%d)", pf);
   2074 			} else
   2075 				reply(501, "Network protocol mismatch"); /*XXX*/
   2076 
   2077 			return;
   2078 		}
   2079 	}
   2080 
   2081 	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
   2082 	if (pdata < 0) {
   2083 		perror_reply(425, "Can't open passive connection");
   2084 		return;
   2085 	}
   2086 	pasv_addr = ctrl_addr;
   2087 	pasv_addr.su_port = 0;
   2088 	(void) seteuid((uid_t) 0);
   2089 	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
   2090 		(void) seteuid((uid_t) pw->pw_uid);
   2091 		goto pasv_error;
   2092 	}
   2093 	(void) seteuid((uid_t) pw->pw_uid);
   2094 	len = pasv_addr.su_len;
   2095 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
   2096 		goto pasv_error;
   2097 	if (listen(pdata, 1) < 0)
   2098 		goto pasv_error;
   2099 	p = (char *) &pasv_addr.su_port;
   2100 
   2101 #define UC(b) (((int) b) & 0xff)
   2102 
   2103 	if (strcmp(cmd, "LPSV") == 0) {
   2104 		switch (pasv_addr.su_family) {
   2105 		case AF_INET:
   2106 			a = (char *) &pasv_addr.su_sin.sin_addr;
   2107 			reply(228, "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
   2108 				4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
   2109 				2, UC(p[0]), UC(p[1]));
   2110 			return;
   2111 		case AF_INET6:
   2112 			a = (char *) &pasv_addr.su_sin6.sin6_addr;
   2113 			reply(228, "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)",
   2114 				6, 16,
   2115 				UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
   2116 				UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
   2117 				UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
   2118 				UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
   2119 				2, UC(p[0]), UC(p[1]));
   2120 			return;
   2121 		}
   2122 #undef UC
   2123 	} else if (strcmp(cmd, "EPSV") == 0) {
   2124 		switch (pasv_addr.su_family) {
   2125 		case AF_INET:
   2126 		case AF_INET6:
   2127 			reply(229, "Entering Extended Passive Mode (|||%d|)",
   2128 			ntohs(pasv_addr.su_port));
   2129 			return;
   2130 		}
   2131 	} else {
   2132 		/* more proper error code? */
   2133 	}
   2134 
   2135   pasv_error:
   2136 	(void) close(pdata);
   2137 	pdata = -1;
   2138 	perror_reply(425, "Can't open passive connection");
   2139 	return;
   2140 }
   2141 
   2142 /*
   2143  * Generate unique name for file with basename "local".
   2144  * The file named "local" is already known to exist.
   2145  * Generates failure reply on error.
   2146  *
   2147  * XXX this function should under go changes similar to
   2148  * the mktemp(3)/mkstemp(3) changes.
   2149  */
   2150 static char *
   2151 gunique(local)
   2152 	const char *local;
   2153 {
   2154 	static char new[MAXPATHLEN + 1];
   2155 	struct stat st;
   2156 	int count, len;
   2157 	char *cp;
   2158 
   2159 	cp = strrchr(local, '/');
   2160 	if (cp)
   2161 		*cp = '\0';
   2162 	if (stat(cp ? local : ".", &st) < 0) {
   2163 		perror_reply(553, cp ? local : ".");
   2164 		return (NULL);
   2165 	}
   2166 	if (cp)
   2167 		*cp = '/';
   2168 	(void) strcpy(new, local);
   2169 	len = strlen(new);
   2170 	cp = new + len;
   2171 	*cp++ = '.';
   2172 	for (count = 1; count < 100; count++) {
   2173 		(void)snprintf(cp, sizeof(new) - len - 2, "%d", count);
   2174 		if (stat(new, &st) < 0)
   2175 			return (new);
   2176 	}
   2177 	reply(452, "Unique file name cannot be created.");
   2178 	return (NULL);
   2179 }
   2180 
   2181 /*
   2182  * Format and send reply containing system error number.
   2183  */
   2184 void
   2185 perror_reply(code, string)
   2186 	int code;
   2187 	const char *string;
   2188 {
   2189 	int save_errno;
   2190 
   2191 	save_errno = errno;
   2192 	reply(code, "%s: %s.", string, strerror(errno));
   2193 	errno = save_errno;
   2194 }
   2195 
   2196 static char *onefile[] = {
   2197 	"",
   2198 	0
   2199 };
   2200 
   2201 void
   2202 send_file_list(whichf)
   2203 	const char *whichf;
   2204 {
   2205 	struct stat st;
   2206 	DIR *dirp = NULL;
   2207 	struct dirent *dir;
   2208 	FILE *dout = NULL;
   2209 	char **dirlist, *dirname, *p;
   2210 	int simple = 0;
   2211 	int freeglob = 0;
   2212 	glob_t gl;
   2213 	off_t b;
   2214 
   2215 #ifdef __GNUC__
   2216 	(void) &dout;
   2217 	(void) &dirlist;
   2218 	(void) &simple;
   2219 	(void) &freeglob;
   2220 #endif
   2221 
   2222 	p = NULL;
   2223 	if (strpbrk(whichf, "~{[*?") != NULL) {
   2224 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
   2225 
   2226 		memset(&gl, 0, sizeof(gl));
   2227 		freeglob = 1;
   2228 		if (glob(whichf, flags, 0, &gl)) {
   2229 			reply(550, "not found");
   2230 			goto out;
   2231 		} else if (gl.gl_pathc == 0) {
   2232 			errno = ENOENT;
   2233 			perror_reply(550, whichf);
   2234 			goto out;
   2235 		}
   2236 		dirlist = gl.gl_pathv;
   2237 	} else {
   2238 		p = xstrdup(whichf);
   2239 		onefile[0] = p;
   2240 		dirlist = onefile;
   2241 		simple = 1;
   2242 	}
   2243 					/* XXX: } for vi sm */
   2244 
   2245 	if (setjmp(urgcatch)) {
   2246 		transflag = 0;
   2247 		goto out;
   2248 	}
   2249 	while ((dirname = *dirlist++) != NULL) {
   2250 		int trailingslash = 0;
   2251 
   2252 		if (stat(dirname, &st) < 0) {
   2253 			/*
   2254 			 * If user typed "ls -l", etc, and the client
   2255 			 * used NLST, do what the user meant.
   2256 			 */
   2257 			if (dirname[0] == '-' && *dirlist == NULL &&
   2258 			    transflag == 0) {
   2259 				retrieve("/bin/ls %s", dirname);
   2260 				goto out;
   2261 			}
   2262 			perror_reply(550, whichf);
   2263 			if (dout != NULL) {
   2264 				(void) fclose(dout);
   2265 				transflag = 0;
   2266 				data = -1;
   2267 				pdata = -1;
   2268 			}
   2269 			goto out;
   2270 		}
   2271 
   2272 		if (S_ISREG(st.st_mode)) {
   2273 			if (dout == NULL) {
   2274 				dout = dataconn("file list", (off_t)-1, "w");
   2275 				if (dout == NULL)
   2276 					goto out;
   2277 				transflag++;
   2278 			}
   2279 			b = fprintf(dout, "%s%s\n", dirname,
   2280 			    type == TYPE_A ? "\r" : "");
   2281 			total_bytes += b;
   2282 			total_bytes_out += b;
   2283 			byte_count += strlen(dirname) + 1;
   2284 			continue;
   2285 		} else if (!S_ISDIR(st.st_mode))
   2286 			continue;
   2287 
   2288 		if (dirname[strlen(dirname) - 1] == '/')
   2289 			trailingslash++;
   2290 
   2291 		if ((dirp = opendir(dirname)) == NULL)
   2292 			continue;
   2293 
   2294 		while ((dir = readdir(dirp)) != NULL) {
   2295 			char nbuf[MAXPATHLEN + 1];
   2296 
   2297 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
   2298 				continue;
   2299 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
   2300 			    dir->d_namlen == 2)
   2301 				continue;
   2302 
   2303 			(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
   2304 			    trailingslash ? "" : "/", dir->d_name);
   2305 
   2306 			/*
   2307 			 * We have to do a stat to ensure it's
   2308 			 * not a directory or special file.
   2309 			 */
   2310 			if (simple || (stat(nbuf, &st) == 0 &&
   2311 			    S_ISREG(st.st_mode))) {
   2312 				char *p;
   2313 
   2314 				if (dout == NULL) {
   2315 					dout = dataconn("file list", (off_t)-1,
   2316 						"w");
   2317 					if (dout == NULL)
   2318 						goto out;
   2319 					transflag++;
   2320 				}
   2321 				p = nbuf;
   2322 				if (nbuf[0] == '.' && nbuf[1] == '/')
   2323 					p = &nbuf[2];
   2324 				b = fprintf(dout, "%s%s\n", p,
   2325 				    type == TYPE_A ? "\r" : "");
   2326 				total_bytes += b;
   2327 				total_bytes_out += b;
   2328 				byte_count += strlen(nbuf) + 1;
   2329 			}
   2330 		}
   2331 		(void) closedir(dirp);
   2332 	}
   2333 
   2334 	if (dout == NULL)
   2335 		reply(550, "No files found.");
   2336 	else if (ferror(dout) != 0)
   2337 		perror_reply(550, "Data connection");
   2338 	else
   2339 		reply(226, "Transfer complete.");
   2340 
   2341 	transflag = 0;
   2342 	if (dout != NULL)
   2343 		(void) fclose(dout);
   2344 	data = -1;
   2345 	pdata = -1;
   2346 out:
   2347 	total_xfers++;
   2348 	total_xfers_out++;
   2349 	if (p)
   2350 		free(p);
   2351 	if (freeglob)
   2352 		globfree(&gl);
   2353 }
   2354 
   2355 char *
   2356 conffilename(s)
   2357 	const char *s;
   2358 {
   2359 	static char filename[MAXPATHLEN + 1];
   2360 
   2361 	(void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
   2362 	return filename;
   2363 }
   2364 
   2365 /*
   2366  * logcmd --
   2367  *	based on the arguments, syslog a message:
   2368  *	 if bytes != -1		"<command> <file1> = <bytes> bytes"
   2369  *	 else if file2 != NULL	"<command> <file1> <file2>"
   2370  *	 else			"<command> <file1>"
   2371  *	if elapsed != NULL, append "in xxx.yyy seconds"
   2372  *	if error != NULL, append ": " + error
   2373  */
   2374 
   2375 void
   2376 logcmd(command, bytes, file1, file2, elapsed, error)
   2377 	const char		*command;
   2378 	off_t			 bytes;
   2379 	const char		*file1;
   2380 	const char		*file2;
   2381 	const struct timeval	*elapsed;
   2382 	const char		*error;
   2383 {
   2384 	char	buf[MAXPATHLEN + 100], realfile[MAXPATHLEN + 1];
   2385 	const char *p;
   2386 	size_t	len;
   2387 
   2388 	if (logging <=1)
   2389 		return;
   2390 
   2391 	if ((p = realpath(file1, realfile)) == NULL) {
   2392 #if 0	/* XXX: too noisy */
   2393 		syslog(LOG_WARNING, "realpath `%s' failed: %s",
   2394 		    realfile, strerror(errno));
   2395 #endif
   2396 		p = file1;
   2397 	}
   2398 	len = snprintf(buf, sizeof(buf), "%s %s", command, p);
   2399 
   2400 	if (bytes != (off_t)-1) {
   2401 		len += snprintf(buf + len, sizeof(buf) - len,
   2402 		    " = %qd byte%s", (qdfmt_t) bytes, PLURAL(bytes));
   2403 	} else if (file2 != NULL) {
   2404 		if ((p = realpath(file2, realfile)) == NULL) {
   2405 #if 0	/* XXX: too noisy */
   2406 			syslog(LOG_WARNING, "realpath `%s' failed: %s",
   2407 			    realfile, strerror(errno));
   2408 #endif
   2409 			p = file2;
   2410 		}
   2411 		len += snprintf(buf + len, sizeof(buf) - len, " %s", p);
   2412 	}
   2413 
   2414 	if (elapsed != NULL) {
   2415 		len += snprintf(buf + len, sizeof(buf) - len,
   2416 		    " in %ld.%.03d seconds", elapsed->tv_sec,
   2417 		    (int)(elapsed->tv_usec / 1000));
   2418 	}
   2419 
   2420 	if (error != NULL)
   2421 		len += snprintf(buf + len, sizeof(buf) - len, ": %s", error);
   2422 
   2423 	syslog(LOG_INFO, "%s", buf);
   2424 }
   2425 
   2426 char *
   2427 xstrdup(s)
   2428 	const char *s;
   2429 {
   2430 	char *new = strdup(s);
   2431 
   2432 	if (new == NULL)
   2433 		fatal("Local resource failure: malloc");
   2434 		/* NOTREACHED */
   2435 	return (new);
   2436 }
   2437