xref: /netbsd-src/libexec/ftpd/ftpd.c (revision 6ea46cb5e46c49111a6ecf3bcbe3c7e2730fe9f6)
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 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 static char rcsid[] = "$Id: ftpd.c,v 1.8 1994/06/29 01:49:45 deraadt Exp $";
39 #endif /* not lint */
40 
41 #ifndef lint
42 static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
43 #endif /* not lint */
44 
45 /*
46  * FTP server.
47  */
48 #include <sys/param.h>
49 #include <sys/stat.h>
50 #include <sys/ioctl.h>
51 #include <sys/socket.h>
52 #include <sys/wait.h>
53 
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 
58 #define	FTP_NAMES
59 #include <arpa/ftp.h>
60 #include <arpa/inet.h>
61 #include <arpa/telnet.h>
62 
63 #include <ctype.h>
64 #include <dirent.h>
65 #include <err.h>
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <glob.h>
69 #include <limits.h>
70 #include <netdb.h>
71 #include <pwd.h>
72 #include <setjmp.h>
73 #include <signal.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <syslog.h>
78 #include <time.h>
79 #include <unistd.h>
80 
81 #include "pathnames.h"
82 #include "extern.h"
83 
84 #if __STDC__
85 #include <stdarg.h>
86 #else
87 #include <varargs.h>
88 #endif
89 
90 static char version[] = "Version 6.00";
91 
92 extern	off_t restart_point;
93 extern	char cbuf[];
94 
95 struct	sockaddr_in ctrl_addr;
96 struct	sockaddr_in data_source;
97 struct	sockaddr_in data_dest;
98 struct	sockaddr_in his_addr;
99 struct	sockaddr_in pasv_addr;
100 
101 int	data;
102 jmp_buf	errcatch, urgcatch;
103 int	logged_in;
104 struct	passwd *pw;
105 int	debug;
106 int	timeout = 900;    /* timeout after 15 minutes of inactivity */
107 int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
108 int	logging;
109 int	guest;
110 int	dochroot;
111 int	type;
112 int	form;
113 int	stru;			/* avoid C keyword */
114 int	mode;
115 int	usedefault = 1;		/* for data transfers */
116 int	pdata = -1;		/* for passive mode */
117 sig_atomic_t transflag;
118 off_t	file_size;
119 off_t	byte_count;
120 #if !defined(CMASK) || CMASK == 0
121 #undef CMASK
122 #define CMASK 027
123 #endif
124 int	defumask = CMASK;		/* default umask value */
125 char	tmpline[7];
126 char	hostname[MAXHOSTNAMELEN];
127 char	remotehost[MAXHOSTNAMELEN];
128 
129 #if defined(KERBEROS)
130 int notickets = 1;
131 char *krbtkfile_env = NULL;
132 #endif
133 
134 /*
135  * Timeout intervals for retrying connections
136  * to hosts that don't accept PORT cmds.  This
137  * is a kludge, but given the problems with TCP...
138  */
139 #define	SWAITMAX	90	/* wait at most 90 seconds */
140 #define	SWAITINT	5	/* interval between retries */
141 
142 int	swaitmax = SWAITMAX;
143 int	swaitint = SWAITINT;
144 
145 #ifdef HASSETPROCTITLE
146 char	proctitle[BUFSIZ];	/* initial part of title */
147 #endif /* HASSETPROCTITLE */
148 
149 #define LOGCMD(cmd, file) \
150 	if (logging > 1) \
151 	    syslog(LOG_INFO,"%s %s%s", cmd, \
152 		*(file) == '/' ? "" : curdir(), file);
153 #define LOGCMD2(cmd, file1, file2) \
154 	 if (logging > 1) \
155 	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
156 		*(file1) == '/' ? "" : curdir(), file1, \
157 		*(file2) == '/' ? "" : curdir(), file2);
158 #define LOGBYTES(cmd, file, cnt) \
159 	if (logging > 1) { \
160 		if (cnt == (off_t)-1) \
161 		    syslog(LOG_INFO,"%s %s%s", cmd, \
162 			*(file) == '/' ? "" : curdir(), file); \
163 		else \
164 		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
165 			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
166 	}
167 
168 static void	 ack __P((char *));
169 static void	 myoob __P((int));
170 static int	 checkuser __P((char *, char *));
171 static FILE	*dataconn __P((char *, off_t, char *));
172 static void	 dolog __P((struct sockaddr_in *));
173 static char	*curdir __P((void));
174 static void	 end_login __P((void));
175 static FILE	*getdatasock __P((char *));
176 static char	*gunique __P((char *));
177 static void	 lostconn __P((int));
178 static int	 receive_data __P((FILE *, FILE *));
179 static void	 send_data __P((FILE *, FILE *, off_t));
180 static struct passwd *
181 		 sgetpwnam __P((char *));
182 static char	*sgetsave __P((char *));
183 
184 static char *
185 curdir()
186 {
187 	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */
188 
189 	if (getcwd(path, sizeof(path)-2) == NULL)
190 		return ("");
191 	if (path[1] != '\0')		/* special case for root dir. */
192 		strcat(path, "/");
193 	/* For guest account, skip / since it's chrooted */
194 	return (guest ? path+1 : path);
195 }
196 
197 int
198 main(argc, argv, envp)
199 	int argc;
200 	char *argv[];
201 	char **envp;
202 {
203 	int addrlen, ch, on = 1, tos;
204 	char *cp, line[LINE_MAX];
205 	FILE *fd;
206 
207 	/*
208 	 * LOG_NDELAY sets up the logging connection immediately,
209 	 * necessary for anonymous ftp's that chroot and can't do it later.
210 	 */
211 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
212 	addrlen = sizeof(his_addr);
213 	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
214 		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
215 		exit(1);
216 	}
217 	addrlen = sizeof(ctrl_addr);
218 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
219 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
220 		exit(1);
221 	}
222 #ifdef IP_TOS
223 	tos = IPTOS_LOWDELAY;
224 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
225 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
226 #endif
227 	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
228 	debug = 0;
229 
230 	while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
231 		switch (ch) {
232 		case 'd':
233 			debug = 1;
234 			break;
235 
236 		case 'l':
237 			logging++;	/* > 1 == extra logging */
238 			break;
239 
240 		case 't':
241 			timeout = atoi(optarg);
242 			if (maxtimeout < timeout)
243 				maxtimeout = timeout;
244 			break;
245 
246 		case 'T':
247 			maxtimeout = atoi(optarg);
248 			if (timeout > maxtimeout)
249 				timeout = maxtimeout;
250 			break;
251 
252 		case 'u':
253 		    {
254 			long val = 0;
255 
256 			val = strtol(optarg, &optarg, 8);
257 			if (*optarg != '\0' || val < 0)
258 				warnx("bad value for -u");
259 			else
260 				defumask = val;
261 			break;
262 		    }
263 
264 		case 'v':
265 			debug = 1;
266 			break;
267 
268 		default:
269 			warnx("unknown flag -%c ignored", optopt);
270 			break;
271 		}
272 	}
273 	(void) freopen(_PATH_DEVNULL, "w", stderr);
274 	(void) signal(SIGPIPE, lostconn);
275 	(void) signal(SIGCHLD, SIG_IGN);
276 	if ((int)signal(SIGURG, myoob) < 0)
277 		syslog(LOG_ERR, "signal: %m");
278 
279 	/* Try to handle urgent data inline */
280 #ifdef SO_OOBINLINE
281 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
282 		syslog(LOG_ERR, "setsockopt: %m");
283 #endif
284 
285 #ifdef	F_SETOWN
286 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
287 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
288 #endif
289 	dolog(&his_addr);
290 	/*
291 	 * Set up default state
292 	 */
293 	data = -1;
294 	type = TYPE_A;
295 	form = FORM_N;
296 	stru = STRU_F;
297 	mode = MODE_S;
298 	tmpline[0] = '\0';
299 
300 	/* If logins are disabled, print out the message. */
301 	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
302 		while (fgets(line, sizeof(line), fd) != NULL) {
303 			if ((cp = strchr(line, '\n')) != NULL)
304 				*cp = '\0';
305 			lreply(530, "%s", line);
306 		}
307 		(void) fflush(stdout);
308 		(void) fclose(fd);
309 		reply(530, "System not available.");
310 		exit(0);
311 	}
312 	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
313 		while (fgets(line, sizeof(line), fd) != NULL) {
314 			if ((cp = strchr(line, '\n')) != NULL)
315 				*cp = '\0';
316 			lreply(220, "%s", line);
317 		}
318 		(void) fflush(stdout);
319 		(void) fclose(fd);
320 		/* reply(220,) must follow */
321 	}
322 	(void) gethostname(hostname, sizeof(hostname));
323 	reply(220, "%s FTP server (%s) ready.", hostname, version);
324 	(void) setjmp(errcatch);
325 	for (;;)
326 		(void) yyparse();
327 	/* NOTREACHED */
328 }
329 
330 static void
331 lostconn(signo)
332 	int signo;
333 {
334 
335 	if (debug)
336 		syslog(LOG_DEBUG, "lost connection");
337 	dologout(-1);
338 }
339 
340 static char ttyline[20];
341 
342 /*
343  * Helper function for sgetpwnam().
344  */
345 static char *
346 sgetsave(s)
347 	char *s;
348 {
349 	char *new = malloc((unsigned) strlen(s) + 1);
350 
351 	if (new == NULL) {
352 		perror_reply(421, "Local resource failure: malloc");
353 		dologout(1);
354 		/* NOTREACHED */
355 	}
356 	(void) strcpy(new, s);
357 	return (new);
358 }
359 
360 /*
361  * Save the result of a getpwnam.  Used for USER command, since
362  * the data returned must not be clobbered by any other command
363  * (e.g., globbing).
364  */
365 static struct passwd *
366 sgetpwnam(name)
367 	char *name;
368 {
369 	static struct passwd save;
370 	struct passwd *p;
371 
372 	if ((p = getpwnam(name)) == NULL)
373 		return (p);
374 	if (save.pw_name) {
375 		free(save.pw_name);
376 		free(save.pw_passwd);
377 		free(save.pw_gecos);
378 		free(save.pw_dir);
379 		free(save.pw_shell);
380 	}
381 	save = *p;
382 	save.pw_name = sgetsave(p->pw_name);
383 	save.pw_passwd = sgetsave(p->pw_passwd);
384 	save.pw_gecos = sgetsave(p->pw_gecos);
385 	save.pw_dir = sgetsave(p->pw_dir);
386 	save.pw_shell = sgetsave(p->pw_shell);
387 	return (&save);
388 }
389 
390 static int login_attempts;	/* number of failed login attempts */
391 static int askpasswd;		/* had user command, ask for passwd */
392 static char curname[10];	/* current USER name */
393 
394 /*
395  * USER command.
396  * Sets global passwd pointer pw if named account exists and is acceptable;
397  * sets askpasswd if a PASS command is expected.  If logged in previously,
398  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
399  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
400  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
401  * requesting login privileges.  Disallow anyone who does not have a standard
402  * shell as returned by getusershell().  Disallow anyone mentioned in the file
403  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
404  */
405 void
406 user(name)
407 	char *name;
408 {
409 	char *cp, *shell;
410 
411 	if (logged_in) {
412 		if (guest) {
413 			reply(530, "Can't change user from guest login.");
414 			return;
415 		} else if (dochroot) {
416 			reply(530, "Can't change user from chroot user.");
417 			return;
418 		}
419 		end_login();
420 	}
421 
422 	guest = 0;
423 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
424 		if (checkuser(_PATH_FTPUSERS, "ftp") ||
425 		    checkuser(_PATH_FTPUSERS, "anonymous"))
426 			reply(530, "User %s access denied.", name);
427 		else if ((pw = sgetpwnam("ftp")) != NULL) {
428 			guest = 1;
429 			askpasswd = 1;
430 			reply(331,
431 			    "Guest login ok, type your name as password.");
432 		} else
433 			reply(530, "User %s unknown.", name);
434 		if (!askpasswd && logging)
435 			syslog(LOG_NOTICE,
436 			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
437 		return;
438 	}
439 	if (pw = sgetpwnam(name)) {
440 		if ((shell = pw->pw_shell) == NULL || *shell == 0)
441 			shell = _PATH_BSHELL;
442 		while ((cp = getusershell()) != NULL)
443 			if (strcmp(cp, shell) == 0)
444 				break;
445 		endusershell();
446 
447 		if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
448 			reply(530, "User %s access denied.", name);
449 			if (logging)
450 				syslog(LOG_NOTICE,
451 				    "FTP LOGIN REFUSED FROM %s, %s",
452 				    remotehost, name);
453 			pw = (struct passwd *) NULL;
454 			return;
455 		}
456 	}
457 	if (logging)
458 		strncpy(curname, name, sizeof(curname)-1);
459 #ifdef SKEY
460 	if (!skey_haskey(name)) {
461 		char *myskey, *skey_keyinfo __P((char *name));
462 
463 		myskey = skey_keyinfo(name);
464 		reply(331, "Password [%s] for %s required.",
465 		    myskey ? myskey : "error getting challenge", name);
466 	} else
467 #endif
468 		reply(331, "Password required for %s.", name);
469 
470 	askpasswd = 1;
471 	/*
472 	 * Delay before reading passwd after first failed
473 	 * attempt to slow down passwd-guessing programs.
474 	 */
475 	if (login_attempts)
476 		sleep((unsigned) login_attempts);
477 }
478 
479 /*
480  * Check if a user is in the file "fname"
481  */
482 static int
483 checkuser(fname, name)
484 	char *fname;
485 	char *name;
486 {
487 	FILE *fd;
488 	int found = 0;
489 	char *p, line[BUFSIZ];
490 
491 	if ((fd = fopen(fname, "r")) != NULL) {
492 		while (fgets(line, sizeof(line), fd) != NULL)
493 			if ((p = strchr(line, '\n')) != NULL) {
494 				*p = '\0';
495 				if (line[0] == '#')
496 					continue;
497 				if (strcmp(p, name) == 0) {
498 					found = 1;
499 					break;
500 				}
501 			}
502 		(void) fclose(fd);
503 	}
504 	return (found);
505 }
506 
507 /*
508  * Terminate login as previous user, if any, resetting state;
509  * used when USER command is given or login fails.
510  */
511 static void
512 end_login()
513 {
514 
515 	(void) seteuid((uid_t)0);
516 	if (logged_in)
517 		logwtmp(ttyline, "", "");
518 	pw = NULL;
519 	logged_in = 0;
520 	guest = 0;
521 	dochroot = 0;
522 }
523 
524 void
525 pass(passwd)
526 	char *passwd;
527 {
528 	int rval;
529 	FILE *fd;
530 
531 	if (logged_in || askpasswd == 0) {
532 		reply(503, "Login with USER first.");
533 		return;
534 	}
535 	askpasswd = 0;
536 	if (!guest) {		/* "ftp" is only account allowed no password */
537 		if (pw == NULL) {
538 			rval = 1;	/* failure below */
539 			goto skip;
540 		}
541 #if defined(KERBEROS)
542 		rval = klogin(pw, "", hostname, passwd);
543 		if (rval == 0)
544 			goto skip;
545 #endif
546 #ifdef SKEY
547 		if (skey_haskey(pw->pw_name) == 0 &&
548 		   (skey_passcheck(pw->pw_name, passwd) != -1)) {
549 			rval = 0;
550 			goto skip;
551 		}
552 #endif
553 		/* the strcmp does not catch null passwords! */
554 		if (pw == NULL || *pw->pw_passwd == '\0' ||
555 		    strcmp(crypt(passwd, (pw ? pw->pw_passwd : "xx")), pw->pw_passwd)) {
556 			rval = 1;	 /* failure */
557 			goto skip;
558 		}
559 		rval = 0;
560 
561 skip:
562 		/*
563 		 * If rval == 1, the user failed the authentication check
564 		 * above.  If rval == 0, either Kerberos or local authentication
565 		 * succeeded.
566 		 */
567 		if (rval) {
568 			reply(530, "Login incorrect.");
569 			if (logging)
570 				syslog(LOG_NOTICE,
571 				    "FTP LOGIN FAILED FROM %s, %s",
572 				    remotehost, curname);
573 			pw = NULL;
574 			if (login_attempts++ >= 5) {
575 				syslog(LOG_NOTICE,
576 				    "repeated login failures from %s",
577 				    remotehost);
578 				exit(0);
579 			}
580 			return;
581 		}
582 	}
583 	login_attempts = 0;		/* this time successful */
584 	if (setegid((gid_t)pw->pw_gid) < 0) {
585 		reply(550, "Can't set gid.");
586 		return;
587 	}
588 	(void) initgroups(pw->pw_name, pw->pw_gid);
589 
590 	/* open wtmp before chroot */
591 	(void)sprintf(ttyline, "ftp%d", getpid());
592 	logwtmp(ttyline, pw->pw_name, remotehost);
593 	logged_in = 1;
594 
595 	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
596 	if (guest) {
597 		/*
598 		 * We MUST do a chdir() after the chroot. Otherwise
599 		 * the old current directory will be accessible as "."
600 		 * outside the new root!
601 		 */
602 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
603 			reply(550, "Can't set guest privileges.");
604 			goto bad;
605 		}
606 	} else if (dochroot) {
607 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
608 			reply(550, "Can't change root.");
609 			goto bad;
610 		}
611 	} else if (chdir(pw->pw_dir) < 0) {
612 		if (chdir("/") < 0) {
613 			reply(530, "User %s: can't change directory to %s.",
614 			    pw->pw_name, pw->pw_dir);
615 			goto bad;
616 		} else
617 			lreply(230, "No directory! Logging in with home=/");
618 	}
619 	if (seteuid((uid_t)pw->pw_uid) < 0) {
620 		reply(550, "Can't set uid.");
621 		goto bad;
622 	}
623 	/*
624 	 * Display a login message, if it exists.
625 	 * N.B. reply(230,) must follow the message.
626 	 */
627 	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
628 		char *cp, line[LINE_MAX];
629 
630 		while (fgets(line, sizeof(line), fd) != NULL) {
631 			if ((cp = strchr(line, '\n')) != NULL)
632 				*cp = '\0';
633 			lreply(230, "%s", line);
634 		}
635 		(void) fflush(stdout);
636 		(void) fclose(fd);
637 	}
638 	if (guest) {
639 		reply(230, "Guest login ok, access restrictions apply.");
640 #ifdef HASSETPROCTITLE
641 		snprintf(proctitle, sizeof(proctitle),
642 		    "%s: anonymous/%.*s", remotehost,
643 		    sizeof(proctitle) - sizeof(remotehost) -
644 		    sizeof(": anonymous/"), passwd);
645 		setproctitle(proctitle);
646 #endif /* HASSETPROCTITLE */
647 		if (logging)
648 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
649 			    remotehost, passwd);
650 	} else {
651 		reply(230, "User %s logged in.", pw->pw_name);
652 #ifdef HASSETPROCTITLE
653 		snprintf(proctitle, sizeof(proctitle),
654 		    "%s: %s", remotehost, pw->pw_name);
655 		setproctitle(proctitle);
656 #endif /* HASSETPROCTITLE */
657 		if (logging)
658 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
659 			    remotehost, pw->pw_name);
660 	}
661 	(void) umask(defumask);
662 	return;
663 bad:
664 	/* Forget all about it... */
665 	end_login();
666 }
667 
668 void
669 retrieve(cmd, name)
670 	char *cmd, *name;
671 {
672 	FILE *fin, *dout;
673 	struct stat st;
674 	int (*closefunc) __P((FILE *));
675 
676 	if (cmd == 0) {
677 		fin = fopen(name, "r"), closefunc = fclose;
678 		st.st_size = 0;
679 	} else {
680 		char line[BUFSIZ];
681 
682 		(void) sprintf(line, cmd, name), name = line;
683 		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
684 		st.st_size = -1;
685 		st.st_blksize = BUFSIZ;
686 	}
687 	if (fin == NULL) {
688 		if (errno != 0) {
689 			perror_reply(550, name);
690 			if (cmd == 0) {
691 				LOGCMD("get", name);
692 			}
693 		}
694 		return;
695 	}
696 	byte_count = -1;
697 	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
698 		reply(550, "%s: not a plain file.", name);
699 		goto done;
700 	}
701 	if (restart_point) {
702 		if (type == TYPE_A) {
703 			off_t i, n;
704 			int c;
705 
706 			n = restart_point;
707 			i = 0;
708 			while (i++ < n) {
709 				if ((c=getc(fin)) == EOF) {
710 					perror_reply(550, name);
711 					goto done;
712 				}
713 				if (c == '\n')
714 					i++;
715 			}
716 		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
717 			perror_reply(550, name);
718 			goto done;
719 		}
720 	}
721 	dout = dataconn(name, st.st_size, "w");
722 	if (dout == NULL)
723 		goto done;
724 	send_data(fin, dout, st.st_blksize);
725 	(void) fclose(dout);
726 	data = -1;
727 	pdata = -1;
728 done:
729 	if (cmd == 0)
730 		LOGBYTES("get", name, byte_count);
731 	(*closefunc)(fin);
732 }
733 
734 void
735 store(name, mode, unique)
736 	char *name, *mode;
737 	int unique;
738 {
739 	FILE *fout, *din;
740 	struct stat st;
741 	int (*closefunc) __P((FILE *));
742 
743 	if (unique && stat(name, &st) == 0 &&
744 	    (name = gunique(name)) == NULL) {
745 		LOGCMD(*mode == 'w' ? "put" : "append", name);
746 		return;
747 	}
748 
749 	if (restart_point)
750 		mode = "r+";
751 	fout = fopen(name, mode);
752 	closefunc = fclose;
753 	if (fout == NULL) {
754 		perror_reply(553, name);
755 		LOGCMD(*mode == 'w' ? "put" : "append", name);
756 		return;
757 	}
758 	byte_count = -1;
759 	if (restart_point) {
760 		if (type == TYPE_A) {
761 			off_t i, n;
762 			int c;
763 
764 			n = restart_point;
765 			i = 0;
766 			while (i++ < n) {
767 				if ((c=getc(fout)) == EOF) {
768 					perror_reply(550, name);
769 					goto done;
770 				}
771 				if (c == '\n')
772 					i++;
773 			}
774 			/*
775 			 * We must do this seek to "current" position
776 			 * because we are changing from reading to
777 			 * writing.
778 			 */
779 			if (fseek(fout, 0L, L_INCR) < 0) {
780 				perror_reply(550, name);
781 				goto done;
782 			}
783 		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
784 			perror_reply(550, name);
785 			goto done;
786 		}
787 	}
788 	din = dataconn(name, (off_t)-1, "r");
789 	if (din == NULL)
790 		goto done;
791 	if (receive_data(din, fout) == 0) {
792 		if (unique)
793 			reply(226, "Transfer complete (unique file name:%s).",
794 			    name);
795 		else
796 			reply(226, "Transfer complete.");
797 	}
798 	(void) fclose(din);
799 	data = -1;
800 	pdata = -1;
801 done:
802 	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
803 	(*closefunc)(fout);
804 }
805 
806 static FILE *
807 getdatasock(mode)
808 	char *mode;
809 {
810 	int on = 1, s, t, tries;
811 
812 	if (data >= 0)
813 		return (fdopen(data, mode));
814 	(void) seteuid((uid_t)0);
815 	s = socket(AF_INET, SOCK_STREAM, 0);
816 	if (s < 0)
817 		goto bad;
818 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
819 	    (char *) &on, sizeof(on)) < 0)
820 		goto bad;
821 	/* anchor socket to avoid multi-homing problems */
822 	data_source.sin_family = AF_INET;
823 	data_source.sin_addr = ctrl_addr.sin_addr;
824 	for (tries = 1; ; tries++) {
825 		if (bind(s, (struct sockaddr *)&data_source,
826 		    sizeof(data_source)) >= 0)
827 			break;
828 		if (errno != EADDRINUSE || tries > 10)
829 			goto bad;
830 		sleep(tries);
831 	}
832 	(void) seteuid((uid_t)pw->pw_uid);
833 #ifdef IP_TOS
834 	on = IPTOS_THROUGHPUT;
835 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
836 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
837 #endif
838 	return (fdopen(s, mode));
839 bad:
840 	/* Return the real value of errno (close may change it) */
841 	t = errno;
842 	(void) seteuid((uid_t)pw->pw_uid);
843 	(void) close(s);
844 	errno = t;
845 	return (NULL);
846 }
847 
848 static FILE *
849 dataconn(name, size, mode)
850 	char *name;
851 	off_t size;
852 	char *mode;
853 {
854 	char sizebuf[32];
855 	FILE *file;
856 	int retry = 0, tos;
857 
858 	file_size = size;
859 	byte_count = 0;
860 	if (size != (off_t) -1)
861 		(void) sprintf(sizebuf, " (%qd bytes)", size);
862 	else
863 		(void) strcpy(sizebuf, "");
864 	if (pdata >= 0) {
865 		struct sockaddr_in from;
866 		int s, fromlen = sizeof(from);
867 
868 		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
869 		if (s < 0) {
870 			reply(425, "Can't open data connection.");
871 			(void) close(pdata);
872 			pdata = -1;
873 			return (NULL);
874 		}
875 		(void) close(pdata);
876 		pdata = s;
877 #ifdef IP_TOS
878 		tos = IPTOS_LOWDELAY;
879 		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
880 		    sizeof(int));
881 #endif
882 		reply(150, "Opening %s mode data connection for '%s'%s.",
883 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
884 		return (fdopen(pdata, mode));
885 	}
886 	if (data >= 0) {
887 		reply(125, "Using existing data connection for '%s'%s.",
888 		    name, sizebuf);
889 		usedefault = 1;
890 		return (fdopen(data, mode));
891 	}
892 	if (usedefault)
893 		data_dest = his_addr;
894 	usedefault = 1;
895 	file = getdatasock(mode);
896 	if (file == NULL) {
897 		reply(425, "Can't create data socket (%s,%d): %s.",
898 		    inet_ntoa(data_source.sin_addr),
899 		    ntohs(data_source.sin_port), strerror(errno));
900 		return (NULL);
901 	}
902 	data = fileno(file);
903 	while (connect(data, (struct sockaddr *)&data_dest,
904 	    sizeof(data_dest)) < 0) {
905 		if (errno == EADDRINUSE && retry < swaitmax) {
906 			sleep((unsigned) swaitint);
907 			retry += swaitint;
908 			continue;
909 		}
910 		perror_reply(425, "Can't build data connection");
911 		(void) fclose(file);
912 		data = -1;
913 		return (NULL);
914 	}
915 	reply(150, "Opening %s mode data connection for '%s'%s.",
916 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
917 	return (file);
918 }
919 
920 /*
921  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
922  * encapsulation of the data subject * to Mode, Structure, and Type.
923  *
924  * NB: Form isn't handled.
925  */
926 static void
927 send_data(instr, outstr, blksize)
928 	FILE *instr, *outstr;
929 	off_t blksize;
930 {
931 	int c, cnt, filefd, netfd;
932 	char *buf;
933 
934 	transflag++;
935 	if (setjmp(urgcatch)) {
936 		transflag = 0;
937 		return;
938 	}
939 	switch (type) {
940 
941 	case TYPE_A:
942 		while ((c = getc(instr)) != EOF) {
943 			byte_count++;
944 			if (c == '\n') {
945 				if (ferror(outstr))
946 					goto data_err;
947 				(void) putc('\r', outstr);
948 			}
949 			(void) putc(c, outstr);
950 		}
951 		fflush(outstr);
952 		transflag = 0;
953 		if (ferror(instr))
954 			goto file_err;
955 		if (ferror(outstr))
956 			goto data_err;
957 		reply(226, "Transfer complete.");
958 		return;
959 
960 	case TYPE_I:
961 	case TYPE_L:
962 		if ((buf = malloc((u_int)blksize)) == NULL) {
963 			transflag = 0;
964 			perror_reply(451, "Local resource failure: malloc");
965 			return;
966 		}
967 		netfd = fileno(outstr);
968 		filefd = fileno(instr);
969 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
970 		    write(netfd, buf, cnt) == cnt)
971 			byte_count += cnt;
972 		transflag = 0;
973 		(void)free(buf);
974 		if (cnt != 0) {
975 			if (cnt < 0)
976 				goto file_err;
977 			goto data_err;
978 		}
979 		reply(226, "Transfer complete.");
980 		return;
981 	default:
982 		transflag = 0;
983 		reply(550, "Unimplemented TYPE %d in send_data", type);
984 		return;
985 	}
986 
987 data_err:
988 	transflag = 0;
989 	perror_reply(426, "Data connection");
990 	return;
991 
992 file_err:
993 	transflag = 0;
994 	perror_reply(551, "Error on input file");
995 }
996 
997 /*
998  * Transfer data from peer to "outstr" using the appropriate encapulation of
999  * the data subject to Mode, Structure, and Type.
1000  *
1001  * N.B.: Form isn't handled.
1002  */
1003 static int
1004 receive_data(instr, outstr)
1005 	FILE *instr, *outstr;
1006 {
1007 	int c;
1008 	int cnt, bare_lfs = 0;
1009 	char buf[BUFSIZ];
1010 
1011 	transflag++;
1012 	if (setjmp(urgcatch)) {
1013 		transflag = 0;
1014 		return (-1);
1015 	}
1016 	switch (type) {
1017 
1018 	case TYPE_I:
1019 	case TYPE_L:
1020 		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1021 			if (write(fileno(outstr), buf, cnt) != cnt)
1022 				goto file_err;
1023 			byte_count += cnt;
1024 		}
1025 		if (cnt < 0)
1026 			goto data_err;
1027 		transflag = 0;
1028 		return (0);
1029 
1030 	case TYPE_E:
1031 		reply(553, "TYPE E not implemented.");
1032 		transflag = 0;
1033 		return (-1);
1034 
1035 	case TYPE_A:
1036 		while ((c = getc(instr)) != EOF) {
1037 			byte_count++;
1038 			if (c == '\n')
1039 				bare_lfs++;
1040 			while (c == '\r') {
1041 				if (ferror(outstr))
1042 					goto data_err;
1043 				if ((c = getc(instr)) != '\n') {
1044 					(void) putc ('\r', outstr);
1045 					if (c == '\0' || c == EOF)
1046 						goto contin2;
1047 				}
1048 			}
1049 			(void) putc(c, outstr);
1050 	contin2:	;
1051 		}
1052 		fflush(outstr);
1053 		if (ferror(instr))
1054 			goto data_err;
1055 		if (ferror(outstr))
1056 			goto file_err;
1057 		transflag = 0;
1058 		if (bare_lfs) {
1059 			lreply(226,
1060 		"WARNING! %d bare linefeeds received in ASCII mode",
1061 			    bare_lfs);
1062 		(void)printf("   File may not have transferred correctly.\r\n");
1063 		}
1064 		return (0);
1065 	default:
1066 		reply(550, "Unimplemented TYPE %d in receive_data", type);
1067 		transflag = 0;
1068 		return (-1);
1069 	}
1070 
1071 data_err:
1072 	transflag = 0;
1073 	perror_reply(426, "Data Connection");
1074 	return (-1);
1075 
1076 file_err:
1077 	transflag = 0;
1078 	perror_reply(452, "Error writing file");
1079 	return (-1);
1080 }
1081 
1082 void
1083 statfilecmd(filename)
1084 	char *filename;
1085 {
1086 	FILE *fin;
1087 	int c;
1088 	char line[LINE_MAX];
1089 
1090 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1091 	fin = ftpd_popen(line, "r");
1092 	lreply(211, "status of %s:", filename);
1093 	while ((c = getc(fin)) != EOF) {
1094 		if (c == '\n') {
1095 			if (ferror(stdout)){
1096 				perror_reply(421, "control connection");
1097 				(void) ftpd_pclose(fin);
1098 				dologout(1);
1099 				/* NOTREACHED */
1100 			}
1101 			if (ferror(fin)) {
1102 				perror_reply(551, filename);
1103 				(void) ftpd_pclose(fin);
1104 				return;
1105 			}
1106 			(void) putc('\r', stdout);
1107 		}
1108 		(void) putc(c, stdout);
1109 	}
1110 	(void) ftpd_pclose(fin);
1111 	reply(211, "End of Status");
1112 }
1113 
1114 void
1115 statcmd()
1116 {
1117 	struct sockaddr_in *sin;
1118 	u_char *a, *p;
1119 
1120 	lreply(211, "%s FTP server status:", hostname, version);
1121 	printf("     %s\r\n", version);
1122 	printf("     Connected to %s", remotehost);
1123 	if (!isdigit(remotehost[0]))
1124 		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1125 	printf("\r\n");
1126 	if (logged_in) {
1127 		if (guest)
1128 			printf("     Logged in anonymously\r\n");
1129 		else
1130 			printf("     Logged in as %s\r\n", pw->pw_name);
1131 	} else if (askpasswd)
1132 		printf("     Waiting for password\r\n");
1133 	else
1134 		printf("     Waiting for user name\r\n");
1135 	printf("     TYPE: %s", typenames[type]);
1136 	if (type == TYPE_A || type == TYPE_E)
1137 		printf(", FORM: %s", formnames[form]);
1138 	if (type == TYPE_L)
1139 #if NBBY == 8
1140 		printf(" %d", NBBY);
1141 #else
1142 		printf(" %d", bytesize);	/* need definition! */
1143 #endif
1144 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1145 	    strunames[stru], modenames[mode]);
1146 	if (data != -1)
1147 		printf("     Data connection open\r\n");
1148 	else if (pdata != -1) {
1149 		printf("     in Passive mode");
1150 		sin = &pasv_addr;
1151 		goto printaddr;
1152 	} else if (usedefault == 0) {
1153 		printf("     PORT");
1154 		sin = &data_dest;
1155 printaddr:
1156 		a = (u_char *) &sin->sin_addr;
1157 		p = (u_char *) &sin->sin_port;
1158 #define UC(b) (((int) b) & 0xff)
1159 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1160 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1161 #undef UC
1162 	} else
1163 		printf("     No data connection\r\n");
1164 	reply(211, "End of status");
1165 }
1166 
1167 void
1168 fatal(s)
1169 	char *s;
1170 {
1171 
1172 	reply(451, "Error in server: %s\n", s);
1173 	reply(221, "Closing connection due to server error.");
1174 	dologout(0);
1175 	/* NOTREACHED */
1176 }
1177 
1178 void
1179 #if __STDC__
1180 reply(int n, const char *fmt, ...)
1181 #else
1182 reply(n, fmt, va_alist)
1183 	int n;
1184 	char *fmt;
1185         va_dcl
1186 #endif
1187 {
1188 	va_list ap;
1189 #if __STDC__
1190 	va_start(ap, fmt);
1191 #else
1192 	va_start(ap);
1193 #endif
1194 	(void)printf("%d ", n);
1195 	(void)vprintf(fmt, ap);
1196 	(void)printf("\r\n");
1197 	(void)fflush(stdout);
1198 	if (debug) {
1199 		syslog(LOG_DEBUG, "<--- %d ", n);
1200 		vsyslog(LOG_DEBUG, fmt, ap);
1201 	}
1202 }
1203 
1204 void
1205 #if __STDC__
1206 lreply(int n, const char *fmt, ...)
1207 #else
1208 lreply(n, fmt, va_alist)
1209 	int n;
1210 	char *fmt;
1211         va_dcl
1212 #endif
1213 {
1214 	va_list ap;
1215 #if __STDC__
1216 	va_start(ap, fmt);
1217 #else
1218 	va_start(ap);
1219 #endif
1220 	(void)printf("%d- ", n);
1221 	(void)vprintf(fmt, ap);
1222 	(void)printf("\r\n");
1223 	(void)fflush(stdout);
1224 	if (debug) {
1225 		syslog(LOG_DEBUG, "<--- %d- ", n);
1226 		vsyslog(LOG_DEBUG, fmt, ap);
1227 	}
1228 }
1229 
1230 static void
1231 ack(s)
1232 	char *s;
1233 {
1234 
1235 	reply(250, "%s command successful.", s);
1236 }
1237 
1238 void
1239 nack(s)
1240 	char *s;
1241 {
1242 
1243 	reply(502, "%s command not implemented.", s);
1244 }
1245 
1246 /* ARGSUSED */
1247 void
1248 yyerror(s)
1249 	char *s;
1250 {
1251 	char *cp;
1252 
1253 	if (cp = strchr(cbuf,'\n'))
1254 		*cp = '\0';
1255 	reply(500, "'%s': command not understood.", cbuf);
1256 }
1257 
1258 void
1259 delete(name)
1260 	char *name;
1261 {
1262 	struct stat st;
1263 
1264 	LOGCMD("delete", name);
1265 	if (stat(name, &st) < 0) {
1266 		perror_reply(550, name);
1267 		return;
1268 	}
1269 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1270 		if (rmdir(name) < 0) {
1271 			perror_reply(550, name);
1272 			return;
1273 		}
1274 		goto done;
1275 	}
1276 	if (unlink(name) < 0) {
1277 		perror_reply(550, name);
1278 		return;
1279 	}
1280 done:
1281 	ack("DELE");
1282 }
1283 
1284 void
1285 cwd(path)
1286 	char *path;
1287 {
1288 
1289 	if (chdir(path) < 0)
1290 		perror_reply(550, path);
1291 	else
1292 		ack("CWD");
1293 }
1294 
1295 void
1296 makedir(name)
1297 	char *name;
1298 {
1299 
1300 	LOGCMD("mkdir", name);
1301 	if (mkdir(name, 0777) < 0)
1302 		perror_reply(550, name);
1303 	else
1304 		reply(257, "MKD command successful.");
1305 }
1306 
1307 void
1308 removedir(name)
1309 	char *name;
1310 {
1311 
1312 	LOGCMD("rmdir", name);
1313 	if (rmdir(name) < 0)
1314 		perror_reply(550, name);
1315 	else
1316 		ack("RMD");
1317 }
1318 
1319 void
1320 pwd()
1321 {
1322 	char path[MAXPATHLEN + 1];
1323 
1324 	if (getwd(path) == (char *)NULL)
1325 		reply(550, "%s.", path);
1326 	else
1327 		reply(257, "\"%s\" is current directory.", path);
1328 }
1329 
1330 char *
1331 renamefrom(name)
1332 	char *name;
1333 {
1334 	struct stat st;
1335 
1336 	if (stat(name, &st) < 0) {
1337 		perror_reply(550, name);
1338 		return ((char *)0);
1339 	}
1340 	reply(350, "File exists, ready for destination name");
1341 	return (name);
1342 }
1343 
1344 void
1345 renamecmd(from, to)
1346 	char *from, *to;
1347 {
1348 
1349 	LOGCMD2("rename", from, to);
1350 	if (rename(from, to) < 0)
1351 		perror_reply(550, "rename");
1352 	else
1353 		ack("RNTO");
1354 }
1355 
1356 static void
1357 dolog(sin)
1358 	struct sockaddr_in *sin;
1359 {
1360 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1361 		sizeof(struct in_addr), AF_INET);
1362 
1363 	if (hp)
1364 		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
1365 	else
1366 		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1367 		    sizeof(remotehost));
1368 #ifdef HASSETPROCTITLE
1369 	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1370 	setproctitle(proctitle);
1371 #endif /* HASSETPROCTITLE */
1372 
1373 	if (logging)
1374 		syslog(LOG_INFO, "connection from %s", remotehost);
1375 }
1376 
1377 /*
1378  * Record logout in wtmp file
1379  * and exit with supplied status.
1380  */
1381 void
1382 dologout(status)
1383 	int status;
1384 {
1385 
1386 	if (logged_in) {
1387 		(void) seteuid((uid_t)0);
1388 		logwtmp(ttyline, "", "");
1389 #if defined(KERBEROS)
1390 		if (!notickets && krbtkfile_env)
1391 			unlink(krbtkfile_env);
1392 #endif
1393 	}
1394 	/* beware of flushing buffers after a SIGPIPE */
1395 	_exit(status);
1396 }
1397 
1398 static void
1399 myoob(signo)
1400 	int signo;
1401 {
1402 	char *cp;
1403 
1404 	/* only process if transfer occurring */
1405 	if (!transflag)
1406 		return;
1407 	cp = tmpline;
1408 	if (getline(cp, 7, stdin) == NULL) {
1409 		reply(221, "You could at least say goodbye.");
1410 		dologout(0);
1411 	}
1412 	upper(cp);
1413 	if (strcmp(cp, "ABOR\r\n") == 0) {
1414 		tmpline[0] = '\0';
1415 		reply(426, "Transfer aborted. Data connection closed.");
1416 		reply(226, "Abort successful");
1417 		longjmp(urgcatch, 1);
1418 	}
1419 	if (strcmp(cp, "STAT\r\n") == 0) {
1420 		if (file_size != (off_t) -1)
1421 			reply(213, "Status: %qd of %qd bytes transferred",
1422 			    byte_count, file_size);
1423 		else
1424 			reply(213, "Status: %qd bytes transferred", byte_count);
1425 	}
1426 }
1427 
1428 /*
1429  * Note: a response of 425 is not mentioned as a possible response to
1430  *	the PASV command in RFC959. However, it has been blessed as
1431  *	a legitimate response by Jon Postel in a telephone conversation
1432  *	with Rick Adams on 25 Jan 89.
1433  */
1434 void
1435 passive()
1436 {
1437 	int len;
1438 	char *p, *a;
1439 
1440 	pdata = socket(AF_INET, SOCK_STREAM, 0);
1441 	if (pdata < 0) {
1442 		perror_reply(425, "Can't open passive connection");
1443 		return;
1444 	}
1445 	pasv_addr = ctrl_addr;
1446 	pasv_addr.sin_port = 0;
1447 	(void) seteuid((uid_t)0);
1448 	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1449 		(void) seteuid((uid_t)pw->pw_uid);
1450 		goto pasv_error;
1451 	}
1452 	(void) seteuid((uid_t)pw->pw_uid);
1453 	len = sizeof(pasv_addr);
1454 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1455 		goto pasv_error;
1456 	if (listen(pdata, 1) < 0)
1457 		goto pasv_error;
1458 	a = (char *) &pasv_addr.sin_addr;
1459 	p = (char *) &pasv_addr.sin_port;
1460 
1461 #define UC(b) (((int) b) & 0xff)
1462 
1463 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1464 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1465 	return;
1466 
1467 pasv_error:
1468 	(void) close(pdata);
1469 	pdata = -1;
1470 	perror_reply(425, "Can't open passive connection");
1471 	return;
1472 }
1473 
1474 /*
1475  * Generate unique name for file with basename "local".
1476  * The file named "local" is already known to exist.
1477  * Generates failure reply on error.
1478  */
1479 static char *
1480 gunique(local)
1481 	char *local;
1482 {
1483 	static char new[MAXPATHLEN];
1484 	struct stat st;
1485 	int count;
1486 	char *cp;
1487 
1488 	cp = strrchr(local, '/');
1489 	if (cp)
1490 		*cp = '\0';
1491 	if (stat(cp ? local : ".", &st) < 0) {
1492 		perror_reply(553, cp ? local : ".");
1493 		return ((char *) 0);
1494 	}
1495 	if (cp)
1496 		*cp = '/';
1497 	(void) strcpy(new, local);
1498 	cp = new + strlen(new);
1499 	*cp++ = '.';
1500 	for (count = 1; count < 100; count++) {
1501 		(void)sprintf(cp, "%d", count);
1502 		if (stat(new, &st) < 0)
1503 			return (new);
1504 	}
1505 	reply(452, "Unique file name cannot be created.");
1506 	return (NULL);
1507 }
1508 
1509 /*
1510  * Format and send reply containing system error number.
1511  */
1512 void
1513 perror_reply(code, string)
1514 	int code;
1515 	char *string;
1516 {
1517 
1518 	reply(code, "%s: %s.", string, strerror(errno));
1519 }
1520 
1521 static char *onefile[] = {
1522 	"",
1523 	0
1524 };
1525 
1526 void
1527 send_file_list(whichf)
1528 	char *whichf;
1529 {
1530 	struct stat st;
1531 	DIR *dirp = NULL;
1532 	struct dirent *dir;
1533 	FILE *dout = NULL;
1534 	char **dirlist, *dirname;
1535 	int simple = 0;
1536 	int freeglob = 0;
1537 	glob_t gl;
1538 
1539 	if (strpbrk(whichf, "~{[*?") != NULL) {
1540 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1541 
1542 		memset(&gl, 0, sizeof(gl));
1543 		freeglob = 1;
1544 		if (glob(whichf, flags, 0, &gl)) {
1545 			reply(550, "not found");
1546 			goto out;
1547 		} else if (gl.gl_pathc == 0) {
1548 			errno = ENOENT;
1549 			perror_reply(550, whichf);
1550 			goto out;
1551 		}
1552 		dirlist = gl.gl_pathv;
1553 	} else {
1554 		onefile[0] = whichf;
1555 		dirlist = onefile;
1556 		simple = 1;
1557 	}
1558 
1559 	if (setjmp(urgcatch)) {
1560 		transflag = 0;
1561 		goto out;
1562 	}
1563 	while (dirname = *dirlist++) {
1564 		if (stat(dirname, &st) < 0) {
1565 			/*
1566 			 * If user typed "ls -l", etc, and the client
1567 			 * used NLST, do what the user meant.
1568 			 */
1569 			if (dirname[0] == '-' && *dirlist == NULL &&
1570 			    transflag == 0) {
1571 				retrieve("/bin/ls %s", dirname);
1572 				goto out;
1573 			}
1574 			perror_reply(550, whichf);
1575 			if (dout != NULL) {
1576 				(void) fclose(dout);
1577 				transflag = 0;
1578 				data = -1;
1579 				pdata = -1;
1580 			}
1581 			goto out;
1582 		}
1583 
1584 		if (S_ISREG(st.st_mode)) {
1585 			if (dout == NULL) {
1586 				dout = dataconn("file list", (off_t)-1, "w");
1587 				if (dout == NULL)
1588 					goto out;
1589 				transflag++;
1590 			}
1591 			fprintf(dout, "%s%s\n", dirname,
1592 				type == TYPE_A ? "\r" : "");
1593 			byte_count += strlen(dirname) + 1;
1594 			continue;
1595 		} else if (!S_ISDIR(st.st_mode))
1596 			continue;
1597 
1598 		if ((dirp = opendir(dirname)) == NULL)
1599 			continue;
1600 
1601 		while ((dir = readdir(dirp)) != NULL) {
1602 			char nbuf[MAXPATHLEN];
1603 
1604 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1605 				continue;
1606 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1607 			    dir->d_namlen == 2)
1608 				continue;
1609 
1610 			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
1611 
1612 			/*
1613 			 * We have to do a stat to insure it's
1614 			 * not a directory or special file.
1615 			 */
1616 			if (simple || (stat(nbuf, &st) == 0 &&
1617 			    S_ISREG(st.st_mode))) {
1618 				if (dout == NULL) {
1619 					dout = dataconn("file list", (off_t)-1,
1620 						"w");
1621 					if (dout == NULL)
1622 						goto out;
1623 					transflag++;
1624 				}
1625 				if (nbuf[0] == '.' && nbuf[1] == '/')
1626 					fprintf(dout, "%s%s\n", &nbuf[2],
1627 						type == TYPE_A ? "\r" : "");
1628 				else
1629 					fprintf(dout, "%s%s\n", nbuf,
1630 						type == TYPE_A ? "\r" : "");
1631 				byte_count += strlen(nbuf) + 1;
1632 			}
1633 		}
1634 		(void) closedir(dirp);
1635 	}
1636 
1637 	if (dout == NULL)
1638 		reply(550, "No files found.");
1639 	else if (ferror(dout) != 0)
1640 		perror_reply(550, "Data connection");
1641 	else
1642 		reply(226, "Transfer complete.");
1643 
1644 	transflag = 0;
1645 	if (dout != NULL)
1646 		(void) fclose(dout);
1647 	data = -1;
1648 	pdata = -1;
1649 out:
1650 	if (freeglob) {
1651 		freeglob = 0;
1652 		globfree(&gl);
1653 	}
1654 }
1655