Home | History | Annotate | Line # | Download | only in ftpd
ftpd.c revision 1.61.2.4
      1  1.61.2.4        he /*	$NetBSD: ftpd.c,v 1.61.2.4 2000/12/14 22:33:47 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.4        he __RCSID("$NetBSD: ftpd.c,v 1.61.2.4 2000/12/14 22:33:47 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.61.2.4        he const char version[] = "Version: 7.1.0a";
    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.21       cjs 		if (fnmatch(glob, name, 0) == 0)  {
    493      1.58     lukem 			if (perm != NULL &&
    494      1.58     lukem 			    ((strcasecmp(perm, "allow") == 0) ||
    495      1.58     lukem 			    (strcasecmp(perm, "yes") == 0)))
    496      1.58     lukem 				retval = TRUE;
    497      1.58     lukem 			else if (perm != NULL &&
    498      1.58     lukem 			    ((strcasecmp(perm, "deny") == 0) ||
    499      1.58     lukem 			    (strcasecmp(perm, "no") == 0)))
    500      1.58     lukem 				retval = FALSE;
    501      1.19       cjs 			else
    502      1.58     lukem 				retval = !def;
    503      1.21       cjs 			break;
    504      1.19       cjs 		}
    505      1.19       cjs 	}
    506      1.19       cjs 	(void) fclose(fd);
    507      1.21       cjs 	return (retval);
    508      1.19       cjs }
    509      1.58     lukem 
    510      1.58     lukem /*
    511      1.58     lukem  * Check if user is allowed by /etc/ftpusers
    512      1.58     lukem  * returns 0 for yes, 1 for no
    513      1.58     lukem  */
    514      1.58     lukem int
    515      1.58     lukem checkaccess(name)
    516      1.58     lukem 	const char *name;
    517      1.58     lukem {
    518      1.58     lukem 
    519      1.58     lukem 	return (! checkuser(_PATH_FTPUSERS, name, TRUE, FALSE));
    520      1.58     lukem }
    521      1.19       cjs 
    522      1.19       cjs /*
    523       1.1       cgd  * Terminate login as previous user, if any, resetting state;
    524       1.1       cgd  * used when USER command is given or login fails.
    525       1.1       cgd  */
    526       1.8   deraadt static void
    527       1.1       cgd end_login()
    528       1.1       cgd {
    529       1.1       cgd 
    530       1.1       cgd 	(void) seteuid((uid_t)0);
    531       1.1       cgd 	if (logged_in)
    532       1.1       cgd 		logwtmp(ttyline, "", "");
    533       1.1       cgd 	pw = NULL;
    534       1.1       cgd 	logged_in = 0;
    535       1.1       cgd 	guest = 0;
    536       1.5       cgd 	dochroot = 0;
    537       1.1       cgd }
    538       1.1       cgd 
    539       1.8   deraadt void
    540       1.1       cgd pass(passwd)
    541       1.1       cgd 	char *passwd;
    542       1.1       cgd {
    543       1.4       cgd 	int rval;
    544       1.8   deraadt 	FILE *fd;
    545      1.53   mycroft 	char const *cp, *shell, *home;
    546       1.1       cgd 
    547       1.1       cgd 	if (logged_in || askpasswd == 0) {
    548       1.1       cgd 		reply(503, "Login with USER first.");
    549       1.1       cgd 		return;
    550       1.1       cgd 	}
    551       1.1       cgd 	askpasswd = 0;
    552       1.1       cgd 	if (!guest) {		/* "ftp" is only account allowed no password */
    553       1.8   deraadt 		if (pw == NULL) {
    554       1.8   deraadt 			rval = 1;	/* failure below */
    555       1.8   deraadt 			goto skip;
    556       1.8   deraadt 		}
    557      1.37   mycroft #ifdef KERBEROS
    558      1.38   mycroft 		if (klogin(pw, "", hostname, passwd) == 0) {
    559      1.38   mycroft 			rval = 0;
    560      1.38   mycroft 			goto skip;
    561      1.38   mycroft 		}
    562      1.38   mycroft #endif
    563      1.38   mycroft #ifdef KERBEROS5
    564      1.37   mycroft 		if (klogin(pw, "", hostname, passwd) == 0) {
    565      1.37   mycroft 			rval = 0;
    566      1.37   mycroft 			goto skip;
    567      1.37   mycroft 		}
    568      1.37   mycroft #endif
    569      1.36   mycroft #ifdef SKEY
    570      1.36   mycroft 		if (skey_haskey(pw->pw_name) == 0 &&
    571      1.36   mycroft 		    skey_passcheck(pw->pw_name, passwd) != -1) {
    572      1.36   mycroft 			rval = 0;
    573       1.8   deraadt 			goto skip;
    574      1.36   mycroft 		}
    575       1.4       cgd #endif
    576      1.51   msaitoh 		if (!sflag && *pw->pw_passwd != '\0' &&
    577      1.37   mycroft 		    !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
    578       1.8   deraadt 			rval = 0;
    579       1.8   deraadt 			goto skip;
    580       1.8   deraadt 		}
    581      1.37   mycroft 		rval = 1;
    582       1.4       cgd 
    583       1.8   deraadt skip:
    584      1.46       cjs 		if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire)
    585      1.45  christos 			rval = 2;
    586       1.4       cgd 		/*
    587      1.45  christos 		 * If rval > 0, the user failed the authentication check
    588       1.4       cgd 		 * above.  If rval == 0, either Kerberos or local authentication
    589       1.4       cgd 		 * succeeded.
    590       1.4       cgd 		 */
    591       1.4       cgd 		if (rval) {
    592      1.45  christos 			reply(530, rval == 2 ? "Password expired." :
    593      1.45  christos 			    "Login incorrect.");
    594      1.23     lukem 			if (logging) {
    595       1.8   deraadt 				syslog(LOG_NOTICE,
    596      1.23     lukem 				    "FTP LOGIN FAILED FROM %s", remotehost);
    597      1.23     lukem 				syslog(LOG_AUTHPRIV | LOG_NOTICE,
    598       1.8   deraadt 				    "FTP LOGIN FAILED FROM %s, %s",
    599       1.8   deraadt 				    remotehost, curname);
    600      1.23     lukem 			}
    601       1.1       cgd 			pw = NULL;
    602       1.1       cgd 			if (login_attempts++ >= 5) {
    603       1.1       cgd 				syslog(LOG_NOTICE,
    604       1.1       cgd 				    "repeated login failures from %s",
    605       1.1       cgd 				    remotehost);
    606       1.1       cgd 				exit(0);
    607       1.1       cgd 			}
    608       1.1       cgd 			return;
    609       1.1       cgd 		}
    610       1.1       cgd 	}
    611      1.19       cjs 
    612      1.19       cjs 	/* password was ok; see if anything else prevents login */
    613      1.19       cjs 	if (checkaccess(pw->pw_name))  {
    614      1.19       cjs 		reply(530, "User %s may not use FTP.", pw->pw_name);
    615      1.19       cjs 		if (logging)
    616      1.19       cjs 			syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
    617      1.19       cjs 			    remotehost, pw->pw_name);
    618      1.19       cjs 		pw = (struct passwd *) NULL;
    619      1.19       cjs 		return;
    620      1.19       cjs 	}
    621      1.19       cjs 	/* check for valid shell, if not guest user */
    622      1.19       cjs 	if ((shell = pw->pw_shell) == NULL || *shell == 0)
    623      1.19       cjs 		shell = _PATH_BSHELL;
    624      1.19       cjs 	while ((cp = getusershell()) != NULL)
    625      1.19       cjs 		if (strcmp(cp, shell) == 0)
    626      1.19       cjs 			break;
    627      1.19       cjs 	endusershell();
    628      1.19       cjs 	if (cp == NULL && guest == 0) {
    629      1.19       cjs 		reply(530, "User %s may not use FTP.", pw->pw_name);
    630      1.19       cjs 		if (logging)
    631      1.19       cjs 			syslog(LOG_NOTICE,
    632      1.19       cjs 			    "FTP LOGIN REFUSED FROM %s, %s",
    633      1.19       cjs 			    remotehost, pw->pw_name);
    634      1.19       cjs 		pw = (struct passwd *) NULL;
    635      1.19       cjs 		return;
    636      1.19       cjs 	}
    637      1.19       cjs 
    638       1.1       cgd 	login_attempts = 0;		/* this time successful */
    639       1.8   deraadt 	if (setegid((gid_t)pw->pw_gid) < 0) {
    640       1.8   deraadt 		reply(550, "Can't set gid.");
    641       1.8   deraadt 		return;
    642       1.8   deraadt 	}
    643       1.1       cgd 	(void) initgroups(pw->pw_name, pw->pw_gid);
    644       1.1       cgd 
    645       1.1       cgd 	/* open wtmp before chroot */
    646       1.1       cgd 	logwtmp(ttyline, pw->pw_name, remotehost);
    647       1.1       cgd 	logged_in = 1;
    648       1.1       cgd 
    649      1.58     lukem 	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name, FALSE, FALSE);
    650      1.24     lukem 
    651      1.24     lukem 	/* parse ftpd.conf, setting up various parameters */
    652      1.24     lukem 	if (guest)
    653      1.24     lukem 		parse_conf(CLASS_GUEST);
    654      1.24     lukem 	else if (dochroot)
    655      1.24     lukem 		parse_conf(CLASS_CHROOT);
    656      1.24     lukem 	else
    657      1.24     lukem 		parse_conf(CLASS_REAL);
    658      1.24     lukem 
    659      1.44     lukem 	home = "/";
    660       1.1       cgd 	if (guest) {
    661       1.1       cgd 		/*
    662       1.1       cgd 		 * We MUST do a chdir() after the chroot. Otherwise
    663       1.1       cgd 		 * the old current directory will be accessible as "."
    664       1.1       cgd 		 * outside the new root!
    665       1.1       cgd 		 */
    666      1.24     lukem 		if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
    667      1.24     lukem 		    chdir("/") < 0) {
    668       1.1       cgd 			reply(550, "Can't set guest privileges.");
    669       1.5       cgd 			goto bad;
    670       1.5       cgd 		}
    671       1.5       cgd 	} else if (dochroot) {
    672       1.5       cgd 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
    673       1.5       cgd 			reply(550, "Can't change root.");
    674       1.1       cgd 			goto bad;
    675       1.1       cgd 		}
    676       1.1       cgd 	} else if (chdir(pw->pw_dir) < 0) {
    677       1.1       cgd 		if (chdir("/") < 0) {
    678       1.1       cgd 			reply(530, "User %s: can't change directory to %s.",
    679       1.1       cgd 			    pw->pw_name, pw->pw_dir);
    680       1.1       cgd 			goto bad;
    681       1.1       cgd 		} else
    682       1.1       cgd 			lreply(230, "No directory! Logging in with home=/");
    683      1.44     lukem 	} else
    684      1.44     lukem 		home = pw->pw_dir;
    685       1.1       cgd 	if (seteuid((uid_t)pw->pw_uid) < 0) {
    686       1.1       cgd 		reply(550, "Can't set uid.");
    687       1.1       cgd 		goto bad;
    688       1.1       cgd 	}
    689      1.44     lukem 	setenv("HOME", home, 1);
    690      1.44     lukem 
    691      1.44     lukem 
    692       1.8   deraadt 	/*
    693       1.8   deraadt 	 * Display a login message, if it exists.
    694       1.8   deraadt 	 * N.B. reply(230,) must follow the message.
    695       1.8   deraadt 	 */
    696      1.34     lukem 	if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) {
    697       1.8   deraadt 		char *cp, line[LINE_MAX];
    698       1.8   deraadt 
    699       1.8   deraadt 		while (fgets(line, sizeof(line), fd) != NULL) {
    700       1.8   deraadt 			if ((cp = strchr(line, '\n')) != NULL)
    701       1.8   deraadt 				*cp = '\0';
    702       1.8   deraadt 			lreply(230, "%s", line);
    703       1.8   deraadt 		}
    704       1.8   deraadt 		(void) fflush(stdout);
    705       1.8   deraadt 		(void) fclose(fd);
    706       1.8   deraadt 	}
    707      1.24     lukem 	show_chdir_messages(230);
    708       1.1       cgd 	if (guest) {
    709       1.1       cgd 		reply(230, "Guest login ok, access restrictions apply.");
    710       1.6       cgd #ifdef HASSETPROCTITLE
    711       1.8   deraadt 		snprintf(proctitle, sizeof(proctitle),
    712       1.8   deraadt 		    "%s: anonymous/%.*s", remotehost,
    713      1.25  christos 		    (int) (sizeof(proctitle) - sizeof(remotehost) -
    714      1.25  christos 		    sizeof(": anonymous/")), passwd);
    715  1.61.2.3        he 		setproctitle("%s", proctitle);
    716       1.6       cgd #endif /* HASSETPROCTITLE */
    717       1.1       cgd 		if (logging)
    718       1.1       cgd 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
    719       1.1       cgd 			    remotehost, passwd);
    720       1.1       cgd 	} else {
    721       1.1       cgd 		reply(230, "User %s logged in.", pw->pw_name);
    722       1.6       cgd #ifdef HASSETPROCTITLE
    723       1.8   deraadt 		snprintf(proctitle, sizeof(proctitle),
    724       1.8   deraadt 		    "%s: %s", remotehost, pw->pw_name);
    725  1.61.2.3        he 		setproctitle("%s", proctitle);
    726       1.6       cgd #endif /* HASSETPROCTITLE */
    727       1.1       cgd 		if (logging)
    728       1.8   deraadt 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
    729       1.1       cgd 			    remotehost, pw->pw_name);
    730       1.1       cgd 	}
    731      1.24     lukem 	(void) umask(curclass.umask);
    732       1.1       cgd 	return;
    733       1.1       cgd bad:
    734       1.1       cgd 	/* Forget all about it... */
    735       1.1       cgd 	end_login();
    736       1.1       cgd }
    737       1.1       cgd 
    738       1.8   deraadt void
    739       1.1       cgd retrieve(cmd, name)
    740       1.1       cgd 	char *cmd, *name;
    741       1.1       cgd {
    742      1.28  christos 	FILE *fin = NULL, *dout;
    743       1.1       cgd 	struct stat st;
    744      1.28  christos 	int (*closefunc) __P((FILE *)) = NULL;
    745      1.49     lukem 	int log, sendrv, closerv, stderrfd, isconversion;
    746       1.1       cgd 
    747      1.49     lukem 	sendrv = closerv = stderrfd = -1;
    748      1.49     lukem 	isconversion = 0;
    749      1.24     lukem 	log = (cmd == 0);
    750      1.49     lukem 	if (cmd == NULL) {
    751       1.1       cgd 		fin = fopen(name, "r"), closefunc = fclose;
    752      1.24     lukem 		if (fin == NULL)
    753      1.24     lukem 			cmd = do_conversion(name);
    754      1.49     lukem 		if (cmd != NULL) {
    755      1.49     lukem 			isconversion++;
    756      1.49     lukem 			syslog(LOG_INFO, "get command: '%s'", cmd);
    757      1.49     lukem 		}
    758      1.24     lukem 	}
    759      1.49     lukem 	if (cmd != NULL) {
    760       1.1       cgd 		char line[BUFSIZ];
    761      1.61     lukem 		char temp[MAXPATHLEN + 1];
    762       1.1       cgd 
    763      1.49     lukem 		(void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
    764      1.49     lukem 		stderrfd = mkstemp(temp);
    765      1.49     lukem 		if (stderrfd != -1)
    766      1.49     lukem 			(void)unlink(temp);
    767      1.30     lukem 		(void)snprintf(line, sizeof(line), cmd, name), name = line;
    768      1.49     lukem 		fin = ftpd_popen(line, "r", stderrfd), closefunc = ftpd_pclose;
    769       1.1       cgd 		st.st_size = -1;
    770       1.1       cgd 		st.st_blksize = BUFSIZ;
    771       1.1       cgd 	}
    772       1.1       cgd 	if (fin == NULL) {
    773       1.8   deraadt 		if (errno != 0) {
    774       1.1       cgd 			perror_reply(550, name);
    775      1.24     lukem 			if (log) {
    776      1.61     lukem 				logcmd("get", -1, name, NULL);
    777       1.8   deraadt 			}
    778       1.8   deraadt 		}
    779      1.49     lukem 		if (stderrfd != -1)
    780      1.49     lukem 			(void)close(stderrfd);
    781       1.1       cgd 		return;
    782       1.1       cgd 	}
    783       1.8   deraadt 	byte_count = -1;
    784      1.49     lukem 	if (cmd == NULL
    785      1.49     lukem 	    && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
    786       1.1       cgd 		reply(550, "%s: not a plain file.", name);
    787       1.1       cgd 		goto done;
    788       1.1       cgd 	}
    789       1.1       cgd 	if (restart_point) {
    790       1.1       cgd 		if (type == TYPE_A) {
    791      1.49     lukem 			off_t i;
    792       1.8   deraadt 			int c;
    793       1.1       cgd 
    794      1.49     lukem 			for (i = 0; i < restart_point; i++) {
    795       1.1       cgd 				if ((c=getc(fin)) == EOF) {
    796       1.1       cgd 					perror_reply(550, name);
    797       1.1       cgd 					goto done;
    798       1.1       cgd 				}
    799       1.1       cgd 				if (c == '\n')
    800       1.1       cgd 					i++;
    801       1.8   deraadt 			}
    802      1.31    kleink 		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
    803       1.1       cgd 			perror_reply(550, name);
    804       1.1       cgd 			goto done;
    805       1.1       cgd 		}
    806       1.1       cgd 	}
    807       1.1       cgd 	dout = dataconn(name, st.st_size, "w");
    808       1.1       cgd 	if (dout == NULL)
    809       1.1       cgd 		goto done;
    810      1.49     lukem 	sendrv = send_data(fin, dout, st.st_blksize);
    811       1.1       cgd 	(void) fclose(dout);
    812       1.1       cgd 	data = -1;
    813       1.1       cgd 	pdata = -1;
    814       1.1       cgd done:
    815      1.24     lukem 	if (log)
    816      1.61     lukem 		logcmd("get", byte_count, name, NULL);
    817      1.49     lukem 	closerv = (*closefunc)(fin);
    818      1.49     lukem 	if (sendrv == 0) {
    819      1.49     lukem 		FILE *err;
    820      1.49     lukem 		struct stat sb;
    821      1.49     lukem 
    822      1.49     lukem 		if (cmd != NULL && closerv != 0) {
    823      1.49     lukem 			lreply(226,
    824      1.49     lukem 			    "Command returned an exit status of %d",
    825      1.49     lukem 			    closerv);
    826      1.49     lukem 			if (isconversion)
    827      1.49     lukem 				syslog(LOG_INFO,
    828      1.49     lukem 				    "get command: '%s' returned %d",
    829      1.49     lukem 				    cmd, closerv);
    830      1.49     lukem 		}
    831      1.49     lukem 		if (cmd != NULL && stderrfd != -1 &&
    832      1.49     lukem 		    (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
    833      1.49     lukem 		    ((err = fdopen(stderrfd, "r")) != NULL)) {
    834      1.49     lukem 			char *cp, line[LINE_MAX];
    835      1.49     lukem 
    836      1.49     lukem 			lreply(226, "Command error messages:");
    837      1.49     lukem 			rewind(err);
    838      1.49     lukem 			while (fgets(line, sizeof(line), err) != NULL) {
    839      1.49     lukem 				if ((cp = strchr(line, '\n')) != NULL)
    840      1.49     lukem 					*cp = '\0';
    841      1.49     lukem 				lreply(226, " %s", line);
    842      1.49     lukem 			}
    843      1.49     lukem 			(void) fflush(stdout);
    844      1.49     lukem 			(void) fclose(err);
    845      1.49     lukem 			lreply(226, "End of command error messages.");
    846      1.49     lukem 				/* a reply(226,) must follow */
    847      1.49     lukem 		}
    848      1.49     lukem 		reply(226, "Transfer complete.");
    849      1.49     lukem 	}
    850      1.49     lukem 	if (stderrfd != -1)
    851      1.49     lukem 		(void)close(stderrfd);
    852       1.1       cgd }
    853       1.1       cgd 
    854       1.8   deraadt void
    855       1.1       cgd store(name, mode, unique)
    856       1.1       cgd 	char *name, *mode;
    857       1.1       cgd 	int unique;
    858       1.1       cgd {
    859       1.1       cgd 	FILE *fout, *din;
    860       1.1       cgd 	struct stat st;
    861       1.8   deraadt 	int (*closefunc) __P((FILE *));
    862       1.1       cgd 
    863       1.1       cgd 	if (unique && stat(name, &st) == 0 &&
    864       1.8   deraadt 	    (name = gunique(name)) == NULL) {
    865      1.61     lukem 		logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL);
    866       1.1       cgd 		return;
    867       1.8   deraadt 	}
    868       1.1       cgd 
    869       1.1       cgd 	if (restart_point)
    870       1.8   deraadt 		mode = "r+";
    871       1.1       cgd 	fout = fopen(name, mode);
    872       1.1       cgd 	closefunc = fclose;
    873       1.1       cgd 	if (fout == NULL) {
    874       1.1       cgd 		perror_reply(553, name);
    875      1.61     lukem 		logcmd(*mode == 'w' ? "put" : "append", -1, name, NULL);
    876       1.1       cgd 		return;
    877       1.1       cgd 	}
    878       1.8   deraadt 	byte_count = -1;
    879       1.1       cgd 	if (restart_point) {
    880       1.1       cgd 		if (type == TYPE_A) {
    881      1.49     lukem 			off_t i;
    882       1.8   deraadt 			int c;
    883       1.1       cgd 
    884      1.49     lukem 			for (i = 0; i < restart_point; i++) {
    885       1.1       cgd 				if ((c=getc(fout)) == EOF) {
    886       1.1       cgd 					perror_reply(550, name);
    887       1.1       cgd 					goto done;
    888       1.1       cgd 				}
    889       1.1       cgd 				if (c == '\n')
    890       1.1       cgd 					i++;
    891       1.8   deraadt 			}
    892       1.1       cgd 			/*
    893       1.1       cgd 			 * We must do this seek to "current" position
    894       1.1       cgd 			 * because we are changing from reading to
    895       1.1       cgd 			 * writing.
    896       1.1       cgd 			 */
    897      1.20     lukem 			if (fseek(fout, 0L, SEEK_CUR) < 0) {
    898       1.1       cgd 				perror_reply(550, name);
    899       1.1       cgd 				goto done;
    900       1.1       cgd 			}
    901      1.31    kleink 		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
    902       1.1       cgd 			perror_reply(550, name);
    903       1.1       cgd 			goto done;
    904       1.1       cgd 		}
    905       1.1       cgd 	}
    906       1.1       cgd 	din = dataconn(name, (off_t)-1, "r");
    907       1.1       cgd 	if (din == NULL)
    908       1.1       cgd 		goto done;
    909       1.1       cgd 	if (receive_data(din, fout) == 0) {
    910       1.1       cgd 		if (unique)
    911       1.1       cgd 			reply(226, "Transfer complete (unique file name:%s).",
    912       1.1       cgd 			    name);
    913       1.1       cgd 		else
    914       1.1       cgd 			reply(226, "Transfer complete.");
    915       1.1       cgd 	}
    916       1.1       cgd 	(void) fclose(din);
    917       1.1       cgd 	data = -1;
    918       1.1       cgd 	pdata = -1;
    919       1.1       cgd done:
    920      1.61     lukem 	logcmd(*mode == 'w' ? "put" : "append", byte_count, name, NULL);
    921       1.1       cgd 	(*closefunc)(fout);
    922       1.1       cgd }
    923       1.1       cgd 
    924       1.8   deraadt static FILE *
    925       1.1       cgd getdatasock(mode)
    926       1.1       cgd 	char *mode;
    927       1.1       cgd {
    928       1.8   deraadt 	int on = 1, s, t, tries;
    929       1.1       cgd 
    930       1.1       cgd 	if (data >= 0)
    931       1.1       cgd 		return (fdopen(data, mode));
    932       1.1       cgd 	(void) seteuid((uid_t)0);
    933       1.1       cgd 	s = socket(AF_INET, SOCK_STREAM, 0);
    934       1.1       cgd 	if (s < 0)
    935       1.1       cgd 		goto bad;
    936       1.1       cgd 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
    937       1.8   deraadt 	    (char *) &on, sizeof(on)) < 0)
    938       1.1       cgd 		goto bad;
    939       1.1       cgd 	/* anchor socket to avoid multi-homing problems */
    940      1.15   mycroft 	data_source.sin_len = sizeof(struct sockaddr_in);
    941       1.1       cgd 	data_source.sin_family = AF_INET;
    942       1.1       cgd 	data_source.sin_addr = ctrl_addr.sin_addr;
    943       1.1       cgd 	for (tries = 1; ; tries++) {
    944       1.1       cgd 		if (bind(s, (struct sockaddr *)&data_source,
    945       1.8   deraadt 		    sizeof(data_source)) >= 0)
    946       1.1       cgd 			break;
    947       1.1       cgd 		if (errno != EADDRINUSE || tries > 10)
    948       1.1       cgd 			goto bad;
    949       1.1       cgd 		sleep(tries);
    950       1.1       cgd 	}
    951       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
    952       1.1       cgd #ifdef IP_TOS
    953       1.1       cgd 	on = IPTOS_THROUGHPUT;
    954       1.1       cgd 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
    955       1.1       cgd 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
    956       1.1       cgd #endif
    957       1.1       cgd 	return (fdopen(s, mode));
    958       1.1       cgd bad:
    959       1.8   deraadt 	/* Return the real value of errno (close may change it) */
    960       1.8   deraadt 	t = errno;
    961       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
    962       1.1       cgd 	(void) close(s);
    963       1.8   deraadt 	errno = t;
    964       1.1       cgd 	return (NULL);
    965       1.1       cgd }
    966       1.1       cgd 
    967       1.8   deraadt static FILE *
    968       1.1       cgd dataconn(name, size, mode)
    969       1.1       cgd 	char *name;
    970       1.1       cgd 	off_t size;
    971       1.1       cgd 	char *mode;
    972       1.1       cgd {
    973       1.1       cgd 	char sizebuf[32];
    974       1.1       cgd 	FILE *file;
    975       1.1       cgd 	int retry = 0, tos;
    976       1.1       cgd 
    977       1.1       cgd 	file_size = size;
    978       1.1       cgd 	byte_count = 0;
    979       1.1       cgd 	if (size != (off_t) -1)
    980      1.30     lukem 		(void)snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
    981      1.29       mrg 		    (long long)size);
    982       1.1       cgd 	else
    983      1.29       mrg 		sizebuf[0] = '\0';
    984       1.1       cgd 	if (pdata >= 0) {
    985       1.1       cgd 		struct sockaddr_in from;
    986       1.1       cgd 		int s, fromlen = sizeof(from);
    987       1.1       cgd 
    988      1.42     lukem 		(void) alarm(curclass.timeout);
    989       1.1       cgd 		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
    990      1.42     lukem 		(void) alarm(0);
    991       1.1       cgd 		if (s < 0) {
    992       1.1       cgd 			reply(425, "Can't open data connection.");
    993       1.1       cgd 			(void) close(pdata);
    994       1.1       cgd 			pdata = -1;
    995       1.8   deraadt 			return (NULL);
    996       1.1       cgd 		}
    997       1.1       cgd 		(void) close(pdata);
    998       1.1       cgd 		pdata = s;
    999       1.1       cgd #ifdef IP_TOS
   1000      1.12   mycroft 		tos = IPTOS_THROUGHPUT;
   1001       1.1       cgd 		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
   1002       1.1       cgd 		    sizeof(int));
   1003       1.1       cgd #endif
   1004       1.8   deraadt 		reply(150, "Opening %s mode data connection for '%s'%s.",
   1005       1.1       cgd 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1006       1.8   deraadt 		return (fdopen(pdata, mode));
   1007       1.1       cgd 	}
   1008       1.1       cgd 	if (data >= 0) {
   1009       1.8   deraadt 		reply(125, "Using existing data connection for '%s'%s.",
   1010       1.1       cgd 		    name, sizebuf);
   1011       1.1       cgd 		usedefault = 1;
   1012       1.1       cgd 		return (fdopen(data, mode));
   1013       1.1       cgd 	}
   1014       1.1       cgd 	if (usedefault)
   1015       1.1       cgd 		data_dest = his_addr;
   1016       1.1       cgd 	usedefault = 1;
   1017       1.1       cgd 	file = getdatasock(mode);
   1018       1.1       cgd 	if (file == NULL) {
   1019       1.1       cgd 		reply(425, "Can't create data socket (%s,%d): %s.",
   1020       1.1       cgd 		    inet_ntoa(data_source.sin_addr),
   1021       1.1       cgd 		    ntohs(data_source.sin_port), strerror(errno));
   1022       1.1       cgd 		return (NULL);
   1023       1.1       cgd 	}
   1024       1.1       cgd 	data = fileno(file);
   1025       1.1       cgd 	while (connect(data, (struct sockaddr *)&data_dest,
   1026       1.8   deraadt 	    sizeof(data_dest)) < 0) {
   1027       1.1       cgd 		if (errno == EADDRINUSE && retry < swaitmax) {
   1028       1.1       cgd 			sleep((unsigned) swaitint);
   1029       1.1       cgd 			retry += swaitint;
   1030       1.1       cgd 			continue;
   1031       1.1       cgd 		}
   1032       1.1       cgd 		perror_reply(425, "Can't build data connection");
   1033       1.1       cgd 		(void) fclose(file);
   1034       1.1       cgd 		data = -1;
   1035       1.1       cgd 		return (NULL);
   1036       1.1       cgd 	}
   1037       1.8   deraadt 	reply(150, "Opening %s mode data connection for '%s'%s.",
   1038       1.1       cgd 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
   1039       1.1       cgd 	return (file);
   1040       1.1       cgd }
   1041       1.1       cgd 
   1042       1.1       cgd /*
   1043       1.8   deraadt  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
   1044       1.8   deraadt  * encapsulation of the data subject * to Mode, Structure, and Type.
   1045       1.1       cgd  *
   1046       1.1       cgd  * NB: Form isn't handled.
   1047       1.1       cgd  */
   1048      1.49     lukem static int
   1049       1.1       cgd send_data(instr, outstr, blksize)
   1050       1.1       cgd 	FILE *instr, *outstr;
   1051       1.1       cgd 	off_t blksize;
   1052       1.1       cgd {
   1053      1.24     lukem 	int	 c, cnt, filefd, netfd;
   1054      1.24     lukem 	char	*buf;
   1055       1.1       cgd 
   1056       1.1       cgd 	transflag++;
   1057       1.1       cgd 	if (setjmp(urgcatch)) {
   1058       1.1       cgd 		transflag = 0;
   1059      1.49     lukem 		return (-1);
   1060       1.1       cgd 	}
   1061      1.24     lukem 
   1062       1.1       cgd 	switch (type) {
   1063       1.1       cgd 
   1064       1.1       cgd 	case TYPE_A:
   1065       1.1       cgd 		while ((c = getc(instr)) != EOF) {
   1066       1.1       cgd 			byte_count++;
   1067       1.1       cgd 			if (c == '\n') {
   1068       1.1       cgd 				if (ferror(outstr))
   1069       1.1       cgd 					goto data_err;
   1070       1.1       cgd 				(void) putc('\r', outstr);
   1071       1.1       cgd 			}
   1072       1.1       cgd 			(void) putc(c, outstr);
   1073       1.1       cgd 		}
   1074       1.1       cgd 		fflush(outstr);
   1075       1.1       cgd 		transflag = 0;
   1076       1.1       cgd 		if (ferror(instr))
   1077       1.1       cgd 			goto file_err;
   1078       1.1       cgd 		if (ferror(outstr))
   1079       1.1       cgd 			goto data_err;
   1080      1.49     lukem 		return (0);
   1081       1.1       cgd 
   1082       1.1       cgd 	case TYPE_I:
   1083       1.1       cgd 	case TYPE_L:
   1084       1.1       cgd 		if ((buf = malloc((u_int)blksize)) == NULL) {
   1085       1.1       cgd 			transflag = 0;
   1086       1.1       cgd 			perror_reply(451, "Local resource failure: malloc");
   1087      1.49     lukem 			return (-1);
   1088       1.1       cgd 		}
   1089       1.1       cgd 		netfd = fileno(outstr);
   1090       1.1       cgd 		filefd = fileno(instr);
   1091       1.1       cgd 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
   1092       1.1       cgd 		    write(netfd, buf, cnt) == cnt)
   1093       1.1       cgd 			byte_count += cnt;
   1094       1.1       cgd 		transflag = 0;
   1095       1.1       cgd 		(void)free(buf);
   1096       1.1       cgd 		if (cnt != 0) {
   1097       1.1       cgd 			if (cnt < 0)
   1098       1.1       cgd 				goto file_err;
   1099       1.1       cgd 			goto data_err;
   1100       1.1       cgd 		}
   1101      1.49     lukem 		return (0);
   1102       1.1       cgd 	default:
   1103       1.1       cgd 		transflag = 0;
   1104       1.1       cgd 		reply(550, "Unimplemented TYPE %d in send_data", type);
   1105      1.49     lukem 		return (-1);
   1106       1.1       cgd 	}
   1107       1.1       cgd 
   1108       1.1       cgd data_err:
   1109       1.1       cgd 	transflag = 0;
   1110       1.1       cgd 	perror_reply(426, "Data connection");
   1111      1.49     lukem 	return (-1);
   1112       1.1       cgd 
   1113       1.1       cgd file_err:
   1114       1.1       cgd 	transflag = 0;
   1115       1.1       cgd 	perror_reply(551, "Error on input file");
   1116      1.49     lukem 	return (-1);
   1117       1.1       cgd }
   1118       1.1       cgd 
   1119       1.1       cgd /*
   1120       1.8   deraadt  * Transfer data from peer to "outstr" using the appropriate encapulation of
   1121       1.8   deraadt  * the data subject to Mode, Structure, and Type.
   1122       1.1       cgd  *
   1123       1.1       cgd  * N.B.: Form isn't handled.
   1124       1.1       cgd  */
   1125       1.8   deraadt static int
   1126       1.1       cgd receive_data(instr, outstr)
   1127       1.1       cgd 	FILE *instr, *outstr;
   1128       1.1       cgd {
   1129      1.24     lukem 	int	c, cnt, bare_lfs;
   1130      1.24     lukem 	char	buf[BUFSIZ];
   1131      1.25  christos #ifdef __GNUC__
   1132      1.25  christos 	(void) &bare_lfs;
   1133      1.25  christos #endif
   1134       1.1       cgd 
   1135      1.24     lukem 	bare_lfs = 0;
   1136       1.1       cgd 	transflag++;
   1137       1.1       cgd 	if (setjmp(urgcatch)) {
   1138       1.1       cgd 		transflag = 0;
   1139       1.1       cgd 		return (-1);
   1140       1.1       cgd 	}
   1141      1.24     lukem 
   1142       1.1       cgd 	switch (type) {
   1143       1.1       cgd 
   1144       1.1       cgd 	case TYPE_I:
   1145       1.1       cgd 	case TYPE_L:
   1146       1.8   deraadt 		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
   1147       1.1       cgd 			if (write(fileno(outstr), buf, cnt) != cnt)
   1148       1.1       cgd 				goto file_err;
   1149       1.1       cgd 			byte_count += cnt;
   1150       1.1       cgd 		}
   1151       1.1       cgd 		if (cnt < 0)
   1152       1.1       cgd 			goto data_err;
   1153       1.1       cgd 		transflag = 0;
   1154       1.1       cgd 		return (0);
   1155       1.1       cgd 
   1156       1.1       cgd 	case TYPE_E:
   1157       1.1       cgd 		reply(553, "TYPE E not implemented.");
   1158       1.1       cgd 		transflag = 0;
   1159       1.1       cgd 		return (-1);
   1160       1.1       cgd 
   1161       1.1       cgd 	case TYPE_A:
   1162       1.1       cgd 		while ((c = getc(instr)) != EOF) {
   1163       1.1       cgd 			byte_count++;
   1164       1.1       cgd 			if (c == '\n')
   1165       1.1       cgd 				bare_lfs++;
   1166       1.1       cgd 			while (c == '\r') {
   1167       1.1       cgd 				if (ferror(outstr))
   1168       1.1       cgd 					goto data_err;
   1169       1.1       cgd 				if ((c = getc(instr)) != '\n') {
   1170       1.1       cgd 					(void) putc ('\r', outstr);
   1171       1.1       cgd 					if (c == '\0' || c == EOF)
   1172       1.1       cgd 						goto contin2;
   1173       1.1       cgd 				}
   1174       1.1       cgd 			}
   1175       1.1       cgd 			(void) putc(c, outstr);
   1176       1.1       cgd 	contin2:	;
   1177       1.1       cgd 		}
   1178       1.1       cgd 		fflush(outstr);
   1179       1.1       cgd 		if (ferror(instr))
   1180       1.1       cgd 			goto data_err;
   1181       1.1       cgd 		if (ferror(outstr))
   1182       1.1       cgd 			goto file_err;
   1183       1.1       cgd 		transflag = 0;
   1184       1.1       cgd 		if (bare_lfs) {
   1185       1.8   deraadt 			lreply(226,
   1186       1.8   deraadt 		"WARNING! %d bare linefeeds received in ASCII mode",
   1187       1.8   deraadt 			    bare_lfs);
   1188       1.8   deraadt 		(void)printf("   File may not have transferred correctly.\r\n");
   1189       1.1       cgd 		}
   1190       1.1       cgd 		return (0);
   1191       1.1       cgd 	default:
   1192       1.1       cgd 		reply(550, "Unimplemented TYPE %d in receive_data", type);
   1193       1.1       cgd 		transflag = 0;
   1194       1.1       cgd 		return (-1);
   1195       1.1       cgd 	}
   1196       1.1       cgd 
   1197       1.1       cgd data_err:
   1198       1.1       cgd 	transflag = 0;
   1199       1.1       cgd 	perror_reply(426, "Data Connection");
   1200       1.1       cgd 	return (-1);
   1201       1.1       cgd 
   1202       1.1       cgd file_err:
   1203       1.1       cgd 	transflag = 0;
   1204       1.1       cgd 	perror_reply(452, "Error writing file");
   1205       1.1       cgd 	return (-1);
   1206       1.1       cgd }
   1207       1.1       cgd 
   1208       1.8   deraadt void
   1209       1.1       cgd statfilecmd(filename)
   1210       1.1       cgd 	char *filename;
   1211       1.1       cgd {
   1212       1.1       cgd 	FILE *fin;
   1213       1.1       cgd 	int c;
   1214       1.8   deraadt 	char line[LINE_MAX];
   1215       1.1       cgd 
   1216       1.8   deraadt 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
   1217      1.49     lukem 	fin = ftpd_popen(line, "r", STDOUT_FILENO);
   1218       1.1       cgd 	lreply(211, "status of %s:", filename);
   1219       1.1       cgd 	while ((c = getc(fin)) != EOF) {
   1220       1.1       cgd 		if (c == '\n') {
   1221       1.1       cgd 			if (ferror(stdout)){
   1222       1.1       cgd 				perror_reply(421, "control connection");
   1223       1.1       cgd 				(void) ftpd_pclose(fin);
   1224       1.1       cgd 				dologout(1);
   1225       1.1       cgd 				/* NOTREACHED */
   1226       1.1       cgd 			}
   1227       1.1       cgd 			if (ferror(fin)) {
   1228       1.1       cgd 				perror_reply(551, filename);
   1229       1.1       cgd 				(void) ftpd_pclose(fin);
   1230       1.1       cgd 				return;
   1231       1.1       cgd 			}
   1232       1.1       cgd 			(void) putc('\r', stdout);
   1233       1.1       cgd 		}
   1234       1.1       cgd 		(void) putc(c, stdout);
   1235       1.1       cgd 	}
   1236       1.1       cgd 	(void) ftpd_pclose(fin);
   1237       1.1       cgd 	reply(211, "End of Status");
   1238       1.1       cgd }
   1239       1.1       cgd 
   1240       1.8   deraadt void
   1241       1.1       cgd statcmd()
   1242       1.1       cgd {
   1243       1.1       cgd 	struct sockaddr_in *sin;
   1244       1.1       cgd 	u_char *a, *p;
   1245       1.1       cgd 
   1246      1.24     lukem 	lreply(211, "%s FTP server status:", hostname);
   1247      1.24     lukem 	lreply(211, "%s", version);
   1248      1.24     lukem 	if (isdigit(remotehost[0]))
   1249      1.24     lukem 		lreply(211, "Connected to %s", remotehost);
   1250      1.24     lukem 	else
   1251      1.24     lukem 		lreply(211, "Connected to %s (%s)", remotehost,
   1252      1.24     lukem 		    inet_ntoa(his_addr.sin_addr));
   1253       1.1       cgd 	if (logged_in) {
   1254       1.1       cgd 		if (guest)
   1255      1.24     lukem 			lreply(211, "Logged in anonymously");
   1256       1.1       cgd 		else
   1257      1.24     lukem 			lreply(211, "Logged in as %s", pw->pw_name);
   1258       1.1       cgd 	} else if (askpasswd)
   1259      1.24     lukem 		lreply(211, "Waiting for password");
   1260       1.1       cgd 	else
   1261      1.24     lukem 		lreply(211, "Waiting for user name");
   1262      1.24     lukem 	printf("211- TYPE: %s", typenames[type]);
   1263       1.1       cgd 	if (type == TYPE_A || type == TYPE_E)
   1264       1.1       cgd 		printf(", FORM: %s", formnames[form]);
   1265       1.1       cgd 	if (type == TYPE_L)
   1266       1.1       cgd #if NBBY == 8
   1267       1.1       cgd 		printf(" %d", NBBY);
   1268       1.1       cgd #else
   1269       1.1       cgd 		printf(" %d", bytesize);	/* need definition! */
   1270       1.1       cgd #endif
   1271       1.1       cgd 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
   1272       1.1       cgd 	    strunames[stru], modenames[mode]);
   1273       1.1       cgd 	if (data != -1)
   1274      1.24     lukem 		lreply(211, "Data connection open");
   1275       1.1       cgd 	else if (pdata != -1) {
   1276      1.24     lukem 		printf("211- in Passive mode");
   1277       1.1       cgd 		sin = &pasv_addr;
   1278       1.1       cgd 		goto printaddr;
   1279       1.1       cgd 	} else if (usedefault == 0) {
   1280      1.24     lukem 		printf("211- PORT");
   1281       1.1       cgd 		sin = &data_dest;
   1282       1.1       cgd printaddr:
   1283       1.1       cgd 		a = (u_char *) &sin->sin_addr;
   1284       1.1       cgd 		p = (u_char *) &sin->sin_port;
   1285       1.1       cgd #define UC(b) (((int) b) & 0xff)
   1286       1.1       cgd 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
   1287       1.1       cgd 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
   1288       1.1       cgd #undef UC
   1289       1.1       cgd 	} else
   1290      1.24     lukem 		lreply(211, "No data connection");
   1291      1.24     lukem 
   1292      1.24     lukem 	if (logged_in) {
   1293      1.24     lukem 		struct ftpconv *cp;
   1294      1.24     lukem 
   1295      1.24     lukem 		lreply(211, "");
   1296      1.24     lukem 		lreply(211, "Class: %s", curclass.classname);
   1297      1.41     lukem 		lreply(211, "Check PORT commands: %sabled",
   1298      1.41     lukem 		    curclass.checkportcmd ? "en" : "dis");
   1299      1.24     lukem 		if (curclass.display)
   1300      1.24     lukem 			lreply(211, "Display file: %s", curclass.display);
   1301      1.24     lukem 		if (curclass.notify)
   1302      1.24     lukem 			lreply(211, "Notify fileglob: %s", curclass.notify);
   1303      1.24     lukem 		lreply(211, "Idle timeout: %d, maximum timeout: %d",
   1304      1.24     lukem 		    curclass.timeout, curclass.maxtimeout);
   1305      1.41     lukem 		lreply(211, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled",
   1306      1.24     lukem 		    curclass.modify ? "en" : "dis");
   1307      1.24     lukem 		lreply(211, "Umask: %.04o", curclass.umask);
   1308      1.24     lukem 		for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
   1309      1.24     lukem 			if (cp->suffix == NULL || cp->types == NULL ||
   1310      1.24     lukem 			    cp->command == NULL)
   1311      1.24     lukem 				continue;
   1312      1.24     lukem 			lreply(211,
   1313      1.24     lukem 			    "Conversion: %s [%s] disable: %s, command: %s",
   1314      1.24     lukem 			    cp->suffix, cp->types, cp->disable, cp->command);
   1315      1.24     lukem 		}
   1316      1.24     lukem 	}
   1317      1.24     lukem 
   1318       1.1       cgd 	reply(211, "End of status");
   1319       1.1       cgd }
   1320       1.1       cgd 
   1321       1.8   deraadt void
   1322       1.1       cgd fatal(s)
   1323       1.1       cgd 	char *s;
   1324       1.1       cgd {
   1325       1.8   deraadt 
   1326       1.1       cgd 	reply(451, "Error in server: %s\n", s);
   1327       1.1       cgd 	reply(221, "Closing connection due to server error.");
   1328       1.1       cgd 	dologout(0);
   1329       1.1       cgd 	/* NOTREACHED */
   1330       1.1       cgd }
   1331       1.1       cgd 
   1332       1.8   deraadt void
   1333      1.45  christos #ifdef __STDC__
   1334       1.8   deraadt reply(int n, const char *fmt, ...)
   1335       1.8   deraadt #else
   1336       1.8   deraadt reply(n, fmt, va_alist)
   1337       1.1       cgd 	int n;
   1338       1.1       cgd 	char *fmt;
   1339       1.8   deraadt         va_dcl
   1340       1.8   deraadt #endif
   1341       1.1       cgd {
   1342       1.8   deraadt 	va_list ap;
   1343      1.45  christos #ifdef __STDC__
   1344       1.8   deraadt 	va_start(ap, fmt);
   1345       1.8   deraadt #else
   1346       1.8   deraadt 	va_start(ap);
   1347       1.8   deraadt #endif
   1348       1.8   deraadt 	(void)printf("%d ", n);
   1349       1.8   deraadt 	(void)vprintf(fmt, ap);
   1350       1.8   deraadt 	(void)printf("\r\n");
   1351       1.1       cgd 	(void)fflush(stdout);
   1352       1.1       cgd 	if (debug) {
   1353       1.1       cgd 		syslog(LOG_DEBUG, "<--- %d ", n);
   1354       1.8   deraadt 		vsyslog(LOG_DEBUG, fmt, ap);
   1355       1.8   deraadt 	}
   1356       1.1       cgd }
   1357       1.1       cgd 
   1358       1.8   deraadt void
   1359      1.45  christos #ifdef __STDC__
   1360       1.8   deraadt lreply(int n, const char *fmt, ...)
   1361       1.8   deraadt #else
   1362       1.8   deraadt lreply(n, fmt, va_alist)
   1363       1.1       cgd 	int n;
   1364       1.1       cgd 	char *fmt;
   1365       1.8   deraadt         va_dcl
   1366       1.8   deraadt #endif
   1367       1.1       cgd {
   1368       1.8   deraadt 	va_list ap;
   1369      1.45  christos #ifdef __STDC__
   1370       1.8   deraadt 	va_start(ap, fmt);
   1371       1.8   deraadt #else
   1372       1.8   deraadt 	va_start(ap);
   1373       1.8   deraadt #endif
   1374       1.8   deraadt 	(void)printf("%d- ", n);
   1375       1.8   deraadt 	(void)vprintf(fmt, ap);
   1376       1.8   deraadt 	(void)printf("\r\n");
   1377       1.1       cgd 	(void)fflush(stdout);
   1378       1.1       cgd 	if (debug) {
   1379       1.1       cgd 		syslog(LOG_DEBUG, "<--- %d- ", n);
   1380       1.8   deraadt 		vsyslog(LOG_DEBUG, fmt, ap);
   1381       1.1       cgd 	}
   1382       1.1       cgd }
   1383       1.1       cgd 
   1384       1.8   deraadt static void
   1385       1.1       cgd ack(s)
   1386       1.1       cgd 	char *s;
   1387       1.1       cgd {
   1388       1.8   deraadt 
   1389       1.1       cgd 	reply(250, "%s command successful.", s);
   1390       1.1       cgd }
   1391       1.1       cgd 
   1392       1.8   deraadt void
   1393       1.1       cgd delete(name)
   1394       1.1       cgd 	char *name;
   1395       1.1       cgd {
   1396       1.1       cgd 
   1397      1.61     lukem 	logcmd("delete", -1, name, NULL);
   1398      1.39   mycroft 	if (remove(name) < 0)
   1399       1.1       cgd 		perror_reply(550, name);
   1400      1.39   mycroft 	else
   1401      1.39   mycroft 		ack("DELE");
   1402       1.1       cgd }
   1403       1.1       cgd 
   1404       1.8   deraadt void
   1405       1.1       cgd cwd(path)
   1406      1.55   mycroft 	const char *path;
   1407       1.1       cgd {
   1408       1.8   deraadt 
   1409       1.1       cgd 	if (chdir(path) < 0)
   1410       1.1       cgd 		perror_reply(550, path);
   1411      1.24     lukem 	else {
   1412      1.24     lukem 		show_chdir_messages(250);
   1413       1.1       cgd 		ack("CWD");
   1414      1.24     lukem 	}
   1415       1.1       cgd }
   1416       1.1       cgd 
   1417      1.33     lukem static void
   1418      1.33     lukem replydirname(name, message)
   1419      1.33     lukem 	const char *name, *message;
   1420      1.33     lukem {
   1421  1.61.2.4        he 	char *p, *ep;
   1422  1.61.2.4        he 	char npath[MAXPATHLEN];
   1423      1.33     lukem 
   1424  1.61.2.4        he 	p = npath;
   1425  1.61.2.4        he 	ep = &npath[sizeof(npath) - 1];
   1426  1.61.2.4        he 	while (*name) {
   1427  1.61.2.4        he 		if (*name == '"' && ep - p >= 2) {
   1428  1.61.2.4        he 			*p++ = *name++;
   1429  1.61.2.4        he 			*p++ = '"';
   1430  1.61.2.4        he 		} else if (ep - p >= 1)
   1431  1.61.2.4        he 			*p++ = *name++;
   1432  1.61.2.4        he 		else
   1433  1.61.2.4        he 			break;
   1434      1.33     lukem 	}
   1435  1.61.2.4        he 	*p = '\0';
   1436      1.33     lukem 	reply(257, "\"%s\" %s", npath, message);
   1437      1.33     lukem }
   1438      1.33     lukem 
   1439       1.8   deraadt void
   1440       1.1       cgd makedir(name)
   1441       1.1       cgd 	char *name;
   1442       1.1       cgd {
   1443       1.8   deraadt 
   1444      1.61     lukem 	logcmd("mkdir", -1, name, NULL);
   1445       1.1       cgd 	if (mkdir(name, 0777) < 0)
   1446       1.1       cgd 		perror_reply(550, name);
   1447       1.1       cgd 	else
   1448      1.33     lukem 		replydirname(name, "directory created.");
   1449       1.1       cgd }
   1450       1.1       cgd 
   1451       1.8   deraadt void
   1452       1.1       cgd removedir(name)
   1453       1.1       cgd 	char *name;
   1454       1.1       cgd {
   1455       1.8   deraadt 
   1456      1.61     lukem 	logcmd("rmdir", -1, name, NULL);
   1457       1.1       cgd 	if (rmdir(name) < 0)
   1458       1.1       cgd 		perror_reply(550, name);
   1459       1.1       cgd 	else
   1460       1.1       cgd 		ack("RMD");
   1461       1.1       cgd }
   1462       1.1       cgd 
   1463       1.8   deraadt void
   1464       1.1       cgd pwd()
   1465       1.1       cgd {
   1466       1.1       cgd 	char path[MAXPATHLEN + 1];
   1467       1.1       cgd 
   1468      1.33     lukem 	if (getcwd(path, sizeof(path) - 1) == NULL)
   1469      1.48     mouse 		reply(550, "Can't get the current directory: %s.",
   1470      1.48     mouse 							strerror(errno));
   1471       1.1       cgd 	else
   1472      1.33     lukem 		replydirname(path, "is the current directory.");
   1473       1.1       cgd }
   1474       1.1       cgd 
   1475       1.1       cgd char *
   1476       1.1       cgd renamefrom(name)
   1477       1.1       cgd 	char *name;
   1478       1.1       cgd {
   1479       1.1       cgd 	struct stat st;
   1480       1.1       cgd 
   1481       1.1       cgd 	if (stat(name, &st) < 0) {
   1482       1.1       cgd 		perror_reply(550, name);
   1483      1.57     lukem 		return (NULL);
   1484       1.1       cgd 	}
   1485       1.1       cgd 	reply(350, "File exists, ready for destination name");
   1486       1.1       cgd 	return (name);
   1487       1.1       cgd }
   1488       1.1       cgd 
   1489       1.8   deraadt void
   1490       1.1       cgd renamecmd(from, to)
   1491       1.1       cgd 	char *from, *to;
   1492       1.1       cgd {
   1493       1.8   deraadt 
   1494      1.61     lukem 	logcmd("rename", -1, from, to);
   1495       1.1       cgd 	if (rename(from, to) < 0)
   1496       1.1       cgd 		perror_reply(550, "rename");
   1497       1.1       cgd 	else
   1498       1.1       cgd 		ack("RNTO");
   1499       1.1       cgd }
   1500       1.1       cgd 
   1501       1.8   deraadt static void
   1502       1.1       cgd dolog(sin)
   1503       1.1       cgd 	struct sockaddr_in *sin;
   1504       1.1       cgd {
   1505       1.1       cgd 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
   1506       1.8   deraadt 		sizeof(struct in_addr), AF_INET);
   1507       1.1       cgd 
   1508       1.1       cgd 	if (hp)
   1509      1.52       mrg 		(void)strncpy(remotehost, hp->h_name, sizeof(remotehost));
   1510       1.1       cgd 	else
   1511      1.52       mrg 		(void)strncpy(remotehost, inet_ntoa(sin->sin_addr),
   1512       1.8   deraadt 		    sizeof(remotehost));
   1513      1.52       mrg 	remotehost[sizeof(remotehost) - 1] = '\0';
   1514       1.6       cgd #ifdef HASSETPROCTITLE
   1515       1.8   deraadt 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
   1516  1.61.2.3        he 	setproctitle("%s", proctitle);
   1517       1.6       cgd #endif /* HASSETPROCTITLE */
   1518       1.1       cgd 
   1519       1.8   deraadt 	if (logging)
   1520       1.8   deraadt 		syslog(LOG_INFO, "connection from %s", remotehost);
   1521       1.1       cgd }
   1522       1.1       cgd 
   1523       1.1       cgd /*
   1524       1.1       cgd  * Record logout in wtmp file
   1525       1.1       cgd  * and exit with supplied status.
   1526       1.1       cgd  */
   1527       1.8   deraadt void
   1528       1.1       cgd dologout(status)
   1529       1.1       cgd 	int status;
   1530       1.1       cgd {
   1531      1.16       mrg 	/*
   1532      1.16       mrg 	* Prevent reception of SIGURG from resulting in a resumption
   1533      1.16       mrg 	* back to the main program loop.
   1534      1.16       mrg 	*/
   1535      1.16       mrg 	transflag = 0;
   1536       1.8   deraadt 
   1537       1.1       cgd 	if (logged_in) {
   1538       1.1       cgd 		(void) seteuid((uid_t)0);
   1539       1.1       cgd 		logwtmp(ttyline, "", "");
   1540      1.36   mycroft #ifdef KERBEROS
   1541       1.4       cgd 		if (!notickets && krbtkfile_env)
   1542       1.4       cgd 			unlink(krbtkfile_env);
   1543       1.4       cgd #endif
   1544       1.1       cgd 	}
   1545       1.1       cgd 	/* beware of flushing buffers after a SIGPIPE */
   1546       1.1       cgd 	_exit(status);
   1547       1.1       cgd }
   1548       1.1       cgd 
   1549       1.8   deraadt static void
   1550       1.8   deraadt myoob(signo)
   1551       1.8   deraadt 	int signo;
   1552       1.1       cgd {
   1553       1.1       cgd 	char *cp;
   1554       1.1       cgd 
   1555       1.1       cgd 	/* only process if transfer occurring */
   1556       1.1       cgd 	if (!transflag)
   1557       1.1       cgd 		return;
   1558       1.1       cgd 	cp = tmpline;
   1559       1.1       cgd 	if (getline(cp, 7, stdin) == NULL) {
   1560       1.1       cgd 		reply(221, "You could at least say goodbye.");
   1561       1.1       cgd 		dologout(0);
   1562       1.1       cgd 	}
   1563      1.58     lukem 	if (strcasecmp(cp, "ABOR\r\n") == 0) {
   1564       1.1       cgd 		tmpline[0] = '\0';
   1565       1.1       cgd 		reply(426, "Transfer aborted. Data connection closed.");
   1566       1.1       cgd 		reply(226, "Abort successful");
   1567       1.1       cgd 		longjmp(urgcatch, 1);
   1568       1.1       cgd 	}
   1569      1.58     lukem 	if (strcasecmp(cp, "STAT\r\n") == 0) {
   1570       1.1       cgd 		if (file_size != (off_t) -1)
   1571       1.8   deraadt 			reply(213, "Status: %qd of %qd bytes transferred",
   1572       1.1       cgd 			    byte_count, file_size);
   1573       1.1       cgd 		else
   1574       1.8   deraadt 			reply(213, "Status: %qd bytes transferred", byte_count);
   1575       1.1       cgd 	}
   1576       1.1       cgd }
   1577       1.1       cgd 
   1578       1.1       cgd /*
   1579       1.1       cgd  * Note: a response of 425 is not mentioned as a possible response to
   1580       1.8   deraadt  *	the PASV command in RFC959. However, it has been blessed as
   1581       1.8   deraadt  *	a legitimate response by Jon Postel in a telephone conversation
   1582       1.1       cgd  *	with Rick Adams on 25 Jan 89.
   1583       1.1       cgd  */
   1584       1.8   deraadt void
   1585       1.1       cgd passive()
   1586       1.1       cgd {
   1587       1.1       cgd 	int len;
   1588       1.8   deraadt 	char *p, *a;
   1589       1.1       cgd 
   1590       1.1       cgd 	pdata = socket(AF_INET, SOCK_STREAM, 0);
   1591      1.23     lukem 	if (pdata < 0 || !logged_in) {
   1592       1.1       cgd 		perror_reply(425, "Can't open passive connection");
   1593       1.1       cgd 		return;
   1594       1.1       cgd 	}
   1595       1.1       cgd 	pasv_addr = ctrl_addr;
   1596       1.1       cgd 	pasv_addr.sin_port = 0;
   1597       1.1       cgd 	(void) seteuid((uid_t)0);
   1598       1.1       cgd 	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
   1599       1.1       cgd 		(void) seteuid((uid_t)pw->pw_uid);
   1600       1.1       cgd 		goto pasv_error;
   1601       1.1       cgd 	}
   1602       1.1       cgd 	(void) seteuid((uid_t)pw->pw_uid);
   1603       1.1       cgd 	len = sizeof(pasv_addr);
   1604       1.1       cgd 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
   1605       1.1       cgd 		goto pasv_error;
   1606       1.1       cgd 	if (listen(pdata, 1) < 0)
   1607       1.1       cgd 		goto pasv_error;
   1608       1.1       cgd 	a = (char *) &pasv_addr.sin_addr;
   1609       1.1       cgd 	p = (char *) &pasv_addr.sin_port;
   1610       1.1       cgd 
   1611       1.1       cgd #define UC(b) (((int) b) & 0xff)
   1612       1.1       cgd 
   1613       1.1       cgd 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
   1614       1.1       cgd 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
   1615       1.1       cgd 	return;
   1616       1.1       cgd 
   1617       1.1       cgd pasv_error:
   1618       1.1       cgd 	(void) close(pdata);
   1619       1.1       cgd 	pdata = -1;
   1620       1.1       cgd 	perror_reply(425, "Can't open passive connection");
   1621       1.1       cgd 	return;
   1622       1.1       cgd }
   1623       1.1       cgd 
   1624       1.1       cgd /*
   1625       1.1       cgd  * Generate unique name for file with basename "local".
   1626       1.1       cgd  * The file named "local" is already known to exist.
   1627       1.1       cgd  * Generates failure reply on error.
   1628      1.29       mrg  *
   1629      1.29       mrg  * XXX this function should under go changes similar to
   1630      1.29       mrg  * the mktemp(3)/mkstemp(3) changes.
   1631       1.1       cgd  */
   1632       1.8   deraadt static char *
   1633       1.1       cgd gunique(local)
   1634       1.1       cgd 	char *local;
   1635       1.1       cgd {
   1636      1.61     lukem 	static char new[MAXPATHLEN + 1];
   1637       1.1       cgd 	struct stat st;
   1638      1.29       mrg 	int count, len;
   1639       1.8   deraadt 	char *cp;
   1640       1.1       cgd 
   1641       1.8   deraadt 	cp = strrchr(local, '/');
   1642       1.1       cgd 	if (cp)
   1643       1.1       cgd 		*cp = '\0';
   1644       1.1       cgd 	if (stat(cp ? local : ".", &st) < 0) {
   1645       1.1       cgd 		perror_reply(553, cp ? local : ".");
   1646      1.57     lukem 		return (NULL);
   1647       1.1       cgd 	}
   1648       1.1       cgd 	if (cp)
   1649       1.1       cgd 		*cp = '/';
   1650       1.1       cgd 	(void) strcpy(new, local);
   1651      1.29       mrg 	len = strlen(new);
   1652      1.29       mrg 	cp = new + len;
   1653       1.1       cgd 	*cp++ = '.';
   1654       1.1       cgd 	for (count = 1; count < 100; count++) {
   1655      1.29       mrg 		(void)snprintf(cp, sizeof(new) - len - 2, "%d", count);
   1656       1.1       cgd 		if (stat(new, &st) < 0)
   1657       1.8   deraadt 			return (new);
   1658       1.1       cgd 	}
   1659       1.1       cgd 	reply(452, "Unique file name cannot be created.");
   1660       1.8   deraadt 	return (NULL);
   1661       1.1       cgd }
   1662       1.1       cgd 
   1663       1.1       cgd /*
   1664       1.1       cgd  * Format and send reply containing system error number.
   1665       1.1       cgd  */
   1666       1.8   deraadt void
   1667       1.1       cgd perror_reply(code, string)
   1668       1.1       cgd 	int code;
   1669      1.55   mycroft 	const char *string;
   1670       1.1       cgd {
   1671       1.8   deraadt 
   1672       1.1       cgd 	reply(code, "%s: %s.", string, strerror(errno));
   1673       1.1       cgd }
   1674       1.1       cgd 
   1675       1.1       cgd static char *onefile[] = {
   1676       1.1       cgd 	"",
   1677       1.1       cgd 	0
   1678       1.1       cgd };
   1679       1.1       cgd 
   1680       1.8   deraadt void
   1681       1.8   deraadt send_file_list(whichf)
   1682       1.8   deraadt 	char *whichf;
   1683       1.1       cgd {
   1684       1.1       cgd 	struct stat st;
   1685       1.1       cgd 	DIR *dirp = NULL;
   1686       1.1       cgd 	struct dirent *dir;
   1687       1.1       cgd 	FILE *dout = NULL;
   1688       1.8   deraadt 	char **dirlist, *dirname;
   1689       1.1       cgd 	int simple = 0;
   1690       1.8   deraadt 	int freeglob = 0;
   1691       1.8   deraadt 	glob_t gl;
   1692      1.25  christos #ifdef __GNUC__
   1693      1.25  christos 	(void) &dout;
   1694      1.25  christos 	(void) &dirlist;
   1695      1.25  christos 	(void) &simple;
   1696      1.25  christos 	(void) &freeglob;
   1697      1.25  christos #endif
   1698       1.1       cgd 
   1699       1.8   deraadt 	if (strpbrk(whichf, "~{[*?") != NULL) {
   1700      1.50    kleink 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
   1701       1.1       cgd 
   1702       1.8   deraadt 		memset(&gl, 0, sizeof(gl));
   1703       1.8   deraadt 		freeglob = 1;
   1704       1.8   deraadt 		if (glob(whichf, flags, 0, &gl)) {
   1705       1.8   deraadt 			reply(550, "not found");
   1706       1.8   deraadt 			goto out;
   1707       1.8   deraadt 		} else if (gl.gl_pathc == 0) {
   1708       1.1       cgd 			errno = ENOENT;
   1709       1.8   deraadt 			perror_reply(550, whichf);
   1710       1.8   deraadt 			goto out;
   1711       1.1       cgd 		}
   1712       1.8   deraadt 		dirlist = gl.gl_pathv;
   1713       1.1       cgd 	} else {
   1714       1.8   deraadt 		onefile[0] = whichf;
   1715       1.1       cgd 		dirlist = onefile;
   1716       1.1       cgd 		simple = 1;
   1717       1.1       cgd 	}
   1718       1.1       cgd 
   1719       1.1       cgd 	if (setjmp(urgcatch)) {
   1720       1.1       cgd 		transflag = 0;
   1721       1.8   deraadt 		goto out;
   1722       1.1       cgd 	}
   1723      1.20     lukem 	while ((dirname = *dirlist++) != NULL) {
   1724      1.33     lukem 		int trailingslash = 0;
   1725      1.33     lukem 
   1726       1.1       cgd 		if (stat(dirname, &st) < 0) {
   1727       1.1       cgd 			/*
   1728       1.1       cgd 			 * If user typed "ls -l", etc, and the client
   1729       1.1       cgd 			 * used NLST, do what the user meant.
   1730       1.1       cgd 			 */
   1731       1.1       cgd 			if (dirname[0] == '-' && *dirlist == NULL &&
   1732       1.1       cgd 			    transflag == 0) {
   1733       1.1       cgd 				retrieve("/bin/ls %s", dirname);
   1734       1.8   deraadt 				goto out;
   1735       1.1       cgd 			}
   1736       1.8   deraadt 			perror_reply(550, whichf);
   1737       1.1       cgd 			if (dout != NULL) {
   1738       1.1       cgd 				(void) fclose(dout);
   1739       1.1       cgd 				transflag = 0;
   1740       1.1       cgd 				data = -1;
   1741       1.1       cgd 				pdata = -1;
   1742       1.1       cgd 			}
   1743       1.8   deraadt 			goto out;
   1744       1.1       cgd 		}
   1745       1.1       cgd 
   1746       1.8   deraadt 		if (S_ISREG(st.st_mode)) {
   1747       1.1       cgd 			if (dout == NULL) {
   1748       1.1       cgd 				dout = dataconn("file list", (off_t)-1, "w");
   1749       1.1       cgd 				if (dout == NULL)
   1750       1.8   deraadt 					goto out;
   1751       1.1       cgd 				transflag++;
   1752       1.1       cgd 			}
   1753       1.1       cgd 			fprintf(dout, "%s%s\n", dirname,
   1754       1.1       cgd 				type == TYPE_A ? "\r" : "");
   1755       1.1       cgd 			byte_count += strlen(dirname) + 1;
   1756       1.1       cgd 			continue;
   1757       1.8   deraadt 		} else if (!S_ISDIR(st.st_mode))
   1758       1.1       cgd 			continue;
   1759       1.1       cgd 
   1760      1.33     lukem 		if (dirname[strlen(dirname) - 1] == '/')
   1761      1.33     lukem 			trailingslash++;
   1762      1.33     lukem 
   1763       1.1       cgd 		if ((dirp = opendir(dirname)) == NULL)
   1764       1.1       cgd 			continue;
   1765       1.1       cgd 
   1766       1.1       cgd 		while ((dir = readdir(dirp)) != NULL) {
   1767      1.61     lukem 			char nbuf[MAXPATHLEN + 1];
   1768       1.1       cgd 
   1769       1.1       cgd 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
   1770       1.1       cgd 				continue;
   1771       1.1       cgd 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
   1772       1.1       cgd 			    dir->d_namlen == 2)
   1773       1.1       cgd 				continue;
   1774       1.1       cgd 
   1775      1.33     lukem 			(void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
   1776      1.33     lukem 			    trailingslash ? "" : "/", dir->d_name);
   1777       1.1       cgd 
   1778       1.1       cgd 			/*
   1779      1.30     lukem 			 * We have to do a stat to ensure it's
   1780       1.1       cgd 			 * not a directory or special file.
   1781       1.1       cgd 			 */
   1782       1.1       cgd 			if (simple || (stat(nbuf, &st) == 0 &&
   1783       1.8   deraadt 			    S_ISREG(st.st_mode))) {
   1784       1.1       cgd 				if (dout == NULL) {
   1785       1.1       cgd 					dout = dataconn("file list", (off_t)-1,
   1786       1.1       cgd 						"w");
   1787       1.1       cgd 					if (dout == NULL)
   1788       1.8   deraadt 						goto out;
   1789       1.1       cgd 					transflag++;
   1790       1.1       cgd 				}
   1791       1.1       cgd 				if (nbuf[0] == '.' && nbuf[1] == '/')
   1792       1.1       cgd 					fprintf(dout, "%s%s\n", &nbuf[2],
   1793       1.1       cgd 						type == TYPE_A ? "\r" : "");
   1794       1.1       cgd 				else
   1795       1.1       cgd 					fprintf(dout, "%s%s\n", nbuf,
   1796       1.1       cgd 						type == TYPE_A ? "\r" : "");
   1797       1.1       cgd 				byte_count += strlen(nbuf) + 1;
   1798       1.1       cgd 			}
   1799       1.1       cgd 		}
   1800       1.1       cgd 		(void) closedir(dirp);
   1801       1.1       cgd 	}
   1802       1.1       cgd 
   1803       1.1       cgd 	if (dout == NULL)
   1804       1.1       cgd 		reply(550, "No files found.");
   1805       1.1       cgd 	else if (ferror(dout) != 0)
   1806       1.1       cgd 		perror_reply(550, "Data connection");
   1807       1.1       cgd 	else
   1808       1.1       cgd 		reply(226, "Transfer complete.");
   1809       1.1       cgd 
   1810       1.1       cgd 	transflag = 0;
   1811       1.1       cgd 	if (dout != NULL)
   1812       1.1       cgd 		(void) fclose(dout);
   1813       1.1       cgd 	data = -1;
   1814       1.1       cgd 	pdata = -1;
   1815       1.8   deraadt out:
   1816       1.8   deraadt 	if (freeglob) {
   1817       1.8   deraadt 		freeglob = 0;
   1818       1.8   deraadt 		globfree(&gl);
   1819       1.8   deraadt 	}
   1820      1.34     lukem }
   1821      1.34     lukem 
   1822      1.34     lukem char *
   1823      1.34     lukem conffilename(s)
   1824      1.34     lukem 	const char *s;
   1825      1.34     lukem {
   1826      1.61     lukem 	static char filename[MAXPATHLEN + 1];
   1827      1.34     lukem 
   1828      1.34     lukem 	(void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
   1829      1.34     lukem 	return filename;
   1830       1.1       cgd }
   1831