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