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