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