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