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