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