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