Home | History | Annotate | Line # | Download | only in ftpd
ftpd.c revision 1.61.2.1
      1  1.61.2.1        he /*	$NetBSD: ftpd.c,v 1.61.2.1 1999/10/01 12:08:06 he Exp $	*/
      2      1.13       cgd 
      3       1.1       cgd /*
      4       1.8   deraadt  * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
      5       1.8   deraadt  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8       1.1       cgd  * modification, are permitted provided that the following conditions
      9       1.1       cgd  * are met:
     10       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15       1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     16       1.1       cgd  *    must display the following acknowledgement:
     17       1.1       cgd  *	This product includes software developed by the University of
     18       1.1       cgd  *	California, Berkeley and its contributors.
     19       1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     20       1.1       cgd  *    may be used to endorse or promote products derived from this software
     21       1.1       cgd  *    without specific prior written permission.
     22       1.1       cgd  *
     23       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33       1.1       cgd  * SUCH DAMAGE.
     34       1.1       cgd  */
     35       1.1       cgd 
     36      1.25  christos #include <sys/cdefs.h>
     37       1.1       cgd #ifndef lint
     38      1.25  christos __COPYRIGHT(
     39       1.8   deraadt "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
     40      1.25  christos 	The Regents of the University of California.  All rights reserved.\n");
     41       1.1       cgd #endif /* not lint */
     42       1.1       cgd 
     43       1.1       cgd #ifndef lint
     44      1.13       cgd #if 0
     45      1.17       cjs static char sccsid[] = "@(#)ftpd.c	8.5 (Berkeley) 4/28/95";
     46      1.13       cgd #else
     47  1.61.2.1        he __RCSID("$NetBSD: ftpd.c,v 1.61.2.1 1999/10/01 12:08:06 he Exp $");
     48      1.13       cgd #endif
     49       1.1       cgd #endif /* not lint */
     50       1.1       cgd 
     51       1.1       cgd /*
     52       1.1       cgd  * FTP server.
     53       1.1       cgd  */
     54       1.1       cgd #include <sys/param.h>
     55       1.1       cgd #include <sys/stat.h>
     56       1.1       cgd #include <sys/ioctl.h>
     57       1.1       cgd #include <sys/socket.h>
     58       1.1       cgd #include <sys/wait.h>
     59       1.1       cgd 
     60       1.1       cgd #include <netinet/in.h>
     61       1.1       cgd #include <netinet/in_systm.h>
     62       1.1       cgd #include <netinet/ip.h>
     63       1.1       cgd 
     64       1.1       cgd #define	FTP_NAMES
     65       1.1       cgd #include <arpa/ftp.h>
     66       1.1       cgd #include <arpa/inet.h>
     67       1.1       cgd #include <arpa/telnet.h>
     68       1.1       cgd 
     69       1.8   deraadt #include <ctype.h>
     70       1.1       cgd #include <dirent.h>
     71       1.8   deraadt #include <err.h>
     72       1.8   deraadt #include <errno.h>
     73       1.1       cgd #include <fcntl.h>
     74      1.21       cjs #include <fnmatch.h>
     75       1.8   deraadt #include <glob.h>
     76       1.8   deraadt #include <limits.h>
     77       1.8   deraadt #include <netdb.h>
     78       1.1       cgd #include <pwd.h>
     79       1.1       cgd #include <setjmp.h>
     80       1.8   deraadt #include <signal.h>
     81       1.1       cgd #include <stdio.h>
     82       1.1       cgd #include <stdlib.h>
     83       1.1       cgd #include <string.h>
     84       1.8   deraadt #include <syslog.h>
     85       1.8   deraadt #include <time.h>
     86       1.8   deraadt #include <unistd.h>
     87      1.25  christos #ifdef SKEY
     88      1.25  christos #include <skey.h>
     89      1.25  christos #endif
     90      1.38   mycroft #ifdef KERBEROS5
     91      1.38   mycroft #include <krb5.h>
     92      1.38   mycroft #endif
     93       1.8   deraadt 
     94      1.24     lukem #include "extern.h"
     95       1.1       cgd #include "pathnames.h"
     96       1.1       cgd 
     97       1.8   deraadt #if __STDC__
     98       1.8   deraadt #include <stdarg.h>
     99       1.8   deraadt #else
    100       1.8   deraadt #include <varargs.h>
    101       1.8   deraadt #endif
    102      1.58     lukem 
    103      1.58     lukem #ifndef TRUE
    104      1.58     lukem #define TRUE	1
    105      1.58     lukem #define FALSE	0
    106      1.58     lukem #endif
    107       1.8   deraadt 
    108      1.60     lukem const char version[] = "Version: 7.1.0";
    109       1.1       cgd 
    110       1.1       cgd struct	sockaddr_in ctrl_addr;
    111       1.1       cgd struct	sockaddr_in data_source;
    112       1.1       cgd struct	sockaddr_in data_dest;
    113       1.1       cgd struct	sockaddr_in his_addr;
    114       1.1       cgd struct	sockaddr_in pasv_addr;
    115       1.1       cgd 
    116       1.1       cgd int	data;
    117       1.1       cgd jmp_buf	errcatch, urgcatch;
    118       1.1       cgd int	logged_in;
    119       1.1       cgd struct	passwd *pw;
    120       1.1       cgd int	debug;
    121      1.51   msaitoh int	sflag;
    122       1.1       cgd int	logging;
    123       1.1       cgd int	guest;
    124       1.5       cgd int	dochroot;
    125       1.1       cgd int	type;
    126       1.1       cgd int	form;
    127       1.1       cgd int	stru;			/* avoid C keyword */
    128       1.1       cgd int	mode;
    129       1.1       cgd int	usedefault = 1;		/* for data transfers */
    130       1.1       cgd int	pdata = -1;		/* for passive mode */
    131       1.8   deraadt sig_atomic_t transflag;
    132       1.1       cgd off_t	file_size;
    133       1.1       cgd off_t	byte_count;
    134       1.1       cgd char	tmpline[7];
    135      1.52       mrg char	hostname[MAXHOSTNAMELEN+1];
    136      1.52       mrg char	remotehost[MAXHOSTNAMELEN+1];
    137      1.13       cgd static char ttyline[20];
    138      1.13       cgd char	*tty = ttyline;		/* for klogin */
    139      1.57     lukem 
    140      1.22       cjs static char *anondir = NULL;
    141      1.34     lukem static char confdir[MAXPATHLEN];
    142      1.24     lukem 
    143      1.38   mycroft #if defined(KERBEROS) || defined(KERBEROS5)
    144      1.13       cgd int	notickets = 1;
    145      1.13       cgd char	*krbtkfile_env = NULL;
    146       1.4       cgd #endif
    147       1.4       cgd 
    148       1.1       cgd /*
    149       1.1       cgd  * Timeout intervals for retrying connections
    150       1.1       cgd  * to hosts that don't accept PORT cmds.  This
    151       1.1       cgd  * is a kludge, but given the problems with TCP...
    152       1.1       cgd  */
    153       1.1       cgd #define	SWAITMAX	90	/* wait at most 90 seconds */
    154       1.1       cgd #define	SWAITINT	5	/* interval between retries */
    155       1.1       cgd 
    156       1.1       cgd int	swaitmax = SWAITMAX;
    157       1.1       cgd int	swaitint = SWAITINT;
    158       1.1       cgd 
    159       1.6       cgd #ifdef HASSETPROCTITLE
    160       1.1       cgd char	proctitle[BUFSIZ];	/* initial part of title */
    161       1.6       cgd #endif /* HASSETPROCTITLE */
    162       1.1       cgd 
    163       1.8   deraadt static void	 ack __P((char *));
    164       1.8   deraadt static void	 myoob __P((int));
    165      1.58     lukem static int	 checkuser __P((const char *, const char *, int, int));
    166      1.54   mycroft static int	 checkaccess __P((const char *));
    167       1.8   deraadt static FILE	*dataconn __P((char *, off_t, char *));
    168       1.8   deraadt static void	 dolog __P((struct sockaddr_in *));
    169       1.8   deraadt static void	 end_login __P((void));
    170       1.8   deraadt static FILE	*getdatasock __P((char *));
    171       1.8   deraadt static char	*gunique __P((char *));
    172       1.8   deraadt static void	 lostconn __P((int));
    173       1.8   deraadt static int	 receive_data __P((FILE *, FILE *));
    174      1.33     lukem static void	 replydirname __P((const char *, const char *));
    175      1.49     lukem static int	 send_data __P((FILE *, FILE *, off_t));
    176       1.8   deraadt static struct passwd *
    177      1.54   mycroft 		 sgetpwnam __P((const char *));
    178       1.8   deraadt 
    179      1.42     lukem int	main __P((int, char *[]));
    180      1.26    mellon 
    181      1.38   mycroft #if defined(KERBEROS) || defined(KERBEROS5)
    182      1.38   mycroft int	klogin __P((struct passwd *, char *, char *, char *));
    183      1.38   mycroft void	kdestroy __P((void));
    184      1.26    mellon #endif
    185       1.8   deraadt int
    186      1.42     lukem main(argc, argv)
    187       1.1       cgd 	int argc;
    188       1.1       cgd 	char *argv[];
    189       1.1       cgd {
    190       1.8   deraadt 	int addrlen, ch, on = 1, tos;
    191       1.8   deraadt 	char *cp, line[LINE_MAX];
    192       1.8   deraadt 	FILE *fd;
    193      1.38   mycroft #ifdef KERBEROS5
    194      1.38   mycroft 	krb5_error_code kerror;
    195      1.38   mycroft #endif
    196       1.1       cgd 
    197       1.1       cgd 	debug = 0;
    198      1.35     lukem 	logging = 0;
    199      1.51   msaitoh 	sflag = 0;
    200      1.34     lukem 	(void)strcpy(confdir, _DEFAULT_CONFDIR);
    201       1.1       cgd 
    202      1.51   msaitoh 	while ((ch = getopt(argc, argv, "a:c:C:dlst:T:u:v")) != -1) {
    203       1.8   deraadt 		switch (ch) {
    204      1.22       cjs 		case 'a':
    205      1.22       cjs 			anondir = optarg;
    206      1.22       cjs 			break;
    207      1.22       cjs 
    208      1.34     lukem 		case 'c':
    209      1.34     lukem 			(void)strncpy(confdir, optarg, sizeof(confdir));
    210      1.34     lukem 			confdir[sizeof(confdir)-1] = '\0';
    211      1.34     lukem 			break;
    212      1.35     lukem 
    213      1.35     lukem 		case 'C':
    214      1.35     lukem 			exit(checkaccess(optarg));
    215      1.35     lukem 			/* NOTREACHED */
    216      1.34     lukem 
    217       1.1       cgd 		case 'd':
    218      1.22       cjs 		case 'v':		/* deprecated */
    219       1.1       cgd 			debug = 1;
    220       1.1       cgd 			break;
    221       1.1       cgd 
    222       1.1       cgd 		case 'l':
    223       1.8   deraadt 			logging++;	/* > 1 == extra logging */
    224       1.1       cgd 			break;
    225       1.1       cgd 
    226      1.51   msaitoh 		case 's':
    227      1.51   msaitoh 			sflag = 1;
    228      1.51   msaitoh 			break;
    229      1.51   msaitoh 
    230       1.1       cgd 		case 't':
    231       1.1       cgd 		case 'T':
    232       1.1       cgd 		case 'u':
    233      1.32     lukem 			warnx("-%c has been deprecated in favour of ftpd.conf",
    234      1.24     lukem 			    ch);
    235       1.8   deraadt 			break;
    236       1.1       cgd 
    237       1.1       cgd 		default:
    238      1.35     lukem 			if (optopt == 'a' || optopt == 'C')
    239      1.35     lukem 				exit(1);
    240       1.8   deraadt 			warnx("unknown flag -%c ignored", optopt);
    241       1.1       cgd 			break;
    242       1.1       cgd 		}
    243       1.1       cgd 	}
    244      1.35     lukem 
    245      1.35     lukem 	/*
    246      1.35     lukem 	 * LOG_NDELAY sets up the logging connection immediately,
    247      1.35     lukem 	 * necessary for anonymous ftp's that chroot and can't do it later.
    248      1.35     lukem 	 */
    249      1.35     lukem 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
    250      1.35     lukem 	addrlen = sizeof(his_addr);
    251      1.35     lukem 	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
    252      1.35     lukem 		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
    253      1.35     lukem 		exit(1);
    254      1.35     lukem 	}
    255      1.35     lukem 	addrlen = sizeof(ctrl_addr);
    256      1.35     lukem 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
    257      1.35     lukem 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
    258      1.35     lukem 		exit(1);
    259      1.35     lukem 	}
    260      1.35     lukem #ifdef IP_TOS
    261      1.35     lukem 	tos = IPTOS_LOWDELAY;
    262      1.35     lukem 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
    263      1.35     lukem 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
    264      1.35     lukem #endif
    265      1.35     lukem 	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
    266      1.35     lukem 
    267      1.35     lukem 	/* set this here so klogin can use it... */
    268      1.35     lukem 	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
    269      1.35     lukem 
    270       1.1       cgd 	(void) freopen(_PATH_DEVNULL, "w", stderr);
    271       1.1       cgd 	(void) signal(SIGPIPE, lostconn);
    272       1.1       cgd 	(void) signal(SIGCHLD, SIG_IGN);
    273      1.10       cgd 	if ((long)signal(SIGURG, myoob) < 0)
    274       1.1       cgd 		syslog(LOG_ERR, "signal: %m");
    275       1.1       cgd 
    276       1.1       cgd 	/* Try to handle urgent data inline */
    277       1.1       cgd #ifdef SO_OOBINLINE
    278       1.1       cgd 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
    279       1.1       cgd 		syslog(LOG_ERR, "setsockopt: %m");
    280       1.1       cgd #endif
    281       1.1       cgd 
    282       1.1       cgd #ifdef	F_SETOWN
    283       1.1       cgd 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
    284       1.1       cgd 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
    285       1.1       cgd #endif
    286       1.1       cgd 	dolog(&his_addr);
    287       1.1       cgd 	/*
    288       1.1       cgd 	 * Set up default state
    289       1.1       cgd 	 */
    290       1.1       cgd 	data = -1;
    291       1.1       cgd 	type = TYPE_A;
    292       1.1       cgd 	form = FORM_N;
    293       1.1       cgd 	stru = STRU_F;
    294       1.1       cgd 	mode = MODE_S;
    295       1.1       cgd 	tmpline[0] = '\0';
    296      1.57     lukem 	hasyyerrored = 0;
    297       1.8   deraadt 
    298      1.38   mycroft #ifdef KERBEROS5
    299      1.38   mycroft 	kerror = krb5_init_context(&kcontext);
    300      1.38   mycroft 	if (kerror) {
    301      1.38   mycroft 		syslog(LOG_NOTICE, "%s when initializing Kerberos context",
    302      1.38   mycroft 		    error_message(kerror));
    303      1.38   mycroft 		exit(0);
    304      1.38   mycroft 	}
    305      1.45  christos #endif /* KERBEROS5 */
    306      1.38   mycroft 
    307       1.8   deraadt 	/* If logins are disabled, print out the message. */
    308       1.8   deraadt 	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
    309       1.8   deraadt 		while (fgets(line, sizeof(line), fd) != NULL) {
    310       1.8   deraadt 			if ((cp = strchr(line, '\n')) != NULL)
    311       1.8   deraadt 				*cp = '\0';
    312       1.8   deraadt 			lreply(530, "%s", line);
    313       1.8   deraadt 		}
    314       1.8   deraadt 		(void) fflush(stdout);
    315       1.8   deraadt 		(void) fclose(fd);
    316       1.8   deraadt 		reply(530, "System not available.");
    317       1.8   deraadt 		exit(0);
    318       1.8   deraadt 	}
    319      1.34     lukem 	if ((fd = fopen(conffilename(_PATH_FTPWELCOME), "r")) != NULL) {
    320       1.8   deraadt 		while (fgets(line, sizeof(line), fd) != NULL) {
    321       1.8   deraadt 			if ((cp = strchr(line, '\n')) != NULL)
    322       1.8   deraadt 				*cp = '\0';
    323       1.8   deraadt 			lreply(220, "%s", line);
    324       1.8   deraadt 		}
    325       1.8   deraadt 		(void) fflush(stdout);
    326       1.8   deraadt 		(void) fclose(fd);
    327       1.8   deraadt 		/* reply(220,) must follow */
    328       1.8   deraadt 	}
    329      1.52       mrg 	(void)gethostname(hostname, sizeof(hostname));
    330      1.52       mrg 	hostname[sizeof(hostname) - 1] = '\0';
    331       1.1       cgd 	reply(220, "%s FTP server (%s) ready.", hostname, version);
    332      1.57     lukem 	curclass.timeout = 300;		/* 5 minutes, as per login(1) */
    333       1.1       cgd 	(void) setjmp(errcatch);
    334       1.1       cgd 	for (;;)
    335       1.1       cgd 		(void) yyparse();
    336       1.1       cgd 	/* NOTREACHED */
    337       1.1       cgd }
    338       1.1       cgd 
    339       1.8   deraadt static void
    340       1.8   deraadt lostconn(signo)
    341       1.8   deraadt 	int signo;
    342       1.1       cgd {
    343       1.8   deraadt 
    344       1.1       cgd 	if (debug)
    345       1.1       cgd 		syslog(LOG_DEBUG, "lost connection");
    346      1.35     lukem 	dologout(1);
    347       1.1       cgd }
    348       1.1       cgd 
    349       1.1       cgd /*
    350       1.1       cgd  * Save the result of a getpwnam.  Used for USER command, since
    351       1.1       cgd  * the data returned must not be clobbered by any other command
    352       1.1       cgd  * (e.g., globbing).
    353       1.1       cgd  */
    354       1.8   deraadt static struct passwd *
    355       1.1       cgd sgetpwnam(name)
    356      1.54   mycroft 	const char *name;
    357       1.1       cgd {
    358       1.1       cgd 	static struct passwd save;
    359       1.8   deraadt 	struct passwd *p;
    360       1.1       cgd 
    361       1.1       cgd 	if ((p = getpwnam(name)) == NULL)
    362       1.1       cgd 		return (p);
    363       1.1       cgd 	if (save.pw_name) {
    364      1.54   mycroft 		free((char *)save.pw_name);
    365      1.54   mycroft 		free((char *)save.pw_passwd);
    366      1.54   mycroft 		free((char *)save.pw_gecos);
    367      1.54   mycroft 		free((char *)save.pw_dir);
    368      1.54   mycroft 		free((char *)save.pw_shell);
    369       1.1       cgd 	}
    370       1.1       cgd 	save = *p;
    371      1.58     lukem 	save.pw_name = xstrdup(p->pw_name);
    372      1.58     lukem 	save.pw_passwd = xstrdup(p->pw_passwd);
    373      1.58     lukem 	save.pw_gecos = xstrdup(p->pw_gecos);
    374      1.58     lukem 	save.pw_dir = xstrdup(p->pw_dir);
    375      1.58     lukem 	save.pw_shell = xstrdup(p->pw_shell);
    376       1.1       cgd 	return (&save);
    377       1.1       cgd }
    378       1.1       cgd 
    379       1.8   deraadt static int login_attempts;	/* number of failed login attempts */
    380       1.8   deraadt static int askpasswd;		/* had user command, ask for passwd */
    381       1.8   deraadt static char curname[10];	/* current USER name */
    382       1.1       cgd 
    383       1.1       cgd /*
    384       1.1       cgd  * USER command.
    385       1.1       cgd  * Sets global passwd pointer pw if named account exists and is acceptable;
    386       1.1       cgd  * sets askpasswd if a PASS command is expected.  If logged in previously,
    387       1.1       cgd  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
    388       1.1       cgd  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
    389       1.1       cgd  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
    390       1.1       cgd  * requesting login privileges.  Disallow anyone who does not have a standard
    391       1.1       cgd  * shell as returned by getusershell().  Disallow anyone mentioned in the file
    392       1.1       cgd  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
    393       1.1       cgd  */
    394       1.8   deraadt void
    395       1.1       cgd user(name)
    396       1.1       cgd 	char *name;
    397       1.1       cgd {
    398       1.1       cgd 	if (logged_in) {
    399       1.1       cgd 		if (guest) {
    400       1.1       cgd 			reply(530, "Can't change user from guest login.");
    401       1.1       cgd 			return;
    402       1.5       cgd 		} else if (dochroot) {
    403       1.5       cgd 			reply(530, "Can't change user from chroot user.");
    404       1.5       cgd 			return;
    405       1.1       cgd 		}
    406       1.1       cgd 		end_login();
    407       1.1       cgd 	}
    408       1.1       cgd 
    409      1.38   mycroft #if defined(KERBEROS) || defined(KERBEROS5)
    410      1.38   mycroft 	kdestroy();
    411      1.38   mycroft #endif
    412      1.38   mycroft 
    413       1.1       cgd 	guest = 0;
    414       1.1       cgd 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
    415      1.19       cjs 		if (checkaccess("ftp") || checkaccess("anonymous"))
    416       1.1       cgd 			reply(530, "User %s access denied.", name);
    417       1.1       cgd 		else if ((pw = sgetpwnam("ftp")) != NULL) {
    418       1.1       cgd 			guest = 1;
    419       1.1       cgd 			askpasswd = 1;
    420       1.8   deraadt 			reply(331,
    421       1.8   deraadt 			    "Guest login ok, type your name as password.");
    422       1.1       cgd 		} else
    423       1.1       cgd 			reply(530, "User %s unknown.", name);
    424       1.8   deraadt 		if (!askpasswd && logging)
    425       1.8   deraadt 			syslog(LOG_NOTICE,
    426       1.8   deraadt 			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
    427       1.1       cgd 		return;
    428       1.1       cgd 	}
    429      1.34     lukem 
    430      1.19       cjs 	pw = sgetpwnam(name);
    431       1.8   deraadt 	if (logging)
    432       1.8   deraadt 		strncpy(curname, name, sizeof(curname)-1);
    433      1.36   mycroft 
    434       1.7   deraadt #ifdef SKEY
    435      1.36   mycroft 	if (skey_haskey(name) == 0) {
    436      1.36   mycroft 		char *myskey;
    437       1.7   deraadt 
    438       1.8   deraadt 		myskey = skey_keyinfo(name);
    439      1.36   mycroft 		reply(331, "Password [%s] required for %s.",
    440       1.8   deraadt 		    myskey ? myskey : "error getting challenge", name);
    441       1.7   deraadt 	} else
    442       1.7   deraadt #endif
    443       1.7   deraadt 		reply(331, "Password required for %s.", name);
    444       1.7   deraadt 
    445       1.1       cgd 	askpasswd = 1;
    446       1.1       cgd 	/*
    447       1.1       cgd 	 * Delay before reading passwd after first failed
    448       1.1       cgd 	 * attempt to slow down passwd-guessing programs.
    449       1.1       cgd 	 */
    450       1.1       cgd 	if (login_attempts)
    451       1.1       cgd 		sleep((unsigned) login_attempts);
    452       1.1       cgd }
    453       1.1       cgd 
    454       1.1       cgd /*
    455      1.58     lukem  * Determine whether something is to happen (allow access, chroot)
    456      1.58     lukem  * for a user. Each line is a shell-style glob followed by
    457      1.58     lukem  * `yes' or `no'.
    458      1.58     lukem  *
    459      1.58     lukem  * For backward compatability, `allow' and `deny' are synonymns
    460      1.58     lukem  * for `yes' and `no', respectively.
    461      1.19       cjs  *
    462      1.21       cjs  * Each glob is matched against the username in turn, and the first
    463      1.58     lukem  * match found is used. If no match is found, the result is the
    464      1.58     lukem  * argument `def'. If a match is found but without and explicit
    465      1.58     lukem  * `yes'/`no', the result is the opposite of def.
    466      1.58     lukem  *
    467      1.58     lukem  * If the file doesn't exist at all, the result is the argument
    468      1.58     lukem  * `nofile'
    469      1.21       cjs  *
    470      1.21       cjs  * Any line starting with `#' is considered a comment and ignored.
    471      1.19       cjs  *
    472      1.58     lukem  * Returns FALSE if the user is denied, or TRUE if they are allowed.
    473      1.19       cjs  */
    474      1.58     lukem int
    475      1.58     lukem checkuser(fname, name, def, nofile)
    476      1.58     lukem 	const char *fname, *name;
    477      1.58     lukem 	int def, nofile;
    478      1.58     lukem {
    479      1.58     lukem 	FILE	*fd;
    480      1.58     lukem 	int	 retval;
    481      1.58     lukem 	char	*glob, *perm, line[BUFSIZ];
    482      1.58     lukem 
    483      1.58     lukem 	retval = def;
    484      1.58     lukem 	if ((fd = fopen(conffilename(fname), "r")) == NULL)
    485      1.58     lukem 		return nofile;
    486      1.19       cjs 
    487      1.19       cjs 	while (fgets(line, sizeof(line), fd) != NULL)  {
    488      1.21       cjs 		glob = strtok(line, " \t\n");
    489  1.61.2.1        he 		if (glob == NULL || glob[0] == '#')
    490      1.19       cjs 			continue;
    491      1.19       cjs 		perm = strtok(NULL, " \t\n");
    492  1.61.2.1        he 		if (perm == NULL)
    493  1.61.2.1        he 			continue;
    494      1.21       cjs 		if (fnmatch(glob, name, 0) == 0)  {
    495      1.58     lukem 			if (perm != NULL &&
    496      1.58     lukem 			    ((strcasecmp(perm, "allow") == 0) ||
    497      1.58     lukem 			    (strcasecmp(perm, "yes") == 0)))
    498      1.58     lukem 				retval = TRUE;
    499      1.58     lukem 			else if (perm != NULL &&
    500      1.58     lukem 			    ((strcasecmp(perm, "deny") == 0) ||
    501      1.58     lukem 			    (strcasecmp(perm, "no") == 0)))
    502      1.58     lukem 				retval = FALSE;
    503      1.19       cjs 			else
    504      1.58     lukem 				retval = !def;
    505      1.21       cjs 			break;
    506      1.19       cjs 		}
    507      1.19       cjs 	}
    508      1.19       cjs 	(void) fclose(fd);
    509      1.21       cjs 	return (retval);
    510      1.19       cjs }
    511      1.58     lukem 
    512      1.58     lukem /*
    513      1.58     lukem  * Check if user is allowed by /etc/ftpusers
    514      1.58     lukem  * returns 0 for yes, 1 for no
    515      1.58     lukem  */
    516      1.58     lukem int
    517      1.58     lukem checkaccess(name)
    518      1.58     lukem 	const char *name;
    519      1.58     lukem {
    520      1.58     lukem 
    521      1.58     lukem 	return (! checkuser(_PATH_FTPUSERS, name, TRUE, FALSE));
    522      1.58     lukem }
    523      1.19       cjs 
    524      1.19       cjs /*
    525       1.1       cgd  * Terminate login as previous user, if any, resetting state;
    526       1.1       cgd  * used when USER command is given or login fails.
    527       1.1       cgd  */
    528       1.8   deraadt static void
    529       1.1       cgd end_login()
    530       1.1       cgd {
    531       1.1       cgd 
    532       1.1       cgd 	(void) seteuid((uid_t)0);
    533       1.1       cgd 	if (logged_in)
    534       1.1       cgd 		logwtmp(ttyline, "", "");
    535       1.1       cgd 	pw = NULL;
    536       1.1       cgd 	logged_in = 0;
    537       1.1       cgd 	guest = 0;
    538       1.5       cgd 	dochroot = 0;
    539       1.1       cgd }
    540       1.1       cgd 
    541       1.8   deraadt void
    542       1.1       cgd pass(passwd)
    543       1.1       cgd 	char *passwd;
    544       1.1       cgd {
    545       1.4       cgd 	int rval;
    546       1.8   deraadt 	FILE *fd;
    547      1.53   mycroft 	char const *cp, *shell, *home;
    548       1.1       cgd 
    549       1.1       cgd 	if (logged_in || askpasswd == 0) {
    550       1.1       cgd 		reply(503, "Login with USER first.");
    551       1.1       cgd 		return;
    552       1.1       cgd 	}
    553       1.1       cgd 	askpasswd = 0;
    554       1.1       cgd 	if (!guest) {		/* "ftp" is only account allowed no password */
    555       1.8   deraadt 		if (pw == NULL) {
    556       1.8   deraadt 			rval = 1;	/* failure below */
    557       1.8   deraadt 			goto skip;
    558       1.8   deraadt 		}
    559      1.37   mycroft #ifdef KERBEROS
    560      1.38   mycroft 		if (klogin(pw, "", hostname, passwd) == 0) {
    561      1.38   mycroft 			rval = 0;
    562      1.38   mycroft 			goto skip;
    563      1.38   mycroft 		}
    564      1.38   mycroft #endif
    565      1.38   mycroft #ifdef KERBEROS5
    566      1.37   mycroft 		if (klogin(pw, "", hostname, passwd) == 0) {
    567      1.37   mycroft 			rval = 0;
    568      1.37   mycroft 			goto skip;
    569      1.37   mycroft 		}
    570      1.37   mycroft #endif
    571      1.36   mycroft #ifdef SKEY
    572      1.36   mycroft 		if (skey_haskey(pw->pw_name) == 0 &&
    573      1.36   mycroft 		    skey_passcheck(pw->pw_name, passwd) != -1) {
    574      1.36   mycroft 			rval = 0;
    575       1.8   deraadt 			goto skip;
    576      1.36   mycroft 		}
    577       1.4       cgd #endif
    578      1.51   msaitoh 		if (!sflag && *pw->pw_passwd != '\0' &&
    579      1.37   mycroft 		    !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
    580       1.8   deraadt 			rval = 0;
    581       1.8   deraadt 			goto skip;
    582       1.8   deraadt 		}
    583      1.37   mycroft 		rval = 1;
    584       1.4       cgd 
    585       1.8   deraadt skip:
    586      1.46       cjs 		if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire)
    587      1.45  christos 			rval = 2;
    588       1.4       cgd 		/*
    589      1.45  christos 		 * If rval > 0, the user failed the authentication check
    590       1.4       cgd 		 * above.  If rval == 0, either Kerberos or local authentication
    591       1.4       cgd 		 * succeeded.
    592       1.4       cgd 		 */
    593       1.4       cgd 		if (rval) {
    594      1.45  christos 			reply(530, rval == 2 ? "Password expired." :
    595      1.45  christos 			    "Login incorrect.");
    596      1.23     lukem 			if (logging) {
    597       1.8   deraadt 				syslog(LOG_NOTICE,
    598      1.23     lukem 				    "FTP LOGIN FAILED FROM %s", remotehost);
    599      1.23     lukem 				syslog(LOG_AUTHPRIV | LOG_NOTICE,
    600       1.8   deraadt 				    "FTP LOGIN FAILED FROM %s, %s",
    601       1.8   deraadt 				    remotehost, curname);
    602      1.23     lukem 			}
    603       1.1       cgd 			pw = NULL;
    604       1.1       cgd 			if (login_attempts++ >= 5) {
    605       1.1       cgd 				syslog(LOG_NOTICE,
    606       1.1       cgd 				    "repeated login failures from %s",
    607       1.1       cgd 				    remotehost);
    608       1.1       cgd 				exit(0);
    609       1.1       cgd 			}
    610       1.1       cgd 			return;
    611       1.1       cgd 		}
    612       1.1       cgd 	}
    613      1.19       cjs 
    614      1.19       cjs 	/* password was ok; see if anything else prevents login */
    615      1.19       cjs 	if (checkaccess(pw->pw_name))  {
    616      1.19       cjs 		reply(530, "User %s may not use FTP.", pw->pw_name);
    617      1.19       cjs 		if (logging)
    618      1.19       cjs 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
    619      1.19       cjs 			    remotehost, pw->pw_name);
    620      1.19       cjs 		pw = (struct passwd *) NULL;
    621      1.19       cjs 		return;
    622      1.19       cjs 	}
    623      1.19       cjs 	/* check for valid shell, if not guest user */
    624      1.19       cjs 	if ((shell = pw->pw_shell) == NULL || *shell == 0)
    625      1.19       cjs 		shell = _PATH_BSHELL;
    626      1.19       cjs 	while ((cp = getusershell()) != NULL)
    627      1.19       cjs 		if (strcmp(cp, shell) == 0)
    628      1.19       cjs 			break;
    629      1.19       cjs 	endusershell();
    630      1.19       cjs 	if (cp == NULL && guest == 0) {
    631      1.19       cjs 		reply(530, "User %s may not use FTP.", pw->pw_name);
    632      1.19       cjs 		if (logging)
    633      1.19       cjs 			syslog(LOG_NOTICE,
    634      1.19       cjs 			    "FTP LOGIN REFUSED FROM %s, %s",
    635      1.19       cjs 			    remotehost, pw->pw_name);
    636      1.19       cjs 		pw = (struct passwd *) NULL;
    637      1.19       cjs 		return;
    638      1.19       cjs 	}
    639      1.19       cjs 
    640       1.1       cgd 	login_attempts = 0;		/* this time successful */
    641       1.8   deraadt 	if (setegid((gid_t)pw->pw_gid) < 0) {
    642       1.8   deraadt 		reply(550, "Can't set gid.");
    643       1.8   deraadt 		return;
    644       1.8   deraadt 	}
    645       1.1       cgd 	(void) initgroups(pw->pw_name, pw->pw_gid);
    646       1.1       cgd 
    647       1.1       cgd 	/* open wtmp before chroot */
    648       1.1       cgd 	logwtmp(ttyline, pw->pw_name, remotehost);
    649       1.1       cgd 	logged_in = 1;
    650       1.1       cgd 
    651      1.58     lukem 	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name, FALSE, FALSE);
    652      1.24     lukem 
    653      1.24     lukem 	/* parse ftpd.conf, setting up various parameters */
    654      1.24     lukem 	if (guest)
    655      1.24     lukem 		parse_conf(CLASS_GUEST);
    656      1.24     lukem 	else if (dochroot)
    657      1.24     lukem 		parse_conf(CLASS_CHROOT);
    658      1.24     lukem 	else
    659      1.24     lukem 		parse_conf(CLASS_REAL);
    660      1.24     lukem 
    661      1.44     lukem 	home = "/";
    662       1.1       cgd 	if (guest) {
    663       1.1       cgd 		/*
    664       1.1       cgd 		 * We MUST do a chdir() after the chroot. Otherwise
    665       1.1       cgd 		 * the old current directory will be accessible as "."
    666       1.1       cgd 		 * outside the new root!
    667       1.1       cgd 		 */
    668      1.24     lukem 		if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
    669      1.24     lukem 		    chdir("/") < 0) {
    670       1.1       cgd 			reply(550, "Can't set guest privileges.");
    671       1.5       cgd 			goto bad;
    672       1.5       cgd 		}
    673       1.5       cgd 	} else if (dochroot) {
    674       1.5       cgd 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
    675       1.5       cgd 			reply(550, "Can't change root.");
    676       1.1       cgd 			goto bad;
    677       1.1       cgd 		}
    678       1.1       cgd 	} else if (chdir(pw->pw_dir) < 0) {
    679       1.1       cgd 		if (chdir("/") < 0) {
    680       1.1       cgd 			reply(530, "User %s: can't change directory to %s.",
    681       1.1       cgd 			    pw->pw_name, pw->pw_dir);
    682       1.1       cgd 			goto bad;
    683       1.1       cgd 		} else
    684       1.1       cgd 			lreply(230, "No directory! Logging in with home=/");
    685      1.44     lukem 	} else
    686      1.44     lukem 		home = pw->pw_dir;
    687       1.1       cgd 	if (seteuid((uid_t)pw->pw_uid) < 0) {
    688       1.1       cgd 		reply(550, "Can't set uid.");
    689       1.1       cgd 		goto bad;
    690       1.1       cgd 	}
    691      1.44     lukem 	setenv("HOME", home, 1);
    692      1.44     lukem 
    693      1.44     lukem 
    694       1.8   deraadt 	/*
    695       1.8   deraadt 	 * Display a login message, if it exists.
    696       1.8   deraadt 	 * N.B. reply(230,) must follow the message.
    697       1.8   deraadt 	 */
    698      1.34     lukem 	if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) {
    699       1.8   deraadt 		char *cp, line[LINE_MAX];
    700       1.8   deraadt 
    701       1.8   deraadt 		while (fgets(line, sizeof(line), fd) != NULL) {
    702       1.8   deraadt 			if ((cp = strchr(line, '\n')) != NULL)
    703       1.8   deraadt 				*cp = '\0';
    704       1.8   deraadt 			lreply(230, "%s", line);
    705       1.8   deraadt 		}
    706       1.8   deraadt 		(void) fflush(stdout);
    707       1.8   deraadt 		(void) fclose(fd);
    708       1.8   deraadt 	}
    709      1.24     lukem 	show_chdir_messages(230);
    710       1.1       cgd 	if (guest) {
    711       1.1       cgd 		reply(230, "Guest login ok, access restrictions apply.");
    712       1.6       cgd #ifdef HASSETPROCTITLE
    713       1.8   deraadt 		snprintf(proctitle, sizeof(proctitle),
    714       1.8   deraadt 		    "%s: anonymous/%.*s", remotehost,
    715      1.25  christos 		    (int) (sizeof(proctitle) - sizeof(remotehost) -
    716      1.25  christos 		    sizeof(": anonymous/")), passwd);
    717       1.1       cgd 		setproctitle(proctitle);
    718       1.6       cgd #endif /* HASSETPROCTITLE */
    719       1.1       cgd 		if (logging)
    720       1.1       cgd 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
    721       1.1       cgd 			    remotehost, passwd);
    722       1.1       cgd 	} else {
    723       1.1       cgd 		reply(230, "User %s logged in.", pw->pw_name);
    724       1.6       cgd #ifdef HASSETPROCTITLE
    725       1.8   deraadt 		snprintf(proctitle, sizeof(proctitle),
    726       1.8   deraadt 		    "%s: %s", remotehost, pw->pw_name);
    727       1.1       cgd 		setproctitle(proctitle);
    728       1.6       cgd #endif /* HASSETPROCTITLE */
    729       1.1       cgd 		if (logging)
    730       1.8   deraadt 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
    731       1.1       cgd 			    remotehost, pw->pw_name);
    732       1.1       cgd 	}
    733      1.24     lukem 	(void) umask(curclass.umask);
    734       1.1       cgd 	return;
    735       1.1       cgd bad:
    736       1.1       cgd 	/* Forget all about it... */
    737       1.1       cgd 	end_login();
    738       1.1       cgd }
    739       1.1       cgd 
    740       1.8   deraadt void
    741       1.1       cgd retrieve(cmd, name)
    742       1.1       cgd 	char *cmd, *name;
    743       1.1       cgd {
    744      1.28  christos 	FILE *fin = NULL, *dout;
    745       1.1       cgd 	struct stat st;
    746      1.28  christos 	int (*closefunc) __P((FILE *)) = NULL;
    747      1.49     lukem 	int log, sendrv, closerv, stderrfd, isconversion;
    748       1.1       cgd 
    749      1.49     lukem 	sendrv = closerv = stderrfd = -1;
    750      1.49     lukem 	isconversion = 0;
    751      1.24     lukem 	log = (cmd == 0);
    752      1.49     lukem 	if (cmd == NULL) {
    753       1.1       cgd 		fin = fopen(name, "r"), closefunc = fclose;
    754      1.24     lukem 		if (fin == NULL)
    755      1.24     lukem 			cmd = do_conversion(name);
    756      1.49     lukem 		if (cmd != NULL) {
    757      1.49     lukem 			isconversion++;
    758      1.49     lukem 			syslog(LOG_INFO, "get command: '%s'", cmd);
    759      1.49     lukem 		}
    760      1.24     lukem 	}
    761      1.49     lukem 	if (cmd != NULL) {
    762       1.1       cgd 		char line[BUFSIZ];
    763      1.61     lukem 		char temp[MAXPATHLEN + 1];
    764       1.1       cgd 
    765      1.49     lukem 		(void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
    766      1.49     lukem 		stderrfd = mkstemp(temp);
    767      1.49     lukem 		if (stderrfd != -1)
    768      1.49     lukem 			(void)unlink(temp);
    769      1.30     lukem 		(void)snprintf(line, sizeof(line), cmd, name), name = line;
    770      1.49     lukem 		fin = ftpd_popen(line, "r", stderrfd), closefunc = ftpd_pclose;
    771       1.1       cgd 		st.st_size = -1;
    772       1.1       cgd 		st.st_blksize = BUFSIZ;
    773       1.1       cgd 	}
    774       1.1       cgd 	if (fin == NULL) {
    775       1.8   deraadt 		if (errno != 0) {
    776       1.1       cgd 			perror_reply(550, name);
    777      1.24     lukem 			if (log) {
    778      1.61     lukem 				logcmd("get", -1, name, NULL);
    779       1.8   deraadt 			}
    780       1.8   deraadt 		}
    781      1.49     lukem 		if (stderrfd != -1)
    782      1.49     lukem 			(void)close(stderrfd);
    783       1.1       cgd 		return;
    784       1.1       cgd 	}
    785       1.8   deraadt 	byte_count = -1;
    786      1.49     lukem 	if (cmd == NULL
    787      1.49     lukem 	    && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
    788       1.1       cgd 		reply(550, "%s: not a plain file.", name);
    789       1.1       cgd 		goto done;
    790       1.1       cgd 	}
    791       1.1       cgd 	if (restart_point) {
    792       1.1       cgd 		if (type == TYPE_A) {
    793      1.49     lukem 			off_t i;
    794       1.8   deraadt 			int c;
    795       1.1       cgd 
    796      1.49     lukem 			for (i = 0; i < restart_point; i++) {
    797       1.1       cgd 				if ((c=getc(fin)) == EOF) {
    798       1.1       cgd 					perror_reply(550, name);
    799       1.1       cgd 					goto done;
    800       1.1       cgd 				}
    801       1.1       cgd 				if (c == '\n')
    802       1.1       cgd 					i++;
    803       1.8   deraadt 			}
    804      1.31    kleink 		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
    805       1.1       cgd 			perror_reply(550, name);
    806       1.1       cgd 			goto done;
    807       1.1       cgd 		}
    808       1.1       cgd 	}
    809       1.1       cgd 	dout = dataconn(name, st.st_size, "w");
    810       1.1       cgd 	if (dout == NULL)
    811       1.1       cgd 		goto done;
    812      1.49     lukem 	sendrv = send_data(fin, dout, st.st_blksize);
    813       1.1       cgd 	(void) fclose(dout);
    814       1.1       cgd 	data = -1;
    815       1.1       cgd 	pdata = -1;
    816       1.1       cgd done:
    817      1.24     lukem 	if (log)
    818      1.61     lukem 		logcmd("get", byte_count, name, NULL);
    819      1.49     lukem 	closerv = (*closefunc)(fin);
    820      1.49     lukem 	if (sendrv == 0) {
    821      1.49     lukem 		FILE *err;
    822      1.49     lukem 		struct stat sb;
    823      1.49     lukem 
    824      1.49     lukem 		if (cmd != NULL && closerv != 0) {
    825      1.49     lukem 			lreply(226,
    826      1.49     lukem 			    "Command returned an exit status of %d",
    827      1.49     lukem 			    closerv);
    828      1.49     lukem 			if (isconversion)
    829      1.49     lukem 				syslog(LOG_INFO,
    830      1.49     lukem 				    "get command: '%s' returned %d",
    831      1.49     lukem 				    cmd, closerv);
    832      1.49     lukem 		}
    833      1.49     lukem 		if (cmd != NULL && stderrfd != -1 &&
    834      1.49     lukem 		    (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
    835      1.49     lukem 		    ((err = fdopen(stderrfd, "r")) != NULL)) {
    836      1.49     lukem 			char *cp, line[LINE_MAX];
    837      1.49     lukem 
    838      1.49     lukem 			lreply(226, "Command error messages:");
    839      1.49     lukem 			rewind(err);
    840      1.49     lukem 			while (fgets(line, sizeof(line), err) != NULL) {
    841      1.49     lukem 				if ((cp = strchr(line, '\n')) != NULL)
    842      1.49     lukem 					*cp = '\0';
    843      1.49     lukem 				lreply(226, " %s", line);
    844      1.49     lukem 			}
    845      1.49     lukem 			(void) fflush(stdout);
    846      1.49     lukem 			(void) fclose(err);
    847      1.49     lukem 			lreply(226, "End of command error messages.");
    848      1.49     lukem 				/* a reply(226,) must follow */
    849      1.49     lukem 		}
    850      1.49     lukem 		reply(226, "Transfer complete.");
    851      1.49     lukem 	}
    852      1.49     lukem 	if (stderrfd != -1)
    853      1.49     lukem 		(void)close(stderrfd);
    854       1.1       cgd }
    855       1.1       cgd 
    856       1.8   deraadt void
    857       1.1       cgd store(name, mode, unique)
    858       1.1       cgd 	char *name, *mode;
    859       1.1       cgd 	int unique;
    860       1.1       cgd {
    861       1.1       cgd 	FILE *fout, *din;
    862       1.1       cgd 	struct stat st;
    863       1.8   deraadt 	int (*closefunc) __P((FILE *));
    864       1.1       cgd 
    865       1.1       cgd 	if (unique && stat(name, &st) == 0 &&
    866       1.8   deraadt 	    (name = gunique(name)) == NULL) {
    867      1.61     lukem 		logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL);
    868       1.1       cgd 		return;
    869       1.8   deraadt 	}
    870       1.1       cgd 
    871       1.1       cgd 	if (restart_point)
    872       1.8   deraadt 		mode = "r+";
    873       1.1       cgd 	fout = fopen(name, mode);
    874       1.1       cgd 	closefunc = fclose;
    875       1.1       cgd 	if (fout == NULL) {
    876       1.1       cgd 		perror_reply(553, name);
    877      1.61     lukem 		logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL);
    878       1.1       cgd 		return;
    879       1.1       cgd 	}
    880       1.8   deraadt 	byte_count = -1;
    881       1.1       cgd 	if (restart_point) {
    882       1.1       cgd 		if (type == TYPE_A) {
    883      1.49     lukem 			off_t i;
    884       1.8   deraadt 			int c;
    885       1.1       cgd 
    886      1.49     lukem 			for (i = 0; i < restart_point; i++) {
    887       1.1       cgd 				if ((c=getc(fout)) == EOF) {
    888       1.1       cgd 					perror_reply(550, name);
    889       1.1       cgd 					goto done;
    890       1.1       cgd 				}
    891       1.1       cgd 				if (c == '\n')
    892       1.1       cgd 					i++;
    893       1.8   deraadt 			}
    894       1.1       cgd 			/*
    895       1.1       cgd 			 * We must do this seek to "current" position
    896       1.1       cgd 			 * because we are changing from reading to
    897       1.1       cgd 			 * writing.
    898       1.1       cgd 			 */
    899      1.20     lukem 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
    900       1.1       cgd 				perror_reply(550, name);
    901       1.1       cgd 				goto done;
    902       1.1       cgd 			}
    903      1.31    kleink 		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
    904       1.1       cgd 			perror_reply(550, name);
    905       1.1       cgd 			goto done;
    906       1.1       cgd 		}
    907       1.1       cgd 	}
    908       1.1       cgd 	din = dataconn(name, (off_t)-1, "r");
    909       1.1       cgd 	if (din == NULL)
    910       1.1       cgd 		goto done;
    911       1.1       cgd 	if (receive_data(din, fout) == 0) {
    912       1.1       cgd 		if (unique)
    913       1.1       cgd 			reply(226, "Transfer complete (unique file name:%s).",
    914       1.1       cgd 			    name);
    915       1.1       cgd 		else
    916       1.1       cgd 			reply(226, "Transfer complete.");
    917       1.1       cgd 	}
    918       1.1       cgd 	(void) fclose(din);
    919       1.1       cgd 	data = -1;
    920       1.1       cgd 	pdata = -1;
    921       1.1       cgd done:
    922      1.61     lukem 	logcmd(*mode == 'w' ? "put" : "append", byte_count, name, NULL);
    923       1.1       cgd 	(*closefunc)(fout);
    924       1.1       cgd }
    925       1.1       cgd 
    926       1.8   deraadt static FILE *
    927       1.1       cgd getdatasock(mode)
    928       1.1       cgd 	char *mode;
    929       1.1       cgd {
    930       1.8   deraadt 	int on = 1, s, t, tries;
    931       1.1       cgd 
    932       1.1       cgd 	if (data >= 0)
    933       1.1       cgd 		return (fdopen(data, mode));
    934       1.1       cgd 	(void) seteuid((uid_t)0);
    935       1.1       cgd 	s = socket(AF_INET, SOCK_STREAM, 0);
    936       1.1       cgd 	if (s < 0)
    937       1.1       cgd 		goto bad;
    938       1.1       cgd 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
    939       1.8   deraadt 	    (char *) &on, sizeof(on)) < 0)
    940       1.1       cgd 		goto bad;
    941       1.1       cgd 	/* anchor socket to avoid multi-homing problems */
    942      1.15   mycroft 	data_source.sin_len = sizeof(struct sockaddr_in);
    943       1.1       cgd 	data_source.sin_family = AF_INET;
    944       1.1       cgd 	data_source.sin_addr = ctrl_addr.sin_addr;
    945       1.1       cgd 	for (tries = 1; ; tries++) {
    946       1.1       cgd 		if (bind(s, (struct sockaddr *)&data_source,
    947       1.8   deraadt 		    sizeof(data_source)) >= 0)
    948       1.1       cgd 			break;
    949       1.1       cgd 		if (errno != EADDRINUSE || tries > 10)
    950       1.1       cgd 			goto bad;
    951       1.1       cgd 		sleep(tries);
    952       1.1       cgd 	}
    953       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
    954       1.1       cgd #ifdef IP_TOS
    955       1.1       cgd 	on = IPTOS_THROUGHPUT;
    956       1.1       cgd 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
    957       1.1       cgd 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
    958       1.1       cgd #endif
    959       1.1       cgd 	return (fdopen(s, mode));
    960       1.1       cgd bad:
    961       1.8   deraadt 	/* Return the real value of errno (close may change it) */
    962       1.8   deraadt 	t = errno;
    963       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
    964       1.1       cgd 	(void) close(s);
    965       1.8   deraadt 	errno = t;
    966       1.1       cgd 	return (NULL);
    967       1.1       cgd }
    968       1.1       cgd 
    969       1.8   deraadt static FILE *
    970       1.1       cgd dataconn(name, size, mode)
    971       1.1       cgd 	char *name;
    972       1.1       cgd 	off_t size;
    973       1.1       cgd 	char *mode;
    974       1.1       cgd {
    975       1.1       cgd 	char sizebuf[32];
    976       1.1       cgd 	FILE *file;
    977       1.1       cgd 	int retry = 0, tos;
    978       1.1       cgd 
    979       1.1       cgd 	file_size = size;
    980       1.1       cgd 	byte_count = 0;
    981       1.1       cgd 	if (size != (off_t) -1)
    982      1.30     lukem 		(void)snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
    983      1.29       mrg 		    (long long)size);
    984       1.1       cgd 	else
    985      1.29       mrg 		sizebuf[0] = '\0';
    986       1.1       cgd 	if (pdata >= 0) {
    987       1.1       cgd 		struct sockaddr_in from;
    988       1.1       cgd 		int s, fromlen = sizeof(from);
    989       1.1       cgd 
    990      1.42     lukem 		(void) alarm(curclass.timeout);
    991       1.1       cgd 		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
    992      1.42     lukem 		(void) alarm(0);
    993       1.1       cgd 		if (s < 0) {
    994       1.1       cgd 			reply(425, "Can't open data connection.");
    995       1.1       cgd 			(void) close(pdata);
    996       1.1       cgd 			pdata = -1;
    997       1.8   deraadt 			return (NULL);
    998       1.1       cgd 		}
    999       1.1       cgd 		(void) close(pdata);
   1000       1.1       cgd 		pdata = s;
   1001       1.1       cgd #ifdef IP_TOS
   1002      1.12   mycroft 		tos = IPTOS_THROUGHPUT;
   1003       1.1       cgd 		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
   1004       1.1       cgd 		    sizeof(int));
   1005       1.1       cgd #endif
   1006       1.8   deraadt 		reply(150, "Opening %s mode data connection for '%s'%s.",
   1007       1.1       cgd 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1008       1.8   deraadt 		return (fdopen(pdata, mode));
   1009       1.1       cgd 	}
   1010       1.1       cgd 	if (data >= 0) {
   1011       1.8   deraadt 		reply(125, "Using existing data connection for '%s'%s.",
   1012       1.1       cgd 		    name, sizebuf);
   1013       1.1       cgd 		usedefault = 1;
   1014       1.1       cgd 		return (fdopen(data, mode));
   1015       1.1       cgd 	}
   1016       1.1       cgd 	if (usedefault)
   1017       1.1       cgd 		data_dest = his_addr;
   1018       1.1       cgd 	usedefault = 1;
   1019       1.1       cgd 	file = getdatasock(mode);
   1020       1.1       cgd 	if (file == NULL) {
   1021       1.1       cgd 		reply(425, "Can't create data socket (%s,%d): %s.",
   1022       1.1       cgd 		    inet_ntoa(data_source.sin_addr),
   1023       1.1       cgd 		    ntohs(data_source.sin_port), strerror(errno));
   1024       1.1       cgd 		return (NULL);
   1025       1.1       cgd 	}
   1026       1.1       cgd 	data = fileno(file);
   1027       1.1       cgd 	while (connect(data, (struct sockaddr *)&data_dest,
   1028       1.8   deraadt 	    sizeof(data_dest)) < 0) {
   1029       1.1       cgd 		if (errno == EADDRINUSE && retry < swaitmax) {
   1030       1.1       cgd 			sleep((unsigned) swaitint);
   1031       1.1       cgd 			retry += swaitint;
   1032       1.1       cgd 			continue;
   1033       1.1       cgd 		}
   1034       1.1       cgd 		perror_reply(425, "Can't build data connection");
   1035       1.1       cgd 		(void) fclose(file);
   1036       1.1       cgd 		data = -1;
   1037       1.1       cgd 		return (NULL);
   1038       1.1       cgd 	}
   1039       1.8   deraadt 	reply(150, "Opening %s mode data connection for '%s'%s.",
   1040       1.1       cgd 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1041       1.1       cgd 	return (file);
   1042       1.1       cgd }
   1043       1.1       cgd 
   1044       1.1       cgd /*
   1045       1.8   deraadt  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
   1046       1.8   deraadt  * encapsulation of the data subject * to Mode, Structure, and Type.
   1047       1.1       cgd  *
   1048       1.1       cgd  * NB: Form isn't handled.
   1049       1.1       cgd  */
   1050      1.49     lukem static int
   1051       1.1       cgd send_data(instr, outstr, blksize)
   1052       1.1       cgd 	FILE *instr, *outstr;
   1053       1.1       cgd 	off_t blksize;
   1054       1.1       cgd {
   1055      1.24     lukem 	int	 c, cnt, filefd, netfd;
   1056      1.24     lukem 	char	*buf;
   1057       1.1       cgd 
   1058       1.1       cgd 	transflag++;
   1059       1.1       cgd 	if (setjmp(urgcatch)) {
   1060       1.1       cgd 		transflag = 0;
   1061      1.49     lukem 		return (-1);
   1062       1.1       cgd 	}
   1063      1.24     lukem 
   1064       1.1       cgd 	switch (type) {
   1065       1.1       cgd 
   1066       1.1       cgd 	case TYPE_A:
   1067       1.1       cgd 		while ((c = getc(instr)) != EOF) {
   1068       1.1       cgd 			byte_count++;
   1069       1.1       cgd 			if (c == '\n') {
   1070       1.1       cgd 				if (ferror(outstr))
   1071       1.1       cgd 					goto data_err;
   1072       1.1       cgd 				(void) putc('\r', outstr);
   1073       1.1       cgd 			}
   1074       1.1       cgd 			(void) putc(c, outstr);
   1075       1.1       cgd 		}
   1076       1.1       cgd 		fflush(outstr);
   1077       1.1       cgd 		transflag = 0;
   1078       1.1       cgd 		if (ferror(instr))
   1079       1.1       cgd 			goto file_err;
   1080       1.1       cgd 		if (ferror(outstr))
   1081       1.1       cgd 			goto data_err;
   1082      1.49     lukem 		return (0);
   1083       1.1       cgd 
   1084       1.1       cgd 	case TYPE_I:
   1085       1.1       cgd 	case TYPE_L:
   1086       1.1       cgd 		if ((buf = malloc((u_int)blksize)) == NULL) {
   1087       1.1       cgd 			transflag = 0;
   1088       1.1       cgd 			perror_reply(451, "Local resource failure: malloc");
   1089      1.49     lukem 			return (-1);
   1090       1.1       cgd 		}
   1091       1.1       cgd 		netfd = fileno(outstr);
   1092       1.1       cgd 		filefd = fileno(instr);
   1093       1.1       cgd 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
   1094       1.1       cgd 		    write(netfd, buf, cnt) == cnt)
   1095       1.1       cgd 			byte_count += cnt;
   1096       1.1       cgd 		transflag = 0;
   1097       1.1       cgd 		(void)free(buf);
   1098       1.1       cgd 		if (cnt != 0) {
   1099       1.1       cgd 			if (cnt < 0)
   1100       1.1       cgd 				goto file_err;
   1101       1.1       cgd 			goto data_err;
   1102       1.1       cgd 		}
   1103      1.49     lukem 		return (0);
   1104       1.1       cgd 	default:
   1105       1.1       cgd 		transflag = 0;
   1106       1.1       cgd 		reply(550, "Unimplemented TYPE %d in send_data", type);
   1107      1.49     lukem 		return (-1);
   1108       1.1       cgd 	}
   1109       1.1       cgd 
   1110       1.1       cgd data_err:
   1111       1.1       cgd 	transflag = 0;
   1112       1.1       cgd 	perror_reply(426, "Data connection");
   1113      1.49     lukem 	return (-1);
   1114       1.1       cgd 
   1115       1.1       cgd file_err:
   1116       1.1       cgd 	transflag = 0;
   1117       1.1       cgd 	perror_reply(551, "Error on input file");
   1118      1.49     lukem 	return (-1);
   1119       1.1       cgd }
   1120       1.1       cgd 
   1121       1.1       cgd /*
   1122       1.8   deraadt  * Transfer data from peer to "outstr" using the appropriate encapulation of
   1123       1.8   deraadt  * the data subject to Mode, Structure, and Type.
   1124       1.1       cgd  *
   1125       1.1       cgd  * N.B.: Form isn't handled.
   1126       1.1       cgd  */
   1127       1.8   deraadt static int
   1128       1.1       cgd receive_data(instr, outstr)
   1129       1.1       cgd 	FILE *instr, *outstr;
   1130       1.1       cgd {
   1131      1.24     lukem 	int	c, cnt, bare_lfs;
   1132      1.24     lukem 	char	buf[BUFSIZ];
   1133      1.25  christos #ifdef __GNUC__
   1134      1.25  christos 	(void) &bare_lfs;
   1135      1.25  christos #endif
   1136       1.1       cgd 
   1137      1.24     lukem 	bare_lfs = 0;
   1138       1.1       cgd 	transflag++;
   1139       1.1       cgd 	if (setjmp(urgcatch)) {
   1140       1.1       cgd 		transflag = 0;
   1141       1.1       cgd 		return (-1);
   1142       1.1       cgd 	}
   1143      1.24     lukem 
   1144       1.1       cgd 	switch (type) {
   1145       1.1       cgd 
   1146       1.1       cgd 	case TYPE_I:
   1147       1.1       cgd 	case TYPE_L:
   1148       1.8   deraadt 		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
   1149       1.1       cgd 			if (write(fileno(outstr), buf, cnt) != cnt)
   1150       1.1       cgd 				goto file_err;
   1151       1.1       cgd 			byte_count += cnt;
   1152       1.1       cgd 		}
   1153       1.1       cgd 		if (cnt < 0)
   1154       1.1       cgd 			goto data_err;
   1155       1.1       cgd 		transflag = 0;
   1156       1.1       cgd 		return (0);
   1157       1.1       cgd 
   1158       1.1       cgd 	case TYPE_E:
   1159       1.1       cgd 		reply(553, "TYPE E not implemented.");
   1160       1.1       cgd 		transflag = 0;
   1161       1.1       cgd 		return (-1);
   1162       1.1       cgd 
   1163       1.1       cgd 	case TYPE_A:
   1164       1.1       cgd 		while ((c = getc(instr)) != EOF) {
   1165       1.1       cgd 			byte_count++;
   1166       1.1       cgd 			if (c == '\n')
   1167       1.1       cgd 				bare_lfs++;
   1168       1.1       cgd 			while (c == '\r') {
   1169       1.1       cgd 				if (ferror(outstr))
   1170       1.1       cgd 					goto data_err;
   1171       1.1       cgd 				if ((c = getc(instr)) != '\n') {
   1172       1.1       cgd 					(void) putc ('\r', outstr);
   1173       1.1       cgd 					if (c == '\0' || c == EOF)
   1174       1.1       cgd 						goto contin2;
   1175       1.1       cgd 				}
   1176       1.1       cgd 			}
   1177       1.1       cgd 			(void) putc(c, outstr);
   1178       1.1       cgd 	contin2:	;
   1179       1.1       cgd 		}
   1180       1.1       cgd 		fflush(outstr);
   1181       1.1       cgd 		if (ferror(instr))
   1182       1.1       cgd 			goto data_err;
   1183       1.1       cgd 		if (ferror(outstr))
   1184       1.1       cgd 			goto file_err;
   1185       1.1       cgd 		transflag = 0;
   1186       1.1       cgd 		if (bare_lfs) {
   1187       1.8   deraadt 			lreply(226,
   1188       1.8   deraadt 		"WARNING! %d bare linefeeds received in ASCII mode",
   1189       1.8   deraadt 			    bare_lfs);
   1190       1.8   deraadt 		(void)printf("   File may not have transferred correctly.\r\n");
   1191       1.1       cgd 		}
   1192       1.1       cgd 		return (0);
   1193       1.1       cgd 	default:
   1194       1.1       cgd 		reply(550, "Unimplemented TYPE %d in receive_data", type);
   1195       1.1       cgd 		transflag = 0;
   1196       1.1       cgd 		return (-1);
   1197       1.1       cgd 	}
   1198       1.1       cgd 
   1199       1.1       cgd data_err:
   1200       1.1       cgd 	transflag = 0;
   1201       1.1       cgd 	perror_reply(426, "Data Connection");
   1202       1.1       cgd 	return (-1);
   1203       1.1       cgd 
   1204       1.1       cgd file_err:
   1205       1.1       cgd 	transflag = 0;
   1206       1.1       cgd 	perror_reply(452, "Error writing file");
   1207       1.1       cgd 	return (-1);
   1208       1.1       cgd }
   1209       1.1       cgd 
   1210       1.8   deraadt void
   1211       1.1       cgd statfilecmd(filename)
   1212       1.1       cgd 	char *filename;
   1213       1.1       cgd {
   1214       1.1       cgd 	FILE *fin;
   1215       1.1       cgd 	int c;
   1216       1.8   deraadt 	char line[LINE_MAX];
   1217       1.1       cgd 
   1218       1.8   deraadt 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
   1219      1.49     lukem 	fin = ftpd_popen(line, "r", STDOUT_FILENO);
   1220       1.1       cgd 	lreply(211, "status of %s:", filename);
   1221       1.1       cgd 	while ((c = getc(fin)) != EOF) {
   1222       1.1       cgd 		if (c == '\n') {
   1223       1.1       cgd 			if (ferror(stdout)){
   1224       1.1       cgd 				perror_reply(421, "control connection");
   1225       1.1       cgd 				(void) ftpd_pclose(fin);
   1226       1.1       cgd 				dologout(1);
   1227       1.1       cgd 				/* NOTREACHED */
   1228       1.1       cgd 			}
   1229       1.1       cgd 			if (ferror(fin)) {
   1230       1.1       cgd 				perror_reply(551, filename);
   1231       1.1       cgd 				(void) ftpd_pclose(fin);
   1232       1.1       cgd 				return;
   1233       1.1       cgd 			}
   1234       1.1       cgd 			(void) putc('\r', stdout);
   1235       1.1       cgd 		}
   1236       1.1       cgd 		(void) putc(c, stdout);
   1237       1.1       cgd 	}
   1238       1.1       cgd 	(void) ftpd_pclose(fin);
   1239       1.1       cgd 	reply(211, "End of Status");
   1240       1.1       cgd }
   1241       1.1       cgd 
   1242       1.8   deraadt void
   1243       1.1       cgd statcmd()
   1244       1.1       cgd {
   1245       1.1       cgd 	struct sockaddr_in *sin;
   1246       1.1       cgd 	u_char *a, *p;
   1247       1.1       cgd 
   1248      1.24     lukem 	lreply(211, "%s FTP server status:", hostname);
   1249      1.24     lukem 	lreply(211, "%s", version);
   1250      1.24     lukem 	if (isdigit(remotehost[0]))
   1251      1.24     lukem 		lreply(211, "Connected to %s", remotehost);
   1252      1.24     lukem 	else
   1253      1.24     lukem 		lreply(211, "Connected to %s (%s)", remotehost,
   1254      1.24     lukem 		    inet_ntoa(his_addr.sin_addr));
   1255       1.1       cgd 	if (logged_in) {
   1256       1.1       cgd 		if (guest)
   1257      1.24     lukem 			lreply(211, "Logged in anonymously");
   1258       1.1       cgd 		else
   1259      1.24     lukem 			lreply(211, "Logged in as %s", pw->pw_name);
   1260       1.1       cgd 	} else if (askpasswd)
   1261      1.24     lukem 		lreply(211, "Waiting for password");
   1262       1.1       cgd 	else
   1263      1.24     lukem 		lreply(211, "Waiting for user name");
   1264      1.24     lukem 	printf("211- TYPE: %s", typenames[type]);
   1265       1.1       cgd 	if (type == TYPE_A || type == TYPE_E)
   1266       1.1       cgd 		printf(", FORM: %s", formnames[form]);
   1267       1.1       cgd 	if (type == TYPE_L)
   1268       1.1       cgd #if NBBY == 8
   1269       1.1       cgd 		printf(" %d", NBBY);
   1270       1.1       cgd #else
   1271       1.1       cgd 		printf(" %d", bytesize);	/* need definition! */
   1272       1.1       cgd #endif
   1273       1.1       cgd 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
   1274       1.1       cgd 	    strunames[stru], modenames[mode]);
   1275       1.1       cgd 	if (data != -1)
   1276      1.24     lukem 		lreply(211, "Data connection open");
   1277       1.1       cgd 	else if (pdata != -1) {
   1278      1.24     lukem 		printf("211- in Passive mode");
   1279       1.1       cgd 		sin = &pasv_addr;
   1280       1.1       cgd 		goto printaddr;
   1281       1.1       cgd 	} else if (usedefault == 0) {
   1282      1.24     lukem 		printf("211- PORT");
   1283       1.1       cgd 		sin = &data_dest;
   1284       1.1       cgd printaddr:
   1285       1.1       cgd 		a = (u_char *) &sin->sin_addr;
   1286       1.1       cgd 		p = (u_char *) &sin->sin_port;
   1287       1.1       cgd #define UC(b) (((int) b) & 0xff)
   1288       1.1       cgd 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
   1289       1.1       cgd 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
   1290       1.1       cgd #undef UC
   1291       1.1       cgd 	} else
   1292      1.24     lukem 		lreply(211, "No data connection");
   1293      1.24     lukem 
   1294      1.24     lukem 	if (logged_in) {
   1295      1.24     lukem 		struct ftpconv *cp;
   1296      1.24     lukem 
   1297      1.24     lukem 		lreply(211, "");
   1298      1.24     lukem 		lreply(211, "Class: %s", curclass.classname);
   1299      1.41     lukem 		lreply(211, "Check PORT commands: %sabled",
   1300      1.41     lukem 		    curclass.checkportcmd ? "en" : "dis");
   1301      1.24     lukem 		if (curclass.display)
   1302      1.24     lukem 			lreply(211, "Display file: %s", curclass.display);
   1303      1.24     lukem 		if (curclass.notify)
   1304      1.24     lukem 			lreply(211, "Notify fileglob: %s", curclass.notify);
   1305      1.24     lukem 		lreply(211, "Idle timeout: %d, maximum timeout: %d",
   1306      1.24     lukem 		    curclass.timeout, curclass.maxtimeout);
   1307      1.41     lukem 		lreply(211, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled",
   1308      1.24     lukem 		    curclass.modify ? "en" : "dis");
   1309      1.24     lukem 		lreply(211, "Umask: %.04o", curclass.umask);
   1310      1.24     lukem 		for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
   1311      1.24     lukem 			if (cp->suffix == NULL || cp->types == NULL ||
   1312      1.24     lukem 			    cp->command == NULL)
   1313      1.24     lukem 				continue;
   1314      1.24     lukem 			lreply(211,
   1315      1.24     lukem 			    "Conversion: %s [%s] disable: %s, command: %s",
   1316      1.24     lukem 			    cp->suffix, cp->types, cp->disable, cp->command);
   1317      1.24     lukem 		}
   1318      1.24     lukem 	}
   1319      1.24     lukem 
   1320       1.1       cgd 	reply(211, "End of status");
   1321       1.1       cgd }
   1322       1.1       cgd 
   1323       1.8   deraadt void
   1324       1.1       cgd fatal(s)
   1325       1.1       cgd 	char *s;
   1326       1.1       cgd {
   1327       1.8   deraadt 
   1328       1.1       cgd 	reply(451, "Error in server: %s\n", s);
   1329       1.1       cgd 	reply(221, "Closing connection due to server error.");
   1330       1.1       cgd 	dologout(0);
   1331       1.1       cgd 	/* NOTREACHED */
   1332       1.1       cgd }
   1333       1.1       cgd 
   1334       1.8   deraadt void
   1335      1.45  christos #ifdef __STDC__
   1336       1.8   deraadt reply(int n, const char *fmt, ...)
   1337       1.8   deraadt #else
   1338       1.8   deraadt reply(n, fmt, va_alist)
   1339       1.1       cgd 	int n;
   1340       1.1       cgd 	char *fmt;
   1341       1.8   deraadt         va_dcl
   1342       1.8   deraadt #endif
   1343       1.1       cgd {
   1344       1.8   deraadt 	va_list ap;
   1345      1.45  christos #ifdef __STDC__
   1346       1.8   deraadt 	va_start(ap, fmt);
   1347       1.8   deraadt #else
   1348       1.8   deraadt 	va_start(ap);
   1349       1.8   deraadt #endif
   1350       1.8   deraadt 	(void)printf("%d ", n);
   1351       1.8   deraadt 	(void)vprintf(fmt, ap);
   1352       1.8   deraadt 	(void)printf("\r\n");
   1353       1.1       cgd 	(void)fflush(stdout);
   1354       1.1       cgd 	if (debug) {
   1355       1.1       cgd 		syslog(LOG_DEBUG, "<--- %d ", n);
   1356       1.8   deraadt 		vsyslog(LOG_DEBUG, fmt, ap);
   1357       1.8   deraadt 	}
   1358       1.1       cgd }
   1359       1.1       cgd 
   1360       1.8   deraadt void
   1361      1.45  christos #ifdef __STDC__
   1362       1.8   deraadt lreply(int n, const char *fmt, ...)
   1363       1.8   deraadt #else
   1364       1.8   deraadt lreply(n, fmt, va_alist)
   1365       1.1       cgd 	int n;
   1366       1.1       cgd 	char *fmt;
   1367       1.8   deraadt         va_dcl
   1368       1.8   deraadt #endif
   1369       1.1       cgd {
   1370       1.8   deraadt 	va_list ap;
   1371      1.45  christos #ifdef __STDC__
   1372       1.8   deraadt 	va_start(ap, fmt);
   1373       1.8   deraadt #else
   1374       1.8   deraadt 	va_start(ap);
   1375       1.8   deraadt #endif
   1376       1.8   deraadt 	(void)printf("%d- ", n);
   1377       1.8   deraadt 	(void)vprintf(fmt, ap);
   1378       1.8   deraadt 	(void)printf("\r\n");
   1379       1.1       cgd 	(void)fflush(stdout);
   1380       1.1       cgd 	if (debug) {
   1381       1.1       cgd 		syslog(LOG_DEBUG, "<--- %d- ", n);
   1382       1.8   deraadt 		vsyslog(LOG_DEBUG, fmt, ap);
   1383       1.1       cgd 	}
   1384       1.1       cgd }
   1385       1.1       cgd 
   1386       1.8   deraadt static void
   1387       1.1       cgd ack(s)
   1388       1.1       cgd 	char *s;
   1389       1.1       cgd {
   1390       1.8   deraadt 
   1391       1.1       cgd 	reply(250, "%s command successful.", s);
   1392       1.1       cgd }
   1393       1.1       cgd 
   1394       1.8   deraadt void
   1395       1.1       cgd delete(name)
   1396       1.1       cgd 	char *name;
   1397       1.1       cgd {
   1398       1.1       cgd 
   1399      1.61     lukem 	logcmd("delete", -1, name, NULL);
   1400      1.39   mycroft 	if (remove(name) < 0)
   1401       1.1       cgd 		perror_reply(550, name);
   1402      1.39   mycroft 	else
   1403      1.39   mycroft 		ack("DELE");
   1404       1.1       cgd }
   1405       1.1       cgd 
   1406       1.8   deraadt void
   1407       1.1       cgd cwd(path)
   1408      1.55   mycroft 	const char *path;
   1409       1.1       cgd {
   1410       1.8   deraadt 
   1411       1.1       cgd 	if (chdir(path) < 0)
   1412       1.1       cgd 		perror_reply(550, path);
   1413      1.24     lukem 	else {
   1414      1.24     lukem 		show_chdir_messages(250);
   1415       1.1       cgd 		ack("CWD");
   1416      1.24     lukem 	}
   1417       1.1       cgd }
   1418       1.1       cgd 
   1419      1.33     lukem static void
   1420      1.33     lukem replydirname(name, message)
   1421      1.33     lukem 	const char *name, *message;
   1422      1.33     lukem {
   1423      1.33     lukem 	char npath[MAXPATHLEN + 1];
   1424      1.33     lukem 	int i;
   1425      1.33     lukem 
   1426      1.33     lukem 	for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
   1427      1.33     lukem 		npath[i] = *name;
   1428      1.33     lukem 		if (*name == '"')
   1429      1.33     lukem 			npath[++i] = '"';
   1430      1.33     lukem 	}
   1431      1.33     lukem 	npath[i] = '\0';
   1432      1.33     lukem 	reply(257, "\"%s\" %s", npath, message);
   1433      1.33     lukem }
   1434      1.33     lukem 
   1435       1.8   deraadt void
   1436       1.1       cgd makedir(name)
   1437       1.1       cgd 	char *name;
   1438       1.1       cgd {
   1439       1.8   deraadt 
   1440      1.61     lukem 	logcmd("mkdir", -1, name, NULL);
   1441       1.1       cgd 	if (mkdir(name, 0777) < 0)
   1442       1.1       cgd 		perror_reply(550, name);
   1443       1.1       cgd 	else
   1444      1.33     lukem 		replydirname(name, "directory created.");
   1445       1.1       cgd }
   1446       1.1       cgd 
   1447       1.8   deraadt void
   1448       1.1       cgd removedir(name)
   1449       1.1       cgd 	char *name;
   1450       1.1       cgd {
   1451       1.8   deraadt 
   1452      1.61     lukem 	logcmd("rmdir", -1, name, NULL);
   1453       1.1       cgd 	if (rmdir(name) < 0)
   1454       1.1       cgd 		perror_reply(550, name);
   1455       1.1       cgd 	else
   1456       1.1       cgd 		ack("RMD");
   1457       1.1       cgd }
   1458       1.1       cgd 
   1459       1.8   deraadt void
   1460       1.1       cgd pwd()
   1461       1.1       cgd {
   1462       1.1       cgd 	char path[MAXPATHLEN + 1];
   1463       1.1       cgd 
   1464      1.33     lukem 	if (getcwd(path, sizeof(path) - 1) == NULL)
   1465      1.48     mouse 		reply(550, "Can't get the current directory: %s.",
   1466      1.48     mouse 							strerror(errno));
   1467       1.1       cgd 	else
   1468      1.33     lukem 		replydirname(path, "is the current directory.");
   1469       1.1       cgd }
   1470       1.1       cgd 
   1471       1.1       cgd char *
   1472       1.1       cgd renamefrom(name)
   1473       1.1       cgd 	char *name;
   1474       1.1       cgd {
   1475       1.1       cgd 	struct stat st;
   1476       1.1       cgd 
   1477       1.1       cgd 	if (stat(name, &st) < 0) {
   1478       1.1       cgd 		perror_reply(550, name);
   1479      1.57     lukem 		return (NULL);
   1480       1.1       cgd 	}
   1481       1.1       cgd 	reply(350, "File exists, ready for destination name");
   1482       1.1       cgd 	return (name);
   1483       1.1       cgd }
   1484       1.1       cgd 
   1485       1.8   deraadt void
   1486       1.1       cgd renamecmd(from, to)
   1487       1.1       cgd 	char *from, *to;
   1488       1.1       cgd {
   1489       1.8   deraadt 
   1490      1.61     lukem 	logcmd("rename", -1, from, to);
   1491       1.1       cgd 	if (rename(from, to) < 0)
   1492       1.1       cgd 		perror_reply(550, "rename");
   1493       1.1       cgd 	else
   1494       1.1       cgd 		ack("RNTO");
   1495       1.1       cgd }
   1496       1.1       cgd 
   1497       1.8   deraadt static void
   1498       1.1       cgd dolog(sin)
   1499       1.1       cgd 	struct sockaddr_in *sin;
   1500       1.1       cgd {
   1501       1.1       cgd 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
   1502       1.8   deraadt 		sizeof(struct in_addr), AF_INET);
   1503       1.1       cgd 
   1504       1.1       cgd 	if (hp)
   1505      1.52       mrg 		(void)strncpy(remotehost, hp->h_name, sizeof(remotehost));
   1506       1.1       cgd 	else
   1507      1.52       mrg 		(void)strncpy(remotehost, inet_ntoa(sin->sin_addr),
   1508       1.8   deraadt 		    sizeof(remotehost));
   1509      1.52       mrg 	remotehost[sizeof(remotehost) - 1] = '\0';
   1510       1.6       cgd #ifdef HASSETPROCTITLE
   1511       1.8   deraadt 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
   1512       1.1       cgd 	setproctitle(proctitle);
   1513       1.6       cgd #endif /* HASSETPROCTITLE */
   1514       1.1       cgd 
   1515       1.8   deraadt 	if (logging)
   1516       1.8   deraadt 		syslog(LOG_INFO, "connection from %s", remotehost);
   1517       1.1       cgd }
   1518       1.1       cgd 
   1519       1.1       cgd /*
   1520       1.1       cgd  * Record logout in wtmp file
   1521       1.1       cgd  * and exit with supplied status.
   1522       1.1       cgd  */
   1523       1.8   deraadt void
   1524       1.1       cgd dologout(status)
   1525       1.1       cgd 	int status;
   1526       1.1       cgd {
   1527      1.16       mrg 	/*
   1528      1.16       mrg 	* Prevent reception of SIGURG from resulting in a resumption
   1529      1.16       mrg 	* back to the main program loop.
   1530      1.16       mrg 	*/
   1531      1.16       mrg 	transflag = 0;
   1532       1.8   deraadt 
   1533       1.1       cgd 	if (logged_in) {
   1534       1.1       cgd 		(void) seteuid((uid_t)0);
   1535       1.1       cgd 		logwtmp(ttyline, "", "");
   1536      1.36   mycroft #ifdef KERBEROS
   1537       1.4       cgd 		if (!notickets && krbtkfile_env)
   1538       1.4       cgd 			unlink(krbtkfile_env);
   1539       1.4       cgd #endif
   1540       1.1       cgd 	}
   1541       1.1       cgd 	/* beware of flushing buffers after a SIGPIPE */
   1542       1.1       cgd 	_exit(status);
   1543       1.1       cgd }
   1544       1.1       cgd 
   1545       1.8   deraadt static void
   1546       1.8   deraadt myoob(signo)
   1547       1.8   deraadt 	int signo;
   1548       1.1       cgd {
   1549       1.1       cgd 	char *cp;
   1550       1.1       cgd 
   1551       1.1       cgd 	/* only process if transfer occurring */
   1552       1.1       cgd 	if (!transflag)
   1553       1.1       cgd 		return;
   1554       1.1       cgd 	cp = tmpline;
   1555       1.1       cgd 	if (getline(cp, 7, stdin) == NULL) {
   1556       1.1       cgd 		reply(221, "You could at least say goodbye.");
   1557       1.1       cgd 		dologout(0);
   1558       1.1       cgd 	}
   1559      1.58     lukem 	if (strcasecmp(cp, "ABOR\r\n") == 0) {
   1560       1.1       cgd 		tmpline[0] = '\0';
   1561       1.1       cgd 		reply(426, "Transfer aborted. Data connection closed.");
   1562       1.1       cgd 		reply(226, "Abort successful");
   1563       1.1       cgd 		longjmp(urgcatch, 1);
   1564       1.1       cgd 	}
   1565      1.58     lukem 	if (strcasecmp(cp, "STAT\r\n") == 0) {
   1566       1.1       cgd 		if (file_size != (off_t) -1)
   1567       1.8   deraadt 			reply(213, "Status: %qd of %qd bytes transferred",
   1568       1.1       cgd 			    byte_count, file_size);
   1569       1.1       cgd 		else
   1570       1.8   deraadt 			reply(213, "Status: %qd bytes transferred", byte_count);
   1571       1.1       cgd 	}
   1572       1.1       cgd }
   1573       1.1       cgd 
   1574       1.1       cgd /*
   1575       1.1       cgd  * Note: a response of 425 is not mentioned as a possible response to
   1576       1.8   deraadt  *	the PASV command in RFC959. However, it has been blessed as
   1577       1.8   deraadt  *	a legitimate response by Jon Postel in a telephone conversation
   1578       1.1       cgd  *	with Rick Adams on 25 Jan 89.
   1579       1.1       cgd  */
   1580       1.8   deraadt void
   1581       1.1       cgd passive()
   1582       1.1       cgd {
   1583       1.1       cgd 	int len;
   1584       1.8   deraadt 	char *p, *a;
   1585       1.1       cgd 
   1586       1.1       cgd 	pdata = socket(AF_INET, SOCK_STREAM, 0);
   1587      1.23     lukem 	if (pdata < 0 || !logged_in) {
   1588       1.1       cgd 		perror_reply(425, "Can't open passive connection");
   1589       1.1       cgd 		return;
   1590       1.1       cgd 	}
   1591       1.1       cgd 	pasv_addr = ctrl_addr;
   1592       1.1       cgd 	pasv_addr.sin_port = 0;
   1593       1.1       cgd 	(void) seteuid((uid_t)0);
   1594       1.1       cgd 	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
   1595       1.1       cgd 		(void) seteuid((uid_t)pw->pw_uid);
   1596       1.1       cgd 		goto pasv_error;
   1597       1.1       cgd 	}
   1598       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
   1599       1.1       cgd 	len = sizeof(pasv_addr);
   1600       1.1       cgd 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
   1601       1.1       cgd 		goto pasv_error;
   1602       1.1       cgd 	if (listen(pdata, 1) < 0)
   1603       1.1       cgd 		goto pasv_error;
   1604       1.1       cgd 	a = (char *) &pasv_addr.sin_addr;
   1605       1.1       cgd 	p = (char *) &pasv_addr.sin_port;
   1606       1.1       cgd 
   1607       1.1       cgd #define UC(b) (((int) b) & 0xff)
   1608       1.1       cgd 
   1609       1.1       cgd 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
   1610       1.1       cgd 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
   1611       1.1       cgd 	return;
   1612       1.1       cgd 
   1613       1.1       cgd pasv_error:
   1614       1.1       cgd 	(void) close(pdata);
   1615       1.1       cgd 	pdata = -1;
   1616       1.1       cgd 	perror_reply(425, "Can't open passive connection");
   1617       1.1       cgd 	return;
   1618       1.1       cgd }
   1619       1.1       cgd 
   1620       1.1       cgd /*
   1621       1.1       cgd  * Generate unique name for file with basename "local".
   1622       1.1       cgd  * The file named "local" is already known to exist.
   1623       1.1       cgd  * Generates failure reply on error.
   1624      1.29       mrg  *
   1625      1.29       mrg  * XXX this function should under go changes similar to
   1626      1.29       mrg  * the mktemp(3)/mkstemp(3) changes.
   1627       1.1       cgd  */
   1628       1.8   deraadt static char *
   1629       1.1       cgd gunique(local)
   1630       1.1       cgd 	char *local;
   1631       1.1       cgd {
   1632      1.61     lukem 	static char new[MAXPATHLEN + 1];
   1633       1.1       cgd 	struct stat st;
   1634      1.29       mrg 	int count, len;
   1635       1.8   deraadt 	char *cp;
   1636       1.1       cgd 
   1637       1.8   deraadt 	cp = strrchr(local, '/');
   1638       1.1       cgd 	if (cp)
   1639       1.1       cgd 		*cp = '\0';
   1640       1.1       cgd 	if (stat(cp ? local : ".", &st) < 0) {
   1641       1.1       cgd 		perror_reply(553, cp ? local : ".");
   1642      1.57     lukem 		return (NULL);
   1643       1.1       cgd 	}
   1644       1.1       cgd 	if (cp)
   1645       1.1       cgd 		*cp = '/';
   1646       1.1       cgd 	(void) strcpy(new, local);
   1647      1.29       mrg 	len = strlen(new);
   1648      1.29       mrg 	cp = new + len;
   1649       1.1       cgd 	*cp++ = '.';
   1650       1.1       cgd 	for (count = 1; count < 100; count++) {
   1651      1.29       mrg 		(void)snprintf(cp, sizeof(new) - len - 2, "%d", count);
   1652       1.1       cgd 		if (stat(new, &st) < 0)
   1653       1.8   deraadt 			return (new);
   1654       1.1       cgd 	}
   1655       1.1       cgd 	reply(452, "Unique file name cannot be created.");
   1656       1.8   deraadt 	return (NULL);
   1657       1.1       cgd }
   1658       1.1       cgd 
   1659       1.1       cgd /*
   1660       1.1       cgd  * Format and send reply containing system error number.
   1661       1.1       cgd  */
   1662       1.8   deraadt void
   1663       1.1       cgd perror_reply(code, string)
   1664       1.1       cgd 	int code;
   1665      1.55   mycroft 	const char *string;
   1666       1.1       cgd {
   1667       1.8   deraadt 
   1668       1.1       cgd 	reply(code, "%s: %s.", string, strerror(errno));
   1669       1.1       cgd }
   1670       1.1       cgd 
   1671       1.1       cgd static char *onefile[] = {
   1672       1.1       cgd 	"",
   1673       1.1       cgd 	0
   1674       1.1       cgd };
   1675       1.1       cgd 
   1676       1.8   deraadt void
   1677       1.8   deraadt send_file_list(whichf)
   1678       1.8   deraadt 	char *whichf;
   1679       1.1       cgd {
   1680       1.1       cgd 	struct stat st;
   1681       1.1       cgd 	DIR *dirp = NULL;
   1682       1.1       cgd 	struct dirent *dir;
   1683       1.1       cgd 	FILE *dout = NULL;
   1684       1.8   deraadt 	char **dirlist, *dirname;
   1685       1.1       cgd 	int simple = 0;
   1686       1.8   deraadt 	int freeglob = 0;
   1687       1.8   deraadt 	glob_t gl;
   1688      1.25  christos #ifdef __GNUC__
   1689      1.25  christos 	(void) &dout;
   1690      1.25  christos 	(void) &dirlist;
   1691      1.25  christos 	(void) &simple;
   1692      1.25  christos 	(void) &freeglob;
   1693      1.25  christos #endif
   1694       1.1       cgd 
   1695       1.8   deraadt 	if (strpbrk(whichf, "~{[*?") != NULL) {
   1696      1.50    kleink 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
   1697       1.1       cgd 
   1698       1.8   deraadt 		memset(&gl, 0, sizeof(gl));
   1699       1.8   deraadt 		freeglob = 1;
   1700       1.8   deraadt 		if (glob(whichf, flags, 0, &gl)) {
   1701       1.8   deraadt 			reply(550, "not found");
   1702       1.8   deraadt 			goto out;
   1703       1.8   deraadt 		} else if (gl.gl_pathc == 0) {
   1704       1.1       cgd 			errno = ENOENT;
   1705       1.8   deraadt 			perror_reply(550, whichf);
   1706       1.8   deraadt 			goto out;
   1707       1.1       cgd 		}
   1708       1.8   deraadt 		dirlist = gl.gl_pathv;
   1709       1.1       cgd 	} else {
   1710       1.8   deraadt 		onefile[0] = whichf;
   1711       1.1       cgd 		dirlist = onefile;
   1712       1.1       cgd 		simple = 1;
   1713       1.1       cgd 	}
   1714       1.1       cgd 
   1715       1.1       cgd 	if (setjmp(urgcatch)) {
   1716       1.1       cgd 		transflag = 0;
   1717       1.8   deraadt 		goto out;
   1718       1.1       cgd 	}
   1719      1.20     lukem 	while ((dirname = *dirlist++) != NULL) {
   1720      1.33     lukem 		int trailingslash = 0;
   1721      1.33     lukem 
   1722       1.1       cgd 		if (stat(dirname, &st) < 0) {
   1723       1.1       cgd 			/*
   1724       1.1       cgd 			 * If user typed "ls -l", etc, and the client
   1725       1.1       cgd 			 * used NLST, do what the user meant.
   1726       1.1       cgd 			 */
   1727       1.1       cgd 			if (dirname[0] == '-' && *dirlist == NULL &&
   1728       1.1       cgd 			    transflag == 0) {
   1729       1.1       cgd 				retrieve("/bin/ls %s", dirname);
   1730       1.8   deraadt 				goto out;
   1731       1.1       cgd 			}
   1732       1.8   deraadt 			perror_reply(550, whichf);
   1733       1.1       cgd 			if (dout != NULL) {
   1734       1.1       cgd 				(void) fclose(dout);
   1735       1.1       cgd 				transflag = 0;
   1736       1.1       cgd 				data = -1;
   1737       1.1       cgd 				pdata = -1;
   1738       1.1       cgd 			}
   1739       1.8   deraadt 			goto out;
   1740       1.1       cgd 		}
   1741       1.1       cgd 
   1742       1.8   deraadt 		if (S_ISREG(st.st_mode)) {
   1743       1.1       cgd 			if (dout == NULL) {
   1744       1.1       cgd 				dout = dataconn("file list", (off_t)-1, "w");
   1745       1.1       cgd 				if (dout == NULL)
   1746       1.8   deraadt 					goto out;
   1747       1.1       cgd 				transflag++;
   1748       1.1       cgd 			}
   1749       1.1       cgd 			fprintf(dout, "%s%s\n", dirname,
   1750       1.1       cgd 				type == TYPE_A ? "\r" : "");
   1751       1.1       cgd 			byte_count += strlen(dirname) + 1;
   1752       1.1       cgd 			continue;
   1753       1.8   deraadt 		} else if (!S_ISDIR(st.st_mode))
   1754       1.1       cgd 			continue;
   1755       1.1       cgd 
   1756      1.33     lukem 		if (dirname[strlen(dirname) - 1] == '/')
   1757      1.33     lukem 			trailingslash++;
   1758      1.33     lukem 
   1759       1.1       cgd 		if ((dirp = opendir(dirname)) == NULL)
   1760       1.1       cgd 			continue;
   1761       1.1       cgd 
   1762       1.1       cgd 		while ((dir = readdir(dirp)) != NULL) {
   1763      1.61     lukem 			char nbuf[MAXPATHLEN + 1];
   1764       1.1       cgd 
   1765       1.1       cgd 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
   1766       1.1       cgd 				continue;
   1767       1.1       cgd 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
   1768       1.1       cgd 			    dir->d_namlen == 2)
   1769       1.1       cgd 				continue;
   1770       1.1       cgd 
   1771      1.33     lukem 			(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
   1772      1.33     lukem 			    trailingslash ? "" : "/", dir->d_name);
   1773       1.1       cgd 
   1774       1.1       cgd 			/*
   1775      1.30     lukem 			 * We have to do a stat to ensure it's
   1776       1.1       cgd 			 * not a directory or special file.
   1777       1.1       cgd 			 */
   1778       1.1       cgd 			if (simple || (stat(nbuf, &st) == 0 &&
   1779       1.8   deraadt 			    S_ISREG(st.st_mode))) {
   1780       1.1       cgd 				if (dout == NULL) {
   1781       1.1       cgd 					dout = dataconn("file list", (off_t)-1,
   1782       1.1       cgd 						"w");
   1783       1.1       cgd 					if (dout == NULL)
   1784       1.8   deraadt 						goto out;
   1785       1.1       cgd 					transflag++;
   1786       1.1       cgd 				}
   1787       1.1       cgd 				if (nbuf[0] == '.' && nbuf[1] == '/')
   1788       1.1       cgd 					fprintf(dout, "%s%s\n", &nbuf[2],
   1789       1.1       cgd 						type == TYPE_A ? "\r" : "");
   1790       1.1       cgd 				else
   1791       1.1       cgd 					fprintf(dout, "%s%s\n", nbuf,
   1792       1.1       cgd 						type == TYPE_A ? "\r" : "");
   1793       1.1       cgd 				byte_count += strlen(nbuf) + 1;
   1794       1.1       cgd 			}
   1795       1.1       cgd 		}
   1796       1.1       cgd 		(void) closedir(dirp);
   1797       1.1       cgd 	}
   1798       1.1       cgd 
   1799       1.1       cgd 	if (dout == NULL)
   1800       1.1       cgd 		reply(550, "No files found.");
   1801       1.1       cgd 	else if (ferror(dout) != 0)
   1802       1.1       cgd 		perror_reply(550, "Data connection");
   1803       1.1       cgd 	else
   1804       1.1       cgd 		reply(226, "Transfer complete.");
   1805       1.1       cgd 
   1806       1.1       cgd 	transflag = 0;
   1807       1.1       cgd 	if (dout != NULL)
   1808       1.1       cgd 		(void) fclose(dout);
   1809       1.1       cgd 	data = -1;
   1810       1.1       cgd 	pdata = -1;
   1811       1.8   deraadt out:
   1812       1.8   deraadt 	if (freeglob) {
   1813       1.8   deraadt 		freeglob = 0;
   1814       1.8   deraadt 		globfree(&gl);
   1815       1.8   deraadt 	}
   1816      1.34     lukem }
   1817      1.34     lukem 
   1818      1.34     lukem char *
   1819      1.34     lukem conffilename(s)
   1820      1.34     lukem 	const char *s;
   1821      1.34     lukem {
   1822      1.61     lukem 	static char filename[MAXPATHLEN + 1];
   1823      1.34     lukem 
   1824      1.34     lukem 	(void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
   1825      1.34     lukem 	return filename;
   1826       1.1       cgd }
   1827