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