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