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