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